a71101304ac9b5c72440f8514e2b49efb79dff58
[jscl.git] / ecmalisp.lisp
1 ;;; ecmalisp.lisp ---
2
3 ;; Copyright (C) 2012, 2013 David Vazquez
4 ;; Copyright (C) 2012 Raimon Grau
5
6 ;; This program 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 ;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
18
19 ;;; This code is executed when ecmalisp compiles this file
20 ;;; itself. The compiler provides compilation of some special forms,
21 ;;; as well as funcalls and macroexpansion, but no functions. So, we
22 ;;; define the Lisp world from scratch. This code has to define enough
23 ;;; language to the compiler to be able to run.
24
25 #+ecmalisp
26 (progn
27   (eval-when-compile
28     (%compile-defmacro 'defmacro
29                        '(function
30                          (lambda (name args &rest body)
31                           `(eval-when-compile
32                              (%compile-defmacro ',name
33                                                 '(function
34                                                   (lambda ,(mapcar #'(lambda (x)
35                                                                        (if (eq x '&body)
36                                                                            '&rest
37                                                                            x))
38                                                                    args)
39                                                    ,@body))))))))
40
41   (defmacro declaim (&rest decls)
42     `(eval-when-compile
43        ,@(mapcar (lambda (decl) `(!proclaim ',decl)) decls)))
44
45   (defmacro defconstant (name value &optional docstring)
46     `(progn
47        (declaim (special ,name))
48        (declaim (constant ,name))
49        (setq ,name ,value)
50        ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring)))
51        ',name))
52
53   (defconstant t 't)
54   (defconstant nil 'nil)
55   (js-vset "nil" nil)
56
57   (defmacro lambda (args &body body)
58     `(function (lambda ,args ,@body)))
59
60   (defmacro when (condition &body body)
61     `(if ,condition (progn ,@body) nil))
62
63   (defmacro unless (condition &body body)
64     `(if ,condition nil (progn ,@body)))
65
66   (defmacro defvar (name value &optional docstring)
67     `(progn
68        (declaim (special ,name))
69        (unless (boundp ',name) (setq ,name ,value))
70        ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring)))
71        ',name))
72
73   (defmacro defparameter (name value &optional docstring)
74     `(progn
75        (setq ,name ,value)
76        ,@(when (stringp docstring) `((oset ',name "vardoc" ,docstring)))
77        ',name))
78
79   (defmacro named-lambda (name args &rest body)
80     (let ((x (gensym "FN")))
81       `(let ((,x (lambda ,args ,@body)))
82          (oset ,x "fname" ,name)
83          ,x)))
84
85   (defmacro defun (name args &rest body)
86     `(progn
87        (fset ',name
88              (named-lambda ,(symbol-name name) ,args
89                ,@(if (and (stringp (car body)) (not (null (cdr body))))
90                      `(,(car body) (block ,name ,@(cdr body)))
91                      `((block ,name ,@body)))))
92        ',name))
93
94   (defun null (x)
95     (eq x nil))
96
97   (defmacro return (&optional value)
98     `(return-from nil ,value))
99
100   (defmacro while (condition &body body)
101     `(block nil (%while ,condition ,@body)))
102
103   (defvar *gensym-counter* 0)
104   (defun gensym (&optional (prefix "G"))
105     (setq *gensym-counter* (+ *gensym-counter* 1))
106     (make-symbol (concat-two prefix (integer-to-string *gensym-counter*))))
107
108   (defun boundp (x)
109     (boundp x))
110
111   ;; Basic functions
112   (defun = (x y) (= x y))
113   (defun * (x y) (* x y))
114   (defun / (x y) (/ x y))
115   (defun 1+ (x) (+ x 1))
116   (defun 1- (x) (- x 1))
117   (defun zerop (x) (= x 0))
118   (defun truncate (x y) (floor (/ x y)))
119
120   (defun eql (x y) (eq x y))
121
122   (defun not (x) (if x nil t))
123
124   (defun cons (x y ) (cons x y))
125   (defun consp (x) (consp x))
126
127   (defun car (x)
128     "Return the CAR part of a cons, or NIL if X is null."
129     (car x))
130
131   (defun cdr (x) (cdr x))
132   (defun caar (x) (car (car x)))
133   (defun cadr (x) (car (cdr x)))
134   (defun cdar (x) (cdr (car x)))
135   (defun cddr (x) (cdr (cdr x)))
136   (defun caddr (x) (car (cdr (cdr x))))
137   (defun cdddr (x) (cdr (cdr (cdr x))))
138   (defun cadddr (x) (car (cdr (cdr (cdr x)))))
139   (defun first (x) (car x))
140   (defun second (x) (cadr x))
141   (defun third (x) (caddr x))
142   (defun fourth (x) (cadddr x))
143   (defun rest (x) (cdr x))
144
145   (defun list (&rest args) args)
146   (defun atom (x)
147     (not (consp x)))
148
149   ;; Basic macros
150
151   (defmacro incf (x &optional (delta 1))
152     `(setq ,x (+ ,x ,delta)))
153
154   (defmacro decf (x &optional (delta 1))
155     `(setq ,x (- ,x ,delta)))
156
157   (defmacro push (x place)
158     `(setq ,place (cons ,x ,place)))
159
160   (defmacro dolist (iter &body body)
161     (let ((var (first iter))
162           (g!list (gensym)))
163       `(block nil
164          (let ((,g!list ,(second iter))
165                (,var nil))
166            (%while ,g!list
167                    (setq ,var (car ,g!list))
168                    (tagbody ,@body)
169                    (setq ,g!list (cdr ,g!list)))
170            ,(third iter)))))
171
172   (defmacro dotimes (iter &body body)
173     (let ((g!to (gensym))
174           (var (first iter))
175           (to (second iter))
176           (result (third iter)))
177       `(block nil
178          (let ((,var 0)
179                (,g!to ,to))
180            (%while (< ,var ,g!to)
181                    (tagbody ,@body)
182                    (incf ,var))
183            ,result))))
184
185   (defmacro cond (&rest clausules)
186     (if (null clausules)
187         nil
188         (if (eq (caar clausules) t)
189             `(progn ,@(cdar clausules))
190             `(if ,(caar clausules)
191                  (progn ,@(cdar clausules))
192                  (cond ,@(cdr clausules))))))
193
194   (defmacro case (form &rest clausules)
195     (let ((!form (gensym)))
196       `(let ((,!form ,form))
197          (cond
198            ,@(mapcar (lambda (clausule)
199                        (if (eq (car clausule) t)
200                            clausule
201                            `((eql ,!form ',(car clausule))
202                              ,@(cdr clausule))))
203                      clausules)))))
204
205   (defmacro ecase (form &rest clausules)
206     `(case ,form
207        ,@(append
208           clausules
209           `((t
210              (error "ECASE expression failed."))))))
211
212   (defmacro and (&rest forms)
213     (cond
214       ((null forms)
215        t)
216       ((null (cdr forms))
217        (car forms))
218       (t
219        `(if ,(car forms)
220             (and ,@(cdr forms))
221             nil))))
222
223   (defmacro or (&rest forms)
224     (cond
225       ((null forms)
226        nil)
227       ((null (cdr forms))
228        (car forms))
229       (t
230        (let ((g (gensym)))
231          `(let ((,g ,(car forms)))
232             (if ,g ,g (or ,@(cdr forms))))))))
233
234   (defmacro prog1 (form &body body)
235     (let ((value (gensym)))
236       `(let ((,value ,form))
237          ,@body
238          ,value)))
239
240   (defmacro prog2 (form1 result &body body)
241     `(prog1 (progn ,form1 ,result) ,@body)))
242
243
244 ;;; This couple of helper functions will be defined in both Common
245 ;;; Lisp and in Ecmalisp.
246 (defun ensure-list (x)
247   (if (listp x)
248       x
249       (list x)))
250
251 (defun !reduce (func list &key initial-value)
252   (if (null list)
253       initial-value
254       (!reduce func
255                (cdr list)
256                :initial-value (funcall func initial-value (car list)))))
257
258 ;;; Go on growing the Lisp language in Ecmalisp, with more high
259 ;;; level utilities as well as correct versions of other
260 ;;; constructions.
261 #+ecmalisp
262 (progn
263   (defun + (&rest args)
264     (let ((r 0))
265       (dolist (x args r)
266         (incf r x))))
267
268   (defun - (x &rest others)
269     (if (null others)
270         (- x)
271         (let ((r x))
272           (dolist (y others r)
273             (decf r y)))))
274
275   (defun append-two (list1 list2)
276     (if (null list1)
277         list2
278         (cons (car list1)
279               (append (cdr list1) list2))))
280
281   (defun append (&rest lists)
282     (!reduce #'append-two lists))
283
284   (defun revappend (list1 list2)
285     (while list1
286       (push (car list1) list2)
287       (setq list1 (cdr list1)))
288     list2)
289
290   (defun reverse (list)
291     (revappend list '()))
292
293   (defmacro psetq (&rest pairs)
294     (let ( ;; For each pair, we store here a list of the form
295           ;; (VARIABLE GENSYM VALUE).
296           (assignments '()))
297       (while t
298         (cond
299           ((null pairs) (return))
300           ((null (cdr pairs))
301            (error "Odd paris in PSETQ"))
302           (t
303            (let ((variable (car pairs))
304                  (value (cadr pairs)))
305              (push `(,variable ,(gensym) ,value)  assignments)
306              (setq pairs (cddr pairs))))))
307       (setq assignments (reverse assignments))
308       ;;
309       `(let ,(mapcar #'cdr assignments)
310          (setq ,@(!reduce #'append (mapcar #'butlast assignments))))))
311
312   (defmacro do (varlist endlist &body body)
313     `(block nil
314        (let ,(mapcar (lambda (x) (list (first x) (second x))) varlist)
315          (while t
316            (when ,(car endlist)
317              (return (progn ,(cdr endlist))))
318            (tagbody ,@body)
319            (psetq
320             ,@(apply #'append
321                      (mapcar (lambda (v)
322                                (and (consp (cddr v))
323                                     (list (first v) (third v))))
324                              varlist)))))))
325
326   (defmacro do* (varlist endlist &body body)
327     `(block nil
328        (let* ,(mapcar (lambda (x) (list (first x) (second x))) varlist)
329          (while t
330            (when ,(car endlist)
331              (return (progn ,(cdr endlist))))
332            (tagbody ,@body)
333            (setq
334             ,@(apply #'append
335                      (mapcar (lambda (v)
336                                (and (consp (cddr v))
337                                     (list (first v) (third v))))
338                              varlist)))))))
339
340   (defun list-length (list)
341     (let ((l 0))
342       (while (not (null list))
343         (incf l)
344         (setq list (cdr list)))
345       l))
346
347   (defun length (seq)
348     (cond
349       ((stringp seq)
350        (string-length seq))
351       ((arrayp seq)
352        (oget seq "length"))
353       ((listp seq)
354        (list-length seq))))
355
356   (defun concat-two (s1 s2)
357     (concat-two s1 s2))
358
359   (defmacro with-collect (&body body)
360     (let ((head (gensym))
361           (tail (gensym)))
362       `(let* ((,head (cons 'sentinel nil))
363               (,tail ,head))
364          (flet ((collect (x)
365                   (rplacd ,tail (cons x nil))
366                   (setq ,tail (cdr ,tail))
367                   x))
368            ,@body)
369          (cdr ,head))))
370
371   (defun map1 (func list)
372     (with-collect
373         (while list
374           (collect (funcall func (car list)))
375           (setq list (cdr list)))))
376
377   (defmacro loop (&body body)
378     `(while t ,@body))
379
380   (defun mapcar (func list &rest lists)
381     (let ((lists (cons list lists)))
382       (with-collect
383           (block loop
384             (loop
385                (let ((elems (map1 #'car lists)))
386                  (do ((tail lists (cdr tail)))
387                      ((null tail))
388                    (when (null (car tail)) (return-from loop))
389                    (rplaca tail (cdar tail)))
390                  (collect (apply func elems))))))))
391
392   (defun identity (x) x)
393
394   (defun constantly (x)
395     (lambda (&rest args)
396       x))
397
398   (defun copy-list (x)
399     (mapcar #'identity x))
400
401   (defun code-char (x) x)
402   (defun char-code (x) x)
403   (defun char= (x y) (= x y))
404
405   (defun integerp (x)
406     (and (numberp x) (= (floor x) x)))
407
408   (defun plusp (x) (< 0 x))
409   (defun minusp (x) (< x 0))
410
411   (defun listp (x)
412     (or (consp x) (null x)))
413
414   (defun nthcdr (n list)
415     (while (and (plusp n) list)
416       (setq n (1- n))
417       (setq list (cdr list)))
418     list)
419
420   (defun nth (n list)
421     (car (nthcdr n list)))
422
423   (defun last (x)
424     (while (consp (cdr x))
425       (setq x (cdr x)))
426     x)
427
428   (defun butlast (x)
429     (and (consp (cdr x))
430          (cons (car x) (butlast (cdr x)))))
431
432   (defun member (x list)
433     (while list
434       (when (eql x (car list))
435         (return list))
436       (setq list (cdr list))))
437
438   (defun remove (x list)
439     (cond
440       ((null list)
441        nil)
442       ((eql x (car list))
443        (remove x (cdr list)))
444       (t
445        (cons (car list) (remove x (cdr list))))))
446
447   (defun remove-if (func list)
448     (cond
449       ((null list)
450        nil)
451       ((funcall func (car list))
452        (remove-if func (cdr list)))
453       (t
454        (cons (car list) (remove-if func (cdr list))))))
455
456   (defun remove-if-not (func list)
457     (cond
458       ((null list)
459        nil)
460       ((funcall func (car list))
461        (cons (car list) (remove-if-not func (cdr list))))
462       (t
463        (remove-if-not func (cdr list)))))
464
465   (defun digit-char-p (x)
466     (if (and (<= #\0 x) (<= x #\9))
467         (- x #\0)
468         nil))
469
470   (defun digit-char (weight)
471     (and (<= 0 weight 9)
472          (char "0123456789" weight)))
473
474   (defun subseq (seq a &optional b)
475     (cond
476       ((stringp seq)
477        (if b
478            (slice seq a b)
479            (slice seq a)))
480       (t
481        (error "Unsupported argument."))))
482
483   (defun some (function seq)
484     (cond
485       ((stringp seq)
486        (let ((index 0)
487              (size (length seq)))
488          (while (< index size)
489            (when (funcall function (char seq index))
490              (return-from some t))
491            (incf index))
492          nil))
493       ((listp seq)
494        (dolist (x seq nil)
495          (when (funcall function x)
496            (return t))))
497       (t
498        (error "Unknown sequence."))))
499
500   (defun every (function seq)
501     (cond
502       ((stringp seq)
503        (let ((index 0)
504              (size (length seq)))
505          (while (< index size)
506            (unless (funcall function (char seq index))
507              (return-from every nil))
508            (incf index))
509          t))
510       ((listp seq)
511        (dolist (x seq t)
512          (unless (funcall function x)
513            (return))))
514       (t
515        (error "Unknown sequence."))))
516
517   (defun assoc (x alist)
518     (while alist
519       (if (eql x (caar alist))
520           (return)
521           (setq alist (cdr alist))))
522     (car alist))
523
524   (defun string (x)
525     (cond ((stringp x) x)
526           ((symbolp x) (symbol-name x))
527           (t (char-to-string x))))
528
529   (defun string= (s1 s2)
530     (equal s1 s2))
531
532   (defun fdefinition (x)
533     (cond
534       ((functionp x)
535        x)
536       ((symbolp x)
537        (symbol-function x))
538       (t
539        (error "Invalid function"))))
540
541   (defun disassemble (function)
542     (write-line (lambda-code (fdefinition function)))
543     nil)
544
545   (defun documentation (x type)
546     "Return the documentation of X. TYPE must be the symbol VARIABLE or FUNCTION."
547     (ecase type
548       (function
549        (let ((func (fdefinition x)))
550          (oget func "docstring")))
551       (variable
552        (unless (symbolp x)
553          (error "Wrong argument type! it should be a symbol"))
554        (oget x "vardoc"))))
555
556   (defmacro multiple-value-bind (variables value-from &body body)
557     `(multiple-value-call (lambda (&optional ,@variables &rest ,(gensym))
558                             ,@body)
559        ,value-from))
560
561   (defmacro multiple-value-list (value-from)
562     `(multiple-value-call #'list ,value-from))
563
564
565 ;;; Generalized references (SETF)
566
567   (defvar *setf-expanders* nil)
568
569   (defun get-setf-expansion (place)
570     (if (symbolp place)
571         (let ((value (gensym)))
572           (values nil
573                   nil
574                   `(,value)
575                   `(setq ,place ,value)
576                   place))
577         (let ((place (ls-macroexpand-1 place)))
578           (let* ((access-fn (car place))
579                  (expander (cdr (assoc access-fn *setf-expanders*))))
580             (when (null expander)
581               (error "Unknown generalized reference."))
582             (apply expander (cdr place))))))
583
584   (defmacro define-setf-expander (access-fn lambda-list &body body)
585     (unless (symbolp access-fn)
586       (error "ACCESS-FN must be a symbol."))
587     `(progn (push (cons ',access-fn (lambda ,lambda-list ,@body))
588                   *setf-expanders*)
589             ',access-fn))
590
591   (defmacro setf (&rest pairs)
592     (cond
593       ((null pairs)
594        nil)
595       ((null (cdr pairs))
596        (error "Odd number of arguments to setf."))
597       ((null (cddr pairs))
598        (let ((place (first pairs))
599              (value (second pairs)))
600          (multiple-value-bind (vars vals store-vars writer-form reader-form)
601              (get-setf-expansion place)
602            ;; TODO: Optimize the expansion a little bit to avoid let*
603            ;; or multiple-value-bind when unnecesary.
604            `(let* ,(mapcar #'list vars vals)
605               (multiple-value-bind ,store-vars
606                   ,value
607                 ,writer-form)))))
608       (t
609        `(progn
610           ,@(do ((pairs pairs (cddr pairs))
611                  (result '() (cons `(setf ,(car pairs) ,(cadr pairs)) result)))
612                 ((null pairs)
613                  (reverse result)))))))
614
615   (define-setf-expander car (x)
616     (let ((cons (gensym))
617           (new-value (gensym)))
618       (values (list cons)
619               (list x)
620               (list new-value)
621               `(progn (rplaca ,cons ,new-value) ,new-value)
622               `(car ,cons))))
623
624   (define-setf-expander cdr (x)
625     (let ((cons (gensym))
626           (new-value (gensym)))
627       (values (list cons)
628               (list x)
629               (list new-value)
630               `(progn (rplacd ,cons ,new-value) ,new-value)
631               `(car ,cons))))
632
633   (defmacro push (x place)
634     (multiple-value-bind (dummies vals newval setter getter)
635         (get-setf-expansion place)
636       (let ((g (gensym)))
637         `(let* ((,g ,x)
638                 ,@(mapcar #'list dummies vals)
639                 (,(car newval) (cons ,g ,getter))
640                 ,@(cdr newval))
641            ,setter))))
642
643   ;; Packages
644
645   (defvar *package-list* nil)
646
647   (defun list-all-packages ()
648     *package-list*)
649
650   (defun make-package (name &key use)
651     (let ((package (new))
652           (use (mapcar #'find-package-or-fail use)))
653       (oset package "packageName" name)
654       (oset package "symbols" (new))
655       (oset package "exports" (new))
656       (oset package "use" use)
657       (push package *package-list*)
658       package))
659
660   (defun packagep (x)
661     (and (objectp x) (in "symbols" x)))
662
663   (defun find-package (package-designator)
664     (when (packagep package-designator)
665       (return-from find-package package-designator))
666     (let ((name (string package-designator)))
667       (dolist (package *package-list*)
668         (when (string= (package-name package) name)
669           (return package)))))
670
671   (defun find-package-or-fail (package-designator)
672     (or (find-package package-designator)
673         (error "Package unknown.")))
674
675   (defun package-name (package-designator)
676     (let ((package (find-package-or-fail package-designator)))
677       (oget package "packageName")))
678
679   (defun %package-symbols (package-designator)
680     (let ((package (find-package-or-fail package-designator)))
681       (oget package "symbols")))
682
683   (defun package-use-list (package-designator)
684     (let ((package (find-package-or-fail package-designator)))
685       (oget package "use")))
686
687   (defun %package-external-symbols (package-designator)
688     (let ((package (find-package-or-fail package-designator)))
689       (oget package "exports")))
690
691   (defvar *common-lisp-package*
692     (make-package "CL"))
693
694   (defvar *user-package*
695     (make-package "CL-USER" :use (list *common-lisp-package*)))
696
697   (defvar *keyword-package*
698     (make-package "KEYWORD"))
699
700   (defun keywordp (x)
701     (and (symbolp x) (eq (symbol-package x) *keyword-package*)))
702
703   (defvar *package* *common-lisp-package*)
704
705   (defmacro in-package (package-designator)
706     `(eval-when-compile
707        (setq *package* (find-package-or-fail ,package-designator))))
708
709   ;; This function is used internally to initialize the CL package
710   ;; with the symbols built during bootstrap.
711   (defun %intern-symbol (symbol)
712     (let* ((package
713             (if (in "package" symbol)
714                 (find-package-or-fail (oget symbol "package"))
715                 *common-lisp-package*))
716            (symbols (%package-symbols package)))
717       (oset symbol "package" package)
718       (when (eq package *keyword-package*)
719         (oset symbol "value" symbol))
720       (oset symbols (symbol-name symbol) symbol)))
721
722   (defun find-symbol (name &optional (package *package*))
723     (let* ((package (find-package-or-fail package))
724            (externals (%package-external-symbols package))
725            (symbols (%package-symbols package)))
726       (cond
727         ((in name externals)
728          (values (oget externals name) :external))
729         ((in name symbols)
730          (values (oget symbols name) :internal))
731         (t
732          (dolist (used (package-use-list package) (values nil nil))
733            (let ((exports (%package-external-symbols used)))
734              (when (in name exports)
735                (return (values (oget exports name) :inherit)))))))))
736
737   (defun intern (name &optional (package *package*))
738     (let ((package (find-package-or-fail package)))
739       (multiple-value-bind (symbol foundp)
740           (find-symbol name package)
741         (if foundp
742             (values symbol foundp)
743             (let ((symbols (%package-symbols package)))
744               (oget symbols name)
745               (let ((symbol (make-symbol name)))
746                 (oset symbol "package" package)
747                 (when (eq package *keyword-package*)
748                   (oset symbol "value" symbol)
749                   (export (list symbol) package))
750                 (oset symbols name symbol)
751                 (values symbol nil)))))))
752
753   (defun symbol-package (symbol)
754     (unless (symbolp symbol)
755       (error "it is not a symbol"))
756     (oget symbol "package"))
757
758   (defun export (symbols &optional (package *package*))
759     (let ((exports (%package-external-symbols package)))
760       (dolist (symb symbols t)
761         (oset exports (symbol-name symb) symb))))
762
763   (defun get-universal-time ()
764     (+ (get-unix-time) 2208988800)))
765
766
767 ;;; The compiler offers some primitives and special forms which are
768 ;;; not found in Common Lisp, for instance, while. So, we grow Common
769 ;;; Lisp a bit to it can execute the rest of the file.
770 #+common-lisp
771 (progn
772   (defmacro while (condition &body body)
773     `(do ()
774          ((not ,condition))
775        ,@body))
776
777   (defmacro eval-when-compile (&body body)
778     `(eval-when (:compile-toplevel :load-toplevel :execute)
779        ,@body))
780
781   (defun concat-two (s1 s2)
782     (concatenate 'string s1 s2))
783
784   (defun aset (array idx value)
785     (setf (aref array idx) value)))
786
787 ;;; At this point, no matter if Common Lisp or ecmalisp is compiling
788 ;;; from here, this code will compile on both. We define some helper
789 ;;; functions now for string manipulation and so on. They will be
790 ;;; useful in the compiler, mostly.
791
792 (defvar *newline* (string (code-char 10)))
793
794 (defun concat (&rest strs)
795   (!reduce #'concat-two strs :initial-value ""))
796
797 (defmacro concatf (variable &body form)
798   `(setq ,variable (concat ,variable (progn ,@form))))
799
800 ;;; Concatenate a list of strings, with a separator
801 (defun join (list &optional (separator ""))
802   (cond
803     ((null list)
804      "")
805     ((null (cdr list))
806      (car list))
807     (t
808      (concat (car list)
809              separator
810              (join (cdr list) separator)))))
811
812 (defun join-trailing (list &optional (separator ""))
813   (if (null list)
814       ""
815       (concat (car list) separator (join-trailing (cdr list) separator))))
816
817 (defun mapconcat (func list)
818   (join (mapcar func list)))
819
820 (defun vector-to-list (vector)
821   (let ((list nil)
822         (size (length vector)))
823     (dotimes (i size (reverse list))
824       (push (aref vector i) list))))
825
826 (defun list-to-vector (list)
827   (let ((v (make-array (length list)))
828         (i 0))
829     (dolist (x list v)
830       (aset v i x)
831       (incf i))))
832
833 #+ecmalisp
834 (progn
835   (defun values-list (list)
836     (values-array (list-to-vector list)))
837
838   (defun values (&rest args)
839     (values-list args)))
840
841 (defun integer-to-string (x)
842   (cond
843     ((zerop x)
844      "0")
845     ((minusp x)
846      (concat "-" (integer-to-string (- 0 x))))
847     (t
848      (let ((digits nil))
849        (while (not (zerop x))
850          (push (mod x 10) digits)
851          (setq x (truncate x 10)))
852        (mapconcat (lambda (x) (string (digit-char x)))
853                   digits)))))
854
855
856 ;;; Printer
857
858 #+ecmalisp
859 (progn
860   (defun prin1-to-string (form)
861     (cond
862       ((symbolp form)
863        (multiple-value-bind (symbol foundp)
864            (find-symbol (symbol-name form) *package*)
865          (if (and foundp (eq symbol form))
866              (symbol-name form)
867              (let ((package (symbol-package form))
868                    (name (symbol-name form)))
869                (concat (cond
870                          ((null package) "#")
871                          ((eq package (find-package "KEYWORD")) "")
872                          (t (package-name package)))
873                        ":" name)))))
874       ((integerp form) (integer-to-string form))
875       ((stringp form) (concat "\"" (escape-string form) "\""))
876       ((functionp form)
877        (let ((name (oget form "fname")))
878          (if name
879              (concat "#<FUNCTION " name ">")
880              (concat "#<FUNCTION>"))))
881       ((listp form)
882        (concat "("
883                (join-trailing (mapcar #'prin1-to-string (butlast form)) " ")
884                (let ((last (last form)))
885                  (if (null (cdr last))
886                      (prin1-to-string (car last))
887                      (concat (prin1-to-string (car last)) " . " (prin1-to-string (cdr last)))))
888                ")"))
889       ((arrayp form)
890        (concat "#" (prin1-to-string (vector-to-list form))))
891       ((packagep form)
892        (concat "#<PACKAGE " (package-name form) ">"))))
893
894   (defun write-line (x)
895     (write-string x)
896     (write-string *newline*)
897     x)
898
899   (defun warn (string)
900     (write-string "WARNING: ")
901     (write-line string))
902
903   (defun print (x)
904     (write-line (prin1-to-string x))
905     x))
906
907
908 ;;;; Reader
909
910 ;;; The Lisp reader, parse strings and return Lisp objects. The main
911 ;;; entry points are `ls-read' and `ls-read-from-string'.
912
913 (defun make-string-stream (string)
914   (cons string 0))
915
916 (defun %peek-char (stream)
917   (and (< (cdr stream) (length (car stream)))
918        (char (car stream) (cdr stream))))
919
920 (defun %read-char (stream)
921   (and (< (cdr stream) (length (car stream)))
922        (prog1 (char (car stream) (cdr stream))
923          (rplacd stream (1+ (cdr stream))))))
924
925 (defun whitespacep (ch)
926   (or (char= ch #\space) (char= ch #\newline) (char= ch #\tab)))
927
928 (defun skip-whitespaces (stream)
929   (let (ch)
930     (setq ch (%peek-char stream))
931     (while (and ch (whitespacep ch))
932       (%read-char stream)
933       (setq ch (%peek-char stream)))))
934
935 (defun terminalp (ch)
936   (or (null ch) (whitespacep ch) (char= #\) ch) (char= #\( ch)))
937
938 (defun read-until (stream func)
939   (let ((string "")
940         (ch))
941     (setq ch (%peek-char stream))
942     (while (and ch (not (funcall func ch)))
943       (setq string (concat string (string ch)))
944       (%read-char stream)
945       (setq ch (%peek-char stream)))
946     string))
947
948 (defun skip-whitespaces-and-comments (stream)
949   (let (ch)
950     (skip-whitespaces stream)
951     (setq ch (%peek-char stream))
952     (while (and ch (char= ch #\;))
953       (read-until stream (lambda (x) (char= x #\newline)))
954       (skip-whitespaces stream)
955       (setq ch (%peek-char stream)))))
956
957 (defun %read-list (stream)
958   (skip-whitespaces-and-comments stream)
959   (let ((ch (%peek-char stream)))
960     (cond
961       ((null ch)
962        (error "Unspected EOF"))
963       ((char= ch #\))
964        (%read-char stream)
965        nil)
966       ((char= ch #\.)
967        (%read-char stream)
968        (prog1 (ls-read stream)
969          (skip-whitespaces-and-comments stream)
970          (unless (char= (%read-char stream) #\))
971            (error "')' was expected."))))
972       (t
973        (cons (ls-read stream) (%read-list stream))))))
974
975 (defun read-string (stream)
976   (let ((string "")
977         (ch nil))
978     (setq ch (%read-char stream))
979     (while (not (eql ch #\"))
980       (when (null ch)
981         (error "Unexpected EOF"))
982       (when (eql ch #\\)
983         (setq ch (%read-char stream)))
984       (setq string (concat string (string ch)))
985       (setq ch (%read-char stream)))
986     string))
987
988 (defun read-sharp (stream)
989   (%read-char stream)
990   (ecase (%read-char stream)
991     (#\'
992      (list 'function (ls-read stream)))
993     (#\( (list-to-vector (%read-list stream)))
994     (#\: (make-symbol (string-upcase (read-until stream #'terminalp))))
995     (#\\
996      (let ((cname
997             (concat (string (%read-char stream))
998                     (read-until stream #'terminalp))))
999        (cond
1000          ((string= cname "space") (char-code #\space))
1001          ((string= cname "tab") (char-code #\tab))
1002          ((string= cname "newline") (char-code #\newline))
1003          (t (char-code (char cname 0))))))
1004     (#\+
1005      (let ((feature (read-until stream #'terminalp)))
1006        (cond
1007          ((string= feature "common-lisp")
1008           (ls-read stream)              ;ignore
1009           (ls-read stream))
1010          ((string= feature "ecmalisp")
1011           (ls-read stream))
1012          (t
1013           (error "Unknown reader form.")))))))
1014
1015 ;;; Parse a string of the form NAME, PACKAGE:NAME or
1016 ;;; PACKAGE::NAME and return the name. If the string is of the
1017 ;;; form 1) or 3), but the symbol does not exist, it will be created
1018 ;;; and interned in that package.
1019 (defun read-symbol (string)
1020   (let ((size (length string))
1021         package name internalp index)
1022     (setq index 0)
1023     (while (and (< index size)
1024                 (not (char= (char string index) #\:)))
1025       (incf index))
1026     (cond
1027       ;; No package prefix
1028       ((= index size)
1029        (setq name string)
1030        (setq package *package*)
1031        (setq internalp t))
1032       (t
1033        ;; Package prefix
1034        (if (zerop index)
1035            (setq package "KEYWORD")
1036            (setq package (string-upcase (subseq string 0 index))))
1037        (incf index)
1038        (when (char= (char string index) #\:)
1039          (setq internalp t)
1040          (incf index))
1041        (setq name (subseq string index))))
1042     ;; Canonalize symbol name and package
1043     (setq name (string-upcase name))
1044     (setq package (find-package package))
1045     ;; TODO: PACKAGE:SYMBOL should signal error if SYMBOL is not an
1046     ;; external symbol from PACKAGE.
1047     (if (or internalp (eq package (find-package "KEYWORD")))
1048         (intern name package)
1049         (find-symbol name package))))
1050
1051
1052 (defun !parse-integer (string junk-allow)
1053   (block nil
1054     (let ((value 0)
1055           (index 0)
1056           (size (length string))
1057           (sign 1))
1058       (when (zerop size) (return (values nil 0)))
1059       ;; Optional sign
1060       (case (char string 0)
1061         (#\+ (incf index))
1062         (#\- (setq sign -1)
1063              (incf index)))
1064       ;; First digit
1065       (unless (and (< index size)
1066                    (setq value (digit-char-p (char string index))))
1067         (return (values nil index)))
1068       (incf index)
1069       ;; Other digits
1070       (while (< index size)
1071         (let ((digit (digit-char-p (char string index))))
1072           (unless digit (return))
1073           (setq value (+ (* value 10) digit))
1074           (incf index)))
1075       (if (or junk-allow
1076               (= index size)
1077               (char= (char string index) #\space))
1078           (values (* sign value) index)
1079           (values nil index)))))
1080
1081 #+ecmalisp
1082 (defun parse-integer (string)
1083   (!parse-integer string nil))
1084
1085 (defvar *eof* (gensym))
1086 (defun ls-read (stream)
1087   (skip-whitespaces-and-comments stream)
1088   (let ((ch (%peek-char stream)))
1089     (cond
1090       ((or (null ch) (char= ch #\)))
1091        *eof*)
1092       ((char= ch #\()
1093        (%read-char stream)
1094        (%read-list stream))
1095       ((char= ch #\')
1096        (%read-char stream)
1097        (list 'quote (ls-read stream)))
1098       ((char= ch #\`)
1099        (%read-char stream)
1100        (list 'backquote (ls-read stream)))
1101       ((char= ch #\")
1102        (%read-char stream)
1103        (read-string stream))
1104       ((char= ch #\,)
1105        (%read-char stream)
1106        (if (eql (%peek-char stream) #\@)
1107            (progn (%read-char stream) (list 'unquote-splicing (ls-read stream)))
1108            (list 'unquote (ls-read stream))))
1109       ((char= ch #\#)
1110        (read-sharp stream))
1111       (t
1112        (let ((string (read-until stream #'terminalp)))
1113          (or (values (!parse-integer string nil))
1114              (read-symbol string)))))))
1115
1116 (defun ls-read-from-string (string)
1117   (ls-read (make-string-stream string)))
1118
1119
1120 ;;;; Compiler
1121
1122 ;;; Translate the Lisp code to Javascript. It will compile the special
1123 ;;; forms. Some primitive functions are compiled as special forms
1124 ;;; too. The respective real functions are defined in the target (see
1125 ;;; the beginning of this file) as well as some primitive functions.
1126
1127 (defun code (&rest args)
1128   (mapconcat (lambda (arg)
1129                (cond
1130                  ((null arg) "")
1131                  ((integerp arg) (integer-to-string arg))
1132                  ((stringp arg) arg)
1133                  (t (error "Unknown argument."))))
1134              args))
1135
1136 ;;; Wrap X with a Javascript code to convert the result from
1137 ;;; Javascript generalized booleans to T or NIL.
1138 (defun js!bool (x)
1139   (code "(" x "?" (ls-compile t) ": " (ls-compile nil) ")"))
1140
1141 ;;; Concatenate the arguments and wrap them with a self-calling
1142 ;;; Javascript anonymous function. It is used to make some Javascript
1143 ;;; statements valid expressions and provide a private scope as well.
1144 ;;; It could be defined as function, but we could do some
1145 ;;; preprocessing in the future.
1146 (defmacro js!selfcall (&body body)
1147   `(code "(function(){" *newline* (indent ,@body) "})()"))
1148
1149 ;;; Like CODE, but prefix each line with four spaces. Two versions
1150 ;;; of this function are available, because the Ecmalisp version is
1151 ;;; very slow and bootstraping was annoying.
1152
1153 #+ecmalisp
1154 (defun indent (&rest string)
1155   (let ((input (apply #'code string)))
1156     (let ((output "")
1157           (index 0)
1158           (size (length input)))
1159       (when (plusp (length input)) (concatf output "    "))
1160       (while (< index size)
1161         (let ((str
1162                (if (and (char= (char input index) #\newline)
1163                         (< index (1- size))
1164                         (not (char= (char input (1+ index)) #\newline)))
1165                    (concat (string #\newline) "    ")
1166                    (string (char input index)))))
1167           (concatf output str))
1168         (incf index))
1169       output)))
1170
1171 #+common-lisp
1172 (defun indent (&rest string)
1173   (with-output-to-string (*standard-output*)
1174     (with-input-from-string (input (apply #'code string))
1175       (loop
1176          for line = (read-line input nil)
1177          while line
1178          do (write-string "    ")
1179          do (write-line line)))))
1180
1181
1182 ;;; A Form can return a multiple values object calling VALUES, like
1183 ;;; values(arg1, arg2, ...). It will work in any context, as well as
1184 ;;; returning an individual object. However, if the special variable
1185 ;;; `*multiple-value-p*' is NIL, is granted that only the primary
1186 ;;; value will be used, so we can optimize to avoid the VALUES
1187 ;;; function call.
1188 (defvar *multiple-value-p* nil)
1189
1190 (defun make-binding (name type value &optional declarations)
1191   (list name type value declarations))
1192
1193 (defun binding-name (b) (first b))
1194 (defun binding-type (b) (second b))
1195 (defun binding-value (b) (third b))
1196 (defun binding-declarations (b) (fourth b))
1197
1198 (defun set-binding-value (b value)
1199   (rplaca (cddr b) value))
1200
1201 (defun set-binding-declarations (b value)
1202   (rplaca (cdddr b) value))
1203
1204 (defun push-binding-declaration (decl b)
1205   (set-binding-declarations b (cons decl (binding-declarations b))))
1206
1207
1208 (defun make-lexenv ()
1209   (list nil nil nil nil))
1210
1211 (defun copy-lexenv (lexenv)
1212   (copy-list lexenv))
1213
1214 (defun push-to-lexenv (binding lexenv namespace)
1215   (ecase namespace
1216     (variable   (rplaca        lexenv  (cons binding (car lexenv))))
1217     (function   (rplaca   (cdr lexenv) (cons binding (cadr lexenv))))
1218     (block      (rplaca  (cddr lexenv) (cons binding (caddr lexenv))))
1219     (gotag      (rplaca (cdddr lexenv) (cons binding (cadddr lexenv))))))
1220
1221 (defun extend-lexenv (bindings lexenv namespace)
1222   (let ((env (copy-lexenv lexenv)))
1223     (dolist (binding (reverse bindings) env)
1224       (push-to-lexenv binding env namespace))))
1225
1226 (defun lookup-in-lexenv (name lexenv namespace)
1227   (assoc name (ecase namespace
1228                 (variable (first lexenv))
1229                 (function (second lexenv))
1230                 (block (third lexenv))
1231                 (gotag (fourth lexenv)))))
1232
1233 (defvar *environment* (make-lexenv))
1234
1235 (defvar *variable-counter* 0)
1236 (defun gvarname (symbol)
1237   (code "v" (incf *variable-counter*)))
1238
1239 (defun translate-variable (symbol)
1240   (binding-value (lookup-in-lexenv symbol *environment* 'variable)))
1241
1242 (defun extend-local-env (args)
1243   (let ((new (copy-lexenv *environment*)))
1244     (dolist (symbol args new)
1245       (let ((b (make-binding symbol 'variable (gvarname symbol))))
1246         (push-to-lexenv b new 'variable)))))
1247
1248 ;;; Toplevel compilations
1249 (defvar *toplevel-compilations* nil)
1250
1251 (defun toplevel-compilation (string)
1252   (push string *toplevel-compilations*))
1253
1254 (defun null-or-empty-p (x)
1255   (zerop (length x)))
1256
1257 (defun get-toplevel-compilations ()
1258   (reverse (remove-if #'null-or-empty-p *toplevel-compilations*)))
1259
1260 (defun %compile-defmacro (name lambda)
1261   (toplevel-compilation (ls-compile `',name))
1262   (push-to-lexenv (make-binding name 'macro lambda) *environment* 'function)
1263   name)
1264
1265 (defun global-binding (name type namespace)
1266   (or (lookup-in-lexenv name *environment* namespace)
1267       (let ((b (make-binding name type nil)))
1268         (push-to-lexenv b *environment* namespace)
1269         b)))
1270
1271 (defun claimp (symbol namespace claim)
1272   (let ((b (lookup-in-lexenv symbol *environment* namespace)))
1273     (and b (member claim (binding-declarations b)))))
1274
1275 (defun !proclaim (decl)
1276   (case (car decl)
1277     (special
1278      (dolist (name (cdr decl))
1279        (let ((b (global-binding name 'variable 'variable)))
1280          (push-binding-declaration 'special b))))
1281     (notinline
1282      (dolist (name (cdr decl))
1283        (let ((b (global-binding name 'function 'function)))
1284          (push-binding-declaration 'notinline b))))
1285     (constant
1286      (dolist (name (cdr decl))
1287        (let ((b (global-binding name 'variable 'variable)))
1288          (push-binding-declaration 'constant b))))))
1289
1290 #+ecmalisp
1291 (fset 'proclaim #'!proclaim)
1292
1293 ;;; Special forms
1294
1295 (defvar *compilations* nil)
1296
1297 (defmacro define-compilation (name args &body body)
1298   ;; Creates a new primitive `name' with parameters args and
1299   ;; @body. The body can access to the local environment through the
1300   ;; variable *ENVIRONMENT*.
1301   `(push (list ',name (lambda ,args (block ,name ,@body)))
1302          *compilations*))
1303
1304 (define-compilation if (condition true false)
1305   (code "(" (ls-compile condition) " !== " (ls-compile nil)
1306         " ? " (ls-compile true *multiple-value-p*)
1307         " : " (ls-compile false *multiple-value-p*)
1308         ")"))
1309
1310 (defvar *ll-keywords* '(&optional &rest &key))
1311
1312 (defun list-until-keyword (list)
1313   (if (or (null list) (member (car list) *ll-keywords*))
1314       nil
1315       (cons (car list) (list-until-keyword (cdr list)))))
1316
1317 (defun ll-section (keyword ll)
1318   (list-until-keyword (cdr (member keyword ll))))
1319
1320 (defun ll-required-arguments (ll)
1321   (list-until-keyword ll))
1322
1323 (defun ll-optional-arguments-canonical (ll)
1324   (mapcar #'ensure-list (ll-section '&optional ll)))
1325
1326 (defun ll-optional-arguments (ll)
1327   (mapcar #'car (ll-optional-arguments-canonical ll)))
1328
1329 (defun ll-rest-argument (ll)
1330   (let ((rest (ll-section '&rest ll)))
1331     (when (cdr rest)
1332       (error "Bad lambda-list"))
1333     (car rest)))
1334
1335 (defun ll-keyword-arguments-canonical (ll)
1336   (flet ((canonicalize (keyarg)
1337            ;; Build a canonical keyword argument descriptor, filling
1338            ;; the optional fields. The result is a list of the form
1339            ;; ((keyword-name var) init-form).
1340            (let ((arg (ensure-list keyarg)))
1341              (cons (if (listp (car arg))
1342                        (car arg)
1343                        (list (intern (symbol-name (car arg)) "KEYWORD") (car arg)))
1344                    (cdr arg)))))
1345     (mapcar #'canonicalize (ll-section '&key ll))))
1346
1347 (defun ll-keyword-arguments (ll)
1348   (mapcar (lambda (keyarg) (second (first keyarg)))
1349           (ll-keyword-arguments-canonical ll)))
1350
1351 (defun ll-svars (lambda-list)
1352   (let ((args
1353          (append
1354           (ll-keyword-arguments-canonical lambda-list)
1355           (ll-optional-arguments-canonical lambda-list))))
1356     (remove nil (mapcar #'third args))))
1357
1358 (defun lambda-docstring-wrapper (docstring &rest strs)
1359   (if docstring
1360       (js!selfcall
1361         "var func = " (join strs) ";" *newline*
1362         "func.docstring = '" docstring "';" *newline*
1363         "return func;" *newline*)
1364       (apply #'code strs)))
1365
1366 (defun lambda-check-argument-count
1367     (n-required-arguments n-optional-arguments rest-p)
1368   ;; Note: Remember that we assume that the number of arguments of a
1369   ;; call is at least 1 (the values argument).
1370   (let ((min (1+ n-required-arguments))
1371         (max (if rest-p 'n/a (+ 1 n-required-arguments n-optional-arguments))))
1372     (block nil
1373       ;; Special case: a positive exact number of arguments.
1374       (when (and (< 1 min) (eql min max))
1375         (return (code "checkArgs(arguments, " min ");" *newline*)))
1376       ;; General case:
1377       (code
1378        (when (< 1 min)
1379          (code "checkArgsAtLeast(arguments, " min ");" *newline*))
1380        (when (numberp max)
1381          (code "checkArgsAtMost(arguments, " max ");" *newline*))))))
1382
1383 (defun compile-lambda-optional (ll)
1384   (let* ((optional-arguments (ll-optional-arguments-canonical ll))
1385          (n-required-arguments (length (ll-required-arguments ll)))
1386          (n-optional-arguments (length optional-arguments)))
1387     (when optional-arguments
1388       (code (mapconcat (lambda (arg)
1389                          (code "var " (translate-variable (first arg)) "; " *newline*
1390                                (when (third arg)
1391                                  (code "var " (translate-variable (third arg))
1392                                        " = " (ls-compile t)
1393                                        "; " *newline*))))
1394                        optional-arguments)
1395             "switch(arguments.length-1){" *newline*
1396             (let ((cases nil)
1397                   (idx 0))
1398               (progn
1399                 (while (< idx n-optional-arguments)
1400                   (let ((arg (nth idx optional-arguments)))
1401                     (push (code "case " (+ idx n-required-arguments) ":" *newline*
1402                                 (indent (translate-variable (car arg))
1403                                         "="
1404                                         (ls-compile (cadr arg)) ";" *newline*)
1405                                 (when (third arg)
1406                                   (indent (translate-variable (third arg))
1407                                           "="
1408                                           (ls-compile nil)
1409                                           ";" *newline*)))
1410                           cases)
1411                     (incf idx)))
1412                 (push (code "default: break;" *newline*) cases)
1413                 (join (reverse cases))))
1414             "}" *newline*))))
1415
1416 (defun compile-lambda-rest (ll)
1417   (let ((n-required-arguments (length (ll-required-arguments ll)))
1418         (n-optional-arguments (length (ll-optional-arguments ll)))
1419         (rest-argument (ll-rest-argument ll)))
1420     (when rest-argument
1421       (let ((js!rest (translate-variable rest-argument)))
1422         (code "var " js!rest "= " (ls-compile nil) ";" *newline*
1423               "for (var i = arguments.length-1; i>="
1424               (+ 1 n-required-arguments n-optional-arguments)
1425               "; i--)" *newline*
1426               (indent js!rest " = {car: arguments[i], cdr: ") js!rest "};"
1427               *newline*)))))
1428
1429 (defun compile-lambda-parse-keywords (ll)
1430   (let ((n-required-arguments
1431          (length (ll-required-arguments ll)))
1432         (n-optional-arguments
1433          (length (ll-optional-arguments ll)))
1434         (keyword-arguments
1435          (ll-keyword-arguments-canonical ll)))
1436     (code
1437      ;; Declare variables
1438      (mapconcat (lambda (arg)
1439                   (let ((var (second (car arg))))
1440                     (code "var " (translate-variable var) "; " *newline*
1441                           (when (third arg)
1442                             (code "var " (translate-variable (third arg))
1443                                   " = " (ls-compile nil)
1444                                   ";" *newline*)))))
1445                 keyword-arguments)
1446      ;; Parse keywords
1447      (flet ((parse-keyword (keyarg)
1448               ;; ((keyword-name var) init-form)
1449               (code "for (i=" (+ 1 n-required-arguments n-optional-arguments)
1450                     "; i<arguments.length; i+=2){" *newline*
1451                     (indent
1452                      "if (arguments[i] === " (ls-compile (caar keyarg)) "){" *newline*
1453                      (indent (translate-variable (cadr (car keyarg)))
1454                              " = arguments[i+1];"
1455                              *newline*
1456                              (let ((svar (third keyarg)))
1457                                (when svar
1458                                  (code (translate-variable svar) " = " (ls-compile t) ";" *newline*)))
1459                              "break;" *newline*)
1460                      "}" *newline*)
1461                     "}" *newline*
1462                     ;; Default value
1463                     "if (i == arguments.length){" *newline*
1464                     (indent (translate-variable (cadr (car keyarg))) " = " (ls-compile (cadr keyarg)) ";" *newline*)
1465                     "}" *newline*)))
1466        (when keyword-arguments
1467          (code "var i;" *newline*
1468                (mapconcat #'parse-keyword keyword-arguments))))
1469      ;; Check for unknown keywords
1470      (when keyword-arguments
1471        (code "for (i=" (+ 1 n-required-arguments n-optional-arguments)
1472              "; i<arguments.length; i+=2){" *newline*
1473              (indent "if ("
1474                      (join (mapcar (lambda (x)
1475                                      (concat "arguments[i] !== " (ls-compile (caar x))))
1476                                    keyword-arguments)
1477                            " && ")
1478                      ")" *newline*
1479                      (indent
1480                       "throw 'Unknown keyword argument ' + arguments[i].name;" *newline*))
1481              "}" *newline*)))))
1482
1483 (defun compile-lambda (ll body)
1484   (let ((required-arguments (ll-required-arguments ll))
1485         (optional-arguments (ll-optional-arguments ll))
1486         (keyword-arguments  (ll-keyword-arguments  ll))
1487         (rest-argument      (ll-rest-argument      ll))
1488         documentation)
1489     ;; Get the documentation string for the lambda function
1490     (when (and (stringp (car body))
1491                (not (null (cdr body))))
1492       (setq documentation (car body))
1493       (setq body (cdr body)))
1494     (let ((n-required-arguments (length required-arguments))
1495           (n-optional-arguments (length optional-arguments))
1496           (*environment* (extend-local-env
1497                           (append (ensure-list rest-argument)
1498                                   required-arguments
1499                                   optional-arguments
1500                                   keyword-arguments
1501                                   (ll-svars ll)))))
1502       (lambda-docstring-wrapper
1503        documentation
1504        "(function ("
1505        (join (cons "values"
1506                    (mapcar #'translate-variable
1507                            (append required-arguments optional-arguments)))
1508              ",")
1509        "){" *newline*
1510        (indent
1511         ;; Check number of arguments
1512         (lambda-check-argument-count n-required-arguments
1513                                      n-optional-arguments
1514                                      (or rest-argument keyword-arguments))
1515         (compile-lambda-optional ll)
1516         (compile-lambda-rest ll)
1517         (compile-lambda-parse-keywords ll)
1518         (let ((*multiple-value-p* t))
1519           (ls-compile-block body t)))
1520        "})"))))
1521
1522
1523
1524 (defun setq-pair (var val)
1525   (let ((b (lookup-in-lexenv var *environment* 'variable)))
1526     (if (and (eq (binding-type b) 'variable)
1527              (not (member 'special (binding-declarations b)))
1528              (not (member 'constant (binding-declarations b))))
1529         (code (binding-value b) " = " (ls-compile val))
1530         (ls-compile `(set ',var ,val)))))
1531
1532 (define-compilation setq (&rest pairs)
1533   (let ((result ""))
1534     (while t
1535       (cond
1536         ((null pairs) (return))
1537         ((null (cdr pairs))
1538          (error "Odd paris in SETQ"))
1539         (t
1540          (concatf result
1541            (concat (setq-pair (car pairs) (cadr pairs))
1542                    (if (null (cddr pairs)) "" ", ")))
1543          (setq pairs (cddr pairs)))))
1544     (code "(" result ")")))
1545
1546 ;;; FFI Variable accessors
1547 (define-compilation js-vref (var)
1548   var)
1549
1550 (define-compilation js-vset (var val)
1551   (code "(" var " = " (ls-compile val) ")"))
1552
1553
1554 ;;; Literals
1555 (defun escape-string (string)
1556   (let ((output "")
1557         (index 0)
1558         (size (length string)))
1559     (while (< index size)
1560       (let ((ch (char string index)))
1561         (when (or (char= ch #\") (char= ch #\\))
1562           (setq output (concat output "\\")))
1563         (when (or (char= ch #\newline))
1564           (setq output (concat output "\\"))
1565           (setq ch #\n))
1566         (setq output (concat output (string ch))))
1567       (incf index))
1568     output))
1569
1570
1571 (defvar *literal-symbols* nil)
1572 (defvar *literal-counter* 0)
1573
1574 (defun genlit ()
1575   (code "l" (incf *literal-counter*)))
1576
1577 (defun literal (sexp &optional recursive)
1578   (cond
1579     ((integerp sexp) (integer-to-string sexp))
1580     ((stringp sexp) (code "\"" (escape-string sexp) "\""))
1581     ((symbolp sexp)
1582      (or (cdr (assoc sexp *literal-symbols*))
1583          (let ((v (genlit))
1584                (s #+common-lisp
1585                  (let ((package (symbol-package sexp)))
1586                    (if (eq package (find-package "KEYWORD"))
1587                        (code "{name: \"" (escape-string (symbol-name sexp))
1588                              "\", 'package': '" (package-name package) "'}")
1589                        (code "{name: \"" (escape-string (symbol-name sexp)) "\"}")))
1590                  #+ecmalisp
1591                  (let ((package (symbol-package sexp)))
1592                    (if (null package)
1593                        (code "{name: \"" (escape-string (symbol-name sexp)) "\"}")
1594                        (ls-compile `(intern ,(symbol-name sexp) ,(package-name package)))))))
1595            (push (cons sexp v) *literal-symbols*)
1596            (toplevel-compilation (code "var " v " = " s))
1597            v)))
1598     ((consp sexp)
1599      (let* ((head (butlast sexp))
1600             (tail (last sexp))
1601             (c (code "QIList("
1602                      (join-trailing (mapcar (lambda (x) (literal x t)) head) ",")
1603                      (literal (car tail) t)
1604                      ","
1605                      (literal (cdr tail) t)
1606                      ")")))
1607        (if recursive
1608            c
1609            (let ((v (genlit)))
1610              (toplevel-compilation (code "var " v " = " c))
1611              v))))
1612     ((arrayp sexp)
1613      (let ((elements (vector-to-list sexp)))
1614        (let ((c (concat "[" (join (mapcar #'literal elements) ", ") "]")))
1615          (if recursive
1616              c
1617              (let ((v (genlit)))
1618                (toplevel-compilation (code "var " v " = " c))
1619                v)))))))
1620
1621 (define-compilation quote (sexp)
1622   (literal sexp))
1623
1624 (define-compilation %while (pred &rest body)
1625   (js!selfcall
1626     "while(" (ls-compile pred) " !== " (ls-compile nil) "){" *newline*
1627     (indent (ls-compile-block body))
1628     "}"
1629     "return " (ls-compile nil) ";" *newline*))
1630
1631 (define-compilation function (x)
1632   (cond
1633     ((and (listp x) (eq (car x) 'lambda))
1634      (compile-lambda (cadr x) (cddr x)))
1635     ((symbolp x)
1636      (let ((b (lookup-in-lexenv x *environment* 'function)))
1637        (if b
1638            (binding-value b)
1639            (ls-compile `(symbol-function ',x)))))))
1640
1641
1642 (defun make-function-binding (fname)
1643   (make-binding fname 'function (gvarname fname)))
1644
1645 (defun compile-function-definition (list)
1646   (compile-lambda (car list) (cdr list)))
1647
1648 (defun translate-function (name)
1649   (let ((b (lookup-in-lexenv name *environment* 'function)))
1650     (binding-value b)))
1651
1652 (define-compilation flet (definitions &rest body)
1653   (let* ((fnames (mapcar #'car definitions))
1654          (fbody  (mapcar #'cdr definitions))
1655          (cfuncs (mapcar #'compile-function-definition fbody))
1656          (*environment*
1657           (extend-lexenv (mapcar #'make-function-binding fnames)
1658                          *environment*
1659                          'function)))
1660     (code "(function("
1661           (join (mapcar #'translate-function fnames) ",")
1662           "){" *newline*
1663           (let ((body (ls-compile-block body t)))
1664             (indent body))
1665           "})(" (join cfuncs ",") ")")))
1666
1667 (define-compilation labels (definitions &rest body)
1668   (let* ((fnames (mapcar #'car definitions))
1669          (*environment*
1670           (extend-lexenv (mapcar #'make-function-binding fnames)
1671                          *environment*
1672                          'function)))
1673     (js!selfcall
1674       (mapconcat (lambda (func)
1675                    (code "var " (translate-function (car func))
1676                          " = " (compile-lambda (cadr func) (cddr func))
1677                          ";" *newline*))
1678                  definitions)
1679       (ls-compile-block body t))))
1680
1681
1682
1683 (defvar *compiling-file* nil)
1684 (define-compilation eval-when-compile (&rest body)
1685   (if *compiling-file*
1686       (progn
1687         (eval (cons 'progn body))
1688         nil)
1689       (ls-compile `(progn ,@body))))
1690
1691 (defmacro define-transformation (name args form)
1692   `(define-compilation ,name ,args
1693      (ls-compile ,form)))
1694
1695 (define-compilation progn (&rest body)
1696   (if (null (cdr body))
1697       (ls-compile (car body) *multiple-value-p*)
1698       (js!selfcall (ls-compile-block body t))))
1699
1700 (defun special-variable-p (x)
1701   (and (claimp x 'variable 'special) t))
1702
1703 ;;; Wrap CODE to restore the symbol values of the dynamic
1704 ;;; bindings. BINDINGS is a list of pairs of the form
1705 ;;; (SYMBOL . PLACE),  where PLACE is a Javascript variable
1706 ;;; name to initialize the symbol value and where to stored
1707 ;;; the old value.
1708 (defun let-binding-wrapper (bindings body)
1709   (when (null bindings)
1710     (return-from let-binding-wrapper body))
1711   (code
1712    "try {" *newline*
1713    (indent "var tmp;" *newline*
1714            (mapconcat
1715             (lambda (b)
1716               (let ((s (ls-compile `(quote ,(car b)))))
1717                 (code "tmp = " s ".value;" *newline*
1718                       s ".value = " (cdr b) ";" *newline*
1719                       (cdr b) " = tmp;" *newline*)))
1720             bindings)
1721            body *newline*)
1722    "}" *newline*
1723    "finally {"  *newline*
1724    (indent
1725     (mapconcat (lambda (b)
1726                  (let ((s (ls-compile `(quote ,(car b)))))
1727                    (code s ".value" " = " (cdr b) ";" *newline*)))
1728                bindings))
1729    "}" *newline*))
1730
1731 (define-compilation let (bindings &rest body)
1732   (let* ((bindings (mapcar #'ensure-list bindings))
1733          (variables (mapcar #'first bindings))
1734          (cvalues (mapcar #'ls-compile (mapcar #'second bindings)))
1735          (*environment* (extend-local-env (remove-if #'special-variable-p variables)))
1736          (dynamic-bindings))
1737     (code "(function("
1738           (join (mapcar (lambda (x)
1739                           (if (special-variable-p x)
1740                               (let ((v (gvarname x)))
1741                                 (push (cons x v) dynamic-bindings)
1742                                 v)
1743                               (translate-variable x)))
1744                         variables)
1745                 ",")
1746           "){" *newline*
1747           (let ((body (ls-compile-block body t)))
1748             (indent (let-binding-wrapper dynamic-bindings body)))
1749           "})(" (join cvalues ",") ")")))
1750
1751
1752 ;;; Return the code to initialize BINDING, and push it extending the
1753 ;;; current lexical environment if the variable is not special.
1754 (defun let*-initialize-value (binding)
1755   (let ((var (first binding))
1756         (value (second binding)))
1757     (if (special-variable-p var)
1758         (code (ls-compile `(setq ,var ,value)) ";" *newline*)
1759         (let* ((v (gvarname var))
1760                (b (make-binding var 'variable v)))
1761           (prog1 (code "var " v " = " (ls-compile value) ";" *newline*)
1762             (push-to-lexenv b *environment* 'variable))))))
1763
1764 ;;; Wrap BODY to restore the symbol values of SYMBOLS after body. It
1765 ;;; DOES NOT generate code to initialize the value of the symbols,
1766 ;;; unlike let-binding-wrapper.
1767 (defun let*-binding-wrapper (symbols body)
1768   (when (null symbols)
1769     (return-from let*-binding-wrapper body))
1770   (let ((store (mapcar (lambda (s) (cons s (gvarname s)))
1771                        (remove-if-not #'special-variable-p symbols))))
1772     (code
1773      "try {" *newline*
1774      (indent
1775       (mapconcat (lambda (b)
1776                    (let ((s (ls-compile `(quote ,(car b)))))
1777                      (code "var " (cdr b) " = " s ".value;" *newline*)))
1778                  store)
1779       body)
1780      "}" *newline*
1781      "finally {" *newline*
1782      (indent
1783       (mapconcat (lambda (b)
1784                    (let ((s (ls-compile `(quote ,(car b)))))
1785                      (code s ".value" " = " (cdr b) ";" *newline*)))
1786                  store))
1787      "}" *newline*)))
1788
1789 (define-compilation let* (bindings &rest body)
1790   (let ((bindings (mapcar #'ensure-list bindings))
1791         (*environment* (copy-lexenv *environment*)))
1792     (js!selfcall
1793       (let ((specials (remove-if-not #'special-variable-p (mapcar #'first bindings)))
1794             (body (concat (mapconcat #'let*-initialize-value bindings)
1795                           (ls-compile-block body t))))
1796         (let*-binding-wrapper specials body)))))
1797
1798
1799 (defvar *block-counter* 0)
1800
1801 (define-compilation block (name &rest body)
1802   (let* ((tr (incf *block-counter*))
1803          (b (make-binding name 'block tr)))
1804     (when *multiple-value-p*
1805       (push-binding-declaration 'multiple-value b))
1806     (let* ((*environment* (extend-lexenv (list b) *environment* 'block))
1807            (cbody (ls-compile-block body t)))
1808       (if (member 'used (binding-declarations b))
1809           (js!selfcall
1810             "try {" *newline*
1811             (indent cbody)
1812             "}" *newline*
1813             "catch (cf){" *newline*
1814             "    if (cf.type == 'block' && cf.id == " tr ")" *newline*
1815             (if *multiple-value-p*
1816                 "        return values.apply(this, forcemv(cf.values));"
1817                 "        return cf.values;")
1818             *newline*
1819             "    else" *newline*
1820             "        throw cf;" *newline*
1821             "}" *newline*)
1822           (js!selfcall cbody)))))
1823
1824 (define-compilation return-from (name &optional value)
1825   (let* ((b (lookup-in-lexenv name *environment* 'block))
1826          (multiple-value-p (member 'multiple-value (binding-declarations b))))
1827     (when (null b)
1828       (error (concat "Unknown block `" (symbol-name name) "'.")))
1829     (push-binding-declaration 'used b)
1830     (js!selfcall
1831       (when multiple-value-p (code "var values = mv;" *newline*))
1832       "throw ({"
1833       "type: 'block', "
1834       "id: " (binding-value b) ", "
1835       "values: " (ls-compile value multiple-value-p) ", "
1836       "message: 'Return from unknown block " (symbol-name name) ".'"
1837       "})")))
1838
1839 (define-compilation catch (id &rest body)
1840   (js!selfcall
1841     "var id = " (ls-compile id) ";" *newline*
1842     "try {" *newline*
1843     (indent (ls-compile-block body t)) *newline*
1844     "}" *newline*
1845     "catch (cf){" *newline*
1846     "    if (cf.type == 'catch' && cf.id == id)" *newline*
1847     (if *multiple-value-p*
1848         "        return values.apply(this, forcemv(cf.values));"
1849         "        return pv.apply(this, forcemv(cf.values));")
1850     *newline*
1851     "    else" *newline*
1852     "        throw cf;" *newline*
1853     "}" *newline*))
1854
1855 (define-compilation throw (id value)
1856   (js!selfcall
1857     "var values = mv;" *newline*
1858     "throw ({"
1859     "type: 'catch', "
1860     "id: " (ls-compile id) ", "
1861     "values: " (ls-compile value t) ", "
1862     "message: 'Throw uncatched.'"
1863     "})"))
1864
1865
1866 (defvar *tagbody-counter* 0)
1867 (defvar *go-tag-counter* 0)
1868
1869 (defun go-tag-p (x)
1870   (or (integerp x) (symbolp x)))
1871
1872 (defun declare-tagbody-tags (tbidx body)
1873   (let ((bindings
1874          (mapcar (lambda (label)
1875                    (let ((tagidx (integer-to-string (incf *go-tag-counter*))))
1876                      (make-binding label 'gotag (list tbidx tagidx))))
1877                  (remove-if-not #'go-tag-p body))))
1878     (extend-lexenv bindings *environment* 'gotag)))
1879
1880 (define-compilation tagbody (&rest body)
1881   ;; Ignore the tagbody if it does not contain any go-tag. We do this
1882   ;; because 1) it is easy and 2) many built-in forms expand to a
1883   ;; implicit tagbody, so we save some space.
1884   (unless (some #'go-tag-p body)
1885     (return-from tagbody (ls-compile `(progn ,@body nil))))
1886   ;; The translation assumes the first form in BODY is a label
1887   (unless (go-tag-p (car body))
1888     (push (gensym "START") body))
1889   ;; Tagbody compilation
1890   (let ((tbidx *tagbody-counter*))
1891     (let ((*environment* (declare-tagbody-tags tbidx body))
1892           initag)
1893       (let ((b (lookup-in-lexenv (first body) *environment* 'gotag)))
1894         (setq initag (second (binding-value b))))
1895       (js!selfcall
1896         "var tagbody_" tbidx " = " initag ";" *newline*
1897         "tbloop:" *newline*
1898         "while (true) {" *newline*
1899         (indent "try {" *newline*
1900                 (indent (let ((content ""))
1901                           (code "switch(tagbody_" tbidx "){" *newline*
1902                                 "case " initag ":" *newline*
1903                                 (dolist (form (cdr body) content)
1904                                   (concatf content
1905                                     (if (not (go-tag-p form))
1906                                         (indent (ls-compile form) ";" *newline*)
1907                                         (let ((b (lookup-in-lexenv form *environment* 'gotag)))
1908                                           (code "case " (second (binding-value b)) ":" *newline*)))))
1909                                 "default:" *newline*
1910                                 "    break tbloop;" *newline*
1911                                 "}" *newline*)))
1912                 "}" *newline*
1913                 "catch (jump) {" *newline*
1914                 "    if (jump.type == 'tagbody' && jump.id == " tbidx ")" *newline*
1915                 "        tagbody_" tbidx " = jump.label;" *newline*
1916                 "    else" *newline*
1917                 "        throw(jump);" *newline*
1918                 "}" *newline*)
1919         "}" *newline*
1920         "return " (ls-compile nil) ";" *newline*))))
1921
1922 (define-compilation go (label)
1923   (let ((b (lookup-in-lexenv label *environment* 'gotag))
1924         (n (cond
1925              ((symbolp label) (symbol-name label))
1926              ((integerp label) (integer-to-string label)))))
1927     (when (null b)
1928       (error (concat "Unknown tag `" n "'.")))
1929     (js!selfcall
1930       "throw ({"
1931       "type: 'tagbody', "
1932       "id: " (first (binding-value b)) ", "
1933       "label: " (second (binding-value b)) ", "
1934       "message: 'Attempt to GO to non-existing tag " n "'"
1935       "})" *newline*)))
1936
1937 (define-compilation unwind-protect (form &rest clean-up)
1938   (js!selfcall
1939     "var ret = " (ls-compile nil) ";" *newline*
1940     "try {" *newline*
1941     (indent "ret = " (ls-compile form) ";" *newline*)
1942     "} finally {" *newline*
1943     (indent (ls-compile-block clean-up))
1944     "}" *newline*
1945     "return ret;" *newline*))
1946
1947 (define-compilation multiple-value-call (func-form &rest forms)
1948   (js!selfcall
1949     "var func = " (ls-compile func-form) ";" *newline*
1950     "var args = [" (if *multiple-value-p* "values" "pv") "];" *newline*
1951     "return "
1952     (js!selfcall
1953       "var values = mv;" *newline*
1954       "var vs;" *newline*
1955       (mapconcat (lambda (form)
1956                    (code "vs = " (ls-compile form t) ";" *newline*
1957                          "if (typeof vs === 'object' && 'multiple-value' in vs)" *newline*
1958                          (indent "args = args.concat(vs);" *newline*)
1959                          "else" *newline*
1960                          (indent "args.push(vs);" *newline*)))
1961                  forms)
1962       "return func.apply(window, args);" *newline*) ";" *newline*))
1963
1964 (define-compilation multiple-value-prog1 (first-form &rest forms)
1965   (js!selfcall
1966     "var args = " (ls-compile first-form *multiple-value-p*) ";" *newline*
1967     (ls-compile-block forms)
1968     "return args;" *newline*))
1969
1970
1971
1972 ;;; A little backquote implementation without optimizations of any
1973 ;;; kind for ecmalisp.
1974 (defun backquote-expand-1 (form)
1975   (cond
1976     ((symbolp form)
1977      (list 'quote form))
1978     ((atom form)
1979      form)
1980     ((eq (car form) 'unquote)
1981      (car form))
1982     ((eq (car form) 'backquote)
1983      (backquote-expand-1 (backquote-expand-1 (cadr form))))
1984     (t
1985      (cons 'append
1986            (mapcar (lambda (s)
1987                      (cond
1988                        ((and (listp s) (eq (car s) 'unquote))
1989                         (list 'list (cadr s)))
1990                        ((and (listp s) (eq (car s) 'unquote-splicing))
1991                         (cadr s))
1992                        (t
1993                         (list 'list (backquote-expand-1 s)))))
1994                    form)))))
1995
1996 (defun backquote-expand (form)
1997   (if (and (listp form) (eq (car form) 'backquote))
1998       (backquote-expand-1 (cadr form))
1999       form))
2000
2001 (defmacro backquote (form)
2002   (backquote-expand-1 form))
2003
2004 (define-transformation backquote (form)
2005   (backquote-expand-1 form))
2006
2007 ;;; Primitives
2008
2009 (defvar *builtins* nil)
2010
2011 (defmacro define-raw-builtin (name args &body body)
2012   ;; Creates a new primitive function `name' with parameters args and
2013   ;; @body. The body can access to the local environment through the
2014   ;; variable *ENVIRONMENT*.
2015   `(push (list ',name (lambda ,args (block ,name ,@body)))
2016          *builtins*))
2017
2018 (defmacro define-builtin (name args &body body)
2019   `(define-raw-builtin ,name ,args
2020      (let ,(mapcar (lambda (arg) `(,arg (ls-compile ,arg))) args)
2021        ,@body)))
2022
2023 ;;; DECLS is a list of (JSVARNAME TYPE LISPFORM) declarations.
2024 (defmacro type-check (decls &body body)
2025   `(js!selfcall
2026      ,@(mapcar (lambda (decl)
2027                  `(code "var " ,(first decl) " = " ,(third decl) ";" *newline*))
2028                decls)
2029      ,@(mapcar (lambda (decl)
2030                  `(code "if (typeof " ,(first decl) " != '" ,(second decl) "')" *newline*
2031                         (indent "throw 'The value ' + "
2032                                 ,(first decl)
2033                                 " + ' is not a type "
2034                                 ,(second decl)
2035                                 ".';"
2036                                 *newline*)))
2037                decls)
2038      (code "return " (progn ,@body) ";" *newline*)))
2039
2040 ;;; VARIABLE-ARITY compiles variable arity operations. ARGS stands for
2041 ;;; a variable which holds a list of forms. It will compile them and
2042 ;;; store the result in some Javascript variables. BODY is evaluated
2043 ;;; with ARGS bound to the list of these variables to generate the
2044 ;;; code which performs the transformation on these variables.
2045
2046 (defun variable-arity-call (args function)
2047   (unless (consp args)
2048     (error "ARGS must be a non-empty list"))
2049   (let ((counter 0)
2050         (fargs '())
2051         (prelude ""))
2052     (dolist (x args)
2053       (if (numberp x)
2054           (push (integer-to-string x) fargs)
2055           (let ((v (code "x" (incf counter))))
2056             (push v fargs)
2057             (concatf prelude
2058               (code "var " v " = " (ls-compile x) ";" *newline*
2059                     "if (typeof " v " !== 'number') throw 'Not a number!';"
2060                     *newline*)))))
2061     (js!selfcall prelude (funcall function (reverse fargs)))))
2062
2063
2064 (defmacro variable-arity (args &body body)
2065   (unless (symbolp args)
2066     (error "Bad usage of VARIABLE-ARITY, you must pass a symbol"))
2067   `(variable-arity-call ,args
2068                         (lambda (,args)
2069                           (code "return " ,@body ";" *newline*))))
2070
2071 (defun num-op-num (x op y)
2072   (type-check (("x" "number" x) ("y" "number" y))
2073     (code "x" op "y")))
2074
2075 (define-raw-builtin + (&rest numbers)
2076   (if (null numbers)
2077       "0"
2078       (variable-arity numbers
2079         (join numbers "+"))))
2080
2081 (define-raw-builtin - (x &rest others)
2082   (let ((args (cons x others)))
2083     (variable-arity args
2084       (if (null others)
2085           (concat "-" (car args))
2086           (join args "-")))))
2087
2088 (define-raw-builtin * (&rest numbers)
2089   (if (null numbers)
2090       "1"
2091       (variable-arity numbers
2092         (join numbers "*"))))
2093
2094 (define-raw-builtin / (x &rest others)
2095   (let ((args (cons x others)))
2096     (variable-arity args
2097       (if (null others)
2098           (concat "1 /" (car args))
2099           (join args "/")))))
2100
2101 (define-builtin mod (x y) (num-op-num x "%" y))
2102
2103
2104 (defun comparison-conjuntion (vars op)
2105   (cond
2106     ((null (cdr vars))
2107      "true")
2108     ((null (cddr vars))
2109      (concat (car vars) op (cadr vars)))
2110     (t
2111      (concat (car vars) op (cadr vars)
2112              " && "
2113              (comparison-conjuntion (cdr vars) op)))))
2114
2115 (defmacro define-builtin-comparison (op sym)
2116   `(define-raw-builtin ,op (x &rest args)
2117      (let ((args (cons x args)))
2118        (variable-arity args
2119          (js!bool (comparison-conjuntion args ,sym))))))
2120
2121 (define-builtin-comparison > ">")
2122 (define-builtin-comparison < "<")
2123 (define-builtin-comparison >= ">=")
2124 (define-builtin-comparison <= "<=")
2125 (define-builtin-comparison = "==")
2126
2127 (define-builtin numberp (x)
2128   (js!bool (code "(typeof (" x ") == \"number\")")))
2129
2130 (define-builtin floor (x)
2131   (type-check (("x" "number" x))
2132     "Math.floor(x)"))
2133
2134 (define-builtin cons (x y)
2135   (code "({car: " x ", cdr: " y "})"))
2136
2137 (define-builtin consp (x)
2138   (js!bool
2139    (js!selfcall
2140      "var tmp = " x ";" *newline*
2141      "return (typeof tmp == 'object' && 'car' in tmp);" *newline*)))
2142
2143 (define-builtin car (x)
2144   (js!selfcall
2145     "var tmp = " x ";" *newline*
2146     "return tmp === " (ls-compile nil)
2147     "? " (ls-compile nil)
2148     ": tmp.car;" *newline*))
2149
2150 (define-builtin cdr (x)
2151   (js!selfcall
2152     "var tmp = " x ";" *newline*
2153     "return tmp === " (ls-compile nil) "? "
2154     (ls-compile nil)
2155     ": tmp.cdr;" *newline*))
2156
2157 (define-builtin rplaca (x new)
2158   (type-check (("x" "object" x))
2159     (code "(x.car = " new ", x)")))
2160
2161 (define-builtin rplacd (x new)
2162   (type-check (("x" "object" x))
2163     (code "(x.cdr = " new ", x)")))
2164
2165 (define-builtin symbolp (x)
2166   (js!bool
2167    (js!selfcall
2168      "var tmp = " x ";" *newline*
2169      "return (typeof tmp == 'object' && 'name' in tmp);" *newline*)))
2170
2171 (define-builtin make-symbol (name)
2172   (type-check (("name" "string" name))
2173     "({name: name})"))
2174
2175 (define-builtin symbol-name (x)
2176   (code "(" x ").name"))
2177
2178 (define-builtin set (symbol value)
2179   (code "(" symbol ").value = " value))
2180
2181 (define-builtin fset (symbol value)
2182   (code "(" symbol ").fvalue = " value))
2183
2184 (define-builtin boundp (x)
2185   (js!bool (code "(" x ".value !== undefined)")))
2186
2187 (define-builtin symbol-value (x)
2188   (js!selfcall
2189     "var symbol = " x ";" *newline*
2190     "var value = symbol.value;" *newline*
2191     "if (value === undefined) throw \"Variable `\" + symbol.name + \"' is unbound.\";" *newline*
2192     "return value;" *newline*))
2193
2194 (define-builtin symbol-function (x)
2195   (js!selfcall
2196     "var symbol = " x ";" *newline*
2197     "var func = symbol.fvalue;" *newline*
2198     "if (func === undefined) throw \"Function `\" + symbol.name + \"' is undefined.\";" *newline*
2199     "return func;" *newline*))
2200
2201 (define-builtin symbol-plist (x)
2202   (code "((" x ").plist || " (ls-compile nil) ")"))
2203
2204 (define-builtin lambda-code (x)
2205   (code "(" x ").toString()"))
2206
2207 (define-builtin eq    (x y) (js!bool (code "(" x " === " y ")")))
2208 (define-builtin equal (x y) (js!bool (code "(" x  " == " y ")")))
2209
2210 (define-builtin char-to-string (x)
2211   (type-check (("x" "number" x))
2212     "String.fromCharCode(x)"))
2213
2214 (define-builtin stringp (x)
2215   (js!bool (code "(typeof(" x ") == \"string\")")))
2216
2217 (define-builtin string-upcase (x)
2218   (type-check (("x" "string" x))
2219     "x.toUpperCase()"))
2220
2221 (define-builtin string-length (x)
2222   (type-check (("x" "string" x))
2223     "x.length"))
2224
2225 (define-raw-builtin slice (string a &optional b)
2226   (js!selfcall
2227     "var str = " (ls-compile string) ";" *newline*
2228     "var a = " (ls-compile a) ";" *newline*
2229     "var b;" *newline*
2230     (when b (code "b = " (ls-compile b) ";" *newline*))
2231     "return str.slice(a,b);" *newline*))
2232
2233 (define-builtin char (string index)
2234   (type-check (("string" "string" string)
2235                ("index" "number" index))
2236     "string.charCodeAt(index)"))
2237
2238 (define-builtin concat-two (string1 string2)
2239   (type-check (("string1" "string" string1)
2240                ("string2" "string" string2))
2241     "string1.concat(string2)"))
2242
2243 (define-raw-builtin funcall (func &rest args)
2244   (js!selfcall
2245     "var f = " (ls-compile func) ";" *newline*
2246     "return (typeof f === 'function'? f: f.fvalue)("
2247     (join (cons (if *multiple-value-p* "values" "pv")
2248                 (mapcar #'ls-compile args))
2249           ", ")
2250     ")"))
2251
2252 (define-raw-builtin apply (func &rest args)
2253   (if (null args)
2254       (code "(" (ls-compile func) ")()")
2255       (let ((args (butlast args))
2256             (last (car (last args))))
2257         (js!selfcall
2258           "var f = " (ls-compile func) ";" *newline*
2259           "var args = [" (join (cons (if *multiple-value-p* "values" "pv")
2260                                      (mapcar #'ls-compile args))
2261                                ", ")
2262           "];" *newline*
2263           "var tail = (" (ls-compile last) ");" *newline*
2264           "while (tail != " (ls-compile nil) "){" *newline*
2265           "    args.push(tail.car);" *newline*
2266           "    tail = tail.cdr;" *newline*
2267           "}" *newline*
2268           "return (typeof f === 'function'? f : f.fvalue).apply(this, args);" *newline*))))
2269
2270 (define-builtin js-eval (string)
2271   (type-check (("string" "string" string))
2272     (if *multiple-value-p*
2273         (js!selfcall
2274           "var v = eval.apply(window, [string]);" *newline*
2275           "if (typeof v !== 'object' || !('multiple-value' in v)){" *newline*
2276           (indent "v = [v];" *newline*
2277                   "v['multiple-value'] = true;" *newline*)
2278           "}" *newline*
2279           "return values.apply(this, v);" *newline*)
2280         "eval.apply(window, [string])")))
2281
2282 (define-builtin error (string)
2283   (js!selfcall "throw " string ";" *newline*))
2284
2285 (define-builtin new () "{}")
2286
2287 (define-builtin objectp (x)
2288   (js!bool (code "(typeof (" x ") === 'object')")))
2289
2290 (define-builtin oget (object key)
2291   (js!selfcall
2292     "var tmp = " "(" object ")[" key "];" *newline*
2293     "return tmp == undefined? " (ls-compile nil) ": tmp ;" *newline*))
2294
2295 (define-builtin oset (object key value)
2296   (code "((" object ")[" key "] = " value ")"))
2297
2298 (define-builtin in (key object)
2299   (js!bool (code "((" key ") in (" object "))")))
2300
2301 (define-builtin functionp (x)
2302   (js!bool (code "(typeof " x " == 'function')")))
2303
2304 (define-builtin write-string (x)
2305   (type-check (("x" "string" x))
2306     "lisp.write(x)"))
2307
2308 (define-builtin make-array (n)
2309   (js!selfcall
2310     "var r = [];" *newline*
2311     "for (var i = 0; i < " n "; i++)" *newline*
2312     (indent "r.push(" (ls-compile nil) ");" *newline*)
2313     "return r;" *newline*))
2314
2315 (define-builtin arrayp (x)
2316   (js!bool
2317    (js!selfcall
2318      "var x = " x ";" *newline*
2319      "return typeof x === 'object' && 'length' in x;")))
2320
2321 (define-builtin aref (array n)
2322   (js!selfcall
2323     "var x = " "(" array ")[" n "];" *newline*
2324     "if (x === undefined) throw 'Out of range';" *newline*
2325     "return x;" *newline*))
2326
2327 (define-builtin aset (array n value)
2328   (js!selfcall
2329     "var x = " array ";" *newline*
2330     "var i = " n ";" *newline*
2331     "if (i < 0 || i >= x.length) throw 'Out of range';" *newline*
2332     "return x[i] = " value ";" *newline*))
2333
2334 (define-builtin get-unix-time ()
2335   (code "(Math.round(new Date() / 1000))"))
2336
2337 (define-builtin values-array (array)
2338   (if *multiple-value-p*
2339       (code "values.apply(this, " array ")")
2340       (code "pv.apply(this, " array ")")))
2341
2342 (define-raw-builtin values (&rest args)
2343   (if *multiple-value-p*
2344       (code "values(" (join (mapcar #'ls-compile args) ", ") ")")
2345       (code "pv(" (join (mapcar #'ls-compile args) ", ") ")")))
2346
2347 (defun macro (x)
2348   (and (symbolp x)
2349        (let ((b (lookup-in-lexenv x *environment* 'function)))
2350          (and (eq (binding-type b) 'macro)
2351               b))))
2352
2353 (defun ls-macroexpand-1 (form)
2354   (let ((macro-binding (macro (car form))))
2355     (if macro-binding
2356         (let ((expander (binding-value macro-binding)))
2357           (when (listp expander)
2358             (let ((compiled (eval expander)))
2359               ;; The list representation are useful while
2360               ;; bootstrapping, as we can dump the definition of the
2361               ;; macros easily, but they are slow because we have to
2362               ;; evaluate them and compile them now and again. So, let
2363               ;; us replace the list representation version of the
2364               ;; function with the compiled one.
2365               ;;
2366               #+ecmalisp (set-binding-value macro-binding compiled)
2367               (setq expander compiled)))
2368           (apply expander (cdr form)))
2369         form)))
2370
2371 (defun compile-funcall (function args)
2372   (let* ((values-funcs (if *multiple-value-p* "values" "pv"))
2373          (arglist (concat "(" (join (cons values-funcs (mapcar #'ls-compile args)) ", ") ")")))
2374     (cond
2375       ((translate-function function)
2376        (concat (translate-function function) arglist))
2377       ((and (symbolp function)
2378             #+ecmalisp (eq (symbol-package function) (find-package "COMMON-LISP"))
2379             #+common-lisp t)
2380        (code (ls-compile `',function) ".fvalue" arglist))
2381       (t
2382        (code (ls-compile `#',function) arglist)))))
2383
2384 (defun ls-compile-block (sexps &optional return-last-p)
2385   (if return-last-p
2386       (code (ls-compile-block (butlast sexps))
2387             "return " (ls-compile (car (last sexps)) *multiple-value-p*) ";")
2388       (join-trailing
2389        (remove-if #'null-or-empty-p (mapcar #'ls-compile sexps))
2390        (concat ";" *newline*))))
2391
2392 (defun ls-compile (sexp &optional multiple-value-p)
2393   (let ((*multiple-value-p* multiple-value-p))
2394     (cond
2395       ((symbolp sexp)
2396        (let ((b (lookup-in-lexenv sexp *environment* 'variable)))
2397          (cond
2398            ((and b (not (member 'special (binding-declarations b))))
2399             (binding-value b))
2400            ((or (keywordp sexp)
2401                 (member 'constant (binding-declarations b)))
2402             (code (ls-compile `',sexp) ".value"))
2403            (t
2404             (ls-compile `(symbol-value ',sexp))))))
2405       ((integerp sexp) (integer-to-string sexp))
2406       ((stringp sexp) (code "\"" (escape-string sexp) "\""))
2407       ((arrayp sexp) (literal sexp))
2408       ((listp sexp)
2409        (let ((name (car sexp))
2410              (args (cdr sexp)))
2411          (cond
2412            ;; Special forms
2413            ((assoc name *compilations*)
2414             (let ((comp (second (assoc name *compilations*))))
2415               (apply comp args)))
2416            ;; Built-in functions
2417            ((and (assoc name *builtins*)
2418                  (not (claimp name 'function 'notinline)))
2419             (let ((comp (second (assoc name *builtins*))))
2420               (apply comp args)))
2421            (t
2422             (if (macro name)
2423                 (ls-compile (ls-macroexpand-1 sexp) multiple-value-p)
2424                 (compile-funcall name args))))))
2425       (t
2426        (error "How should I compile this?")))))
2427
2428 (defun ls-compile-toplevel (sexp &optional multiple-value-p)
2429   (let ((*toplevel-compilations* nil))
2430     (cond
2431       ((and (consp sexp) (eq (car sexp) 'progn))
2432        (let ((subs (mapcar (lambda (s)
2433                              (ls-compile-toplevel s t))
2434                            (cdr sexp))))
2435          (join (remove-if #'null-or-empty-p subs))))
2436       (t
2437        (let ((code (ls-compile sexp multiple-value-p)))
2438          (code (join-trailing (get-toplevel-compilations)
2439                               (code ";" *newline*))
2440                (when code
2441                  (code code ";" *newline*))))))))
2442
2443
2444 ;;; Once we have the compiler, we define the runtime environment and
2445 ;;; interactive development (eval), which works calling the compiler
2446 ;;; and evaluating the Javascript result globally.
2447
2448 #+ecmalisp
2449 (progn
2450   (defun eval (x)
2451     (js-eval (ls-compile-toplevel x t)))
2452
2453   (export '(&rest &key &optional &body * *gensym-counter* *package* + - / 1+ 1- <
2454             <= = = > >= and append apply aref arrayp assoc atom block boundp
2455             boundp butlast caar cadddr caddr cadr car car case catch cdar cdddr
2456             cddr cdr cdr char char-code fdefinition find-package find-symbol first
2457             flet fourth fset funcall function functionp gensym get-setf-expansion
2458             get-universal-time go identity if in-package incf integerp integerp
2459             intern keywordp labels lambda last length let let* char= code-char
2460             cond cons consp constantly copy-list decf declaim define-setf-expander
2461             defconstant defparameter defun defmacro defvar digit-char digit-char-p
2462             disassemble do do* documentation dolist dotimes ecase eq eql equal
2463             error eval every export list-all-packages list listp loop make-array
2464             make-package make-symbol mapcar member minusp mod multiple-value-bind
2465             multiple-value-call multiple-value-list multiple-value-prog1 nil not
2466             nth nthcdr null numberp or package-name package-use-list packagep
2467             parse-integer plusp prin1-to-string print proclaim prog1 prog2 progn
2468             psetq push quote remove remove-if remove-if-not return return-from
2469             revappend reverse rplaca rplacd second set setf setq some
2470             string-upcase string string= stringp subseq symbol-function
2471             symbol-name symbol-package symbol-plist symbol-value symbolp t tagbody
2472             third throw truncate unless unwind-protect values values-list variable
2473             warn when write-line write-string zerop))
2474
2475   (setq *package* *user-package*)
2476
2477   (js-eval "var lisp")
2478   (js-vset "lisp" (new))
2479   (js-vset "lisp.read" #'ls-read-from-string)
2480   (js-vset "lisp.print" #'prin1-to-string)
2481   (js-vset "lisp.eval" #'eval)
2482   (js-vset "lisp.compile" (lambda (s) (ls-compile-toplevel s t)))
2483   (js-vset "lisp.evalString" (lambda (str) (eval (ls-read-from-string str))))
2484   (js-vset "lisp.compileString" (lambda (str) (ls-compile-toplevel (ls-read-from-string str) t)))
2485
2486   ;; Set the initial global environment to be equal to the host global
2487   ;; environment at this point of the compilation.
2488   (eval-when-compile
2489     (toplevel-compilation
2490      (ls-compile `(setq *environment* ',*environment*))))
2491
2492   (eval-when-compile
2493     (toplevel-compilation
2494      (ls-compile
2495       `(progn
2496          ,@(mapcar (lambda (s) `(%intern-symbol (js-vref ,(cdr s))))
2497                    *literal-symbols*)
2498          (setq *literal-symbols* ',*literal-symbols*)
2499          (setq *variable-counter* ,*variable-counter*)
2500          (setq *gensym-counter* ,*gensym-counter*)
2501          (setq *block-counter* ,*block-counter*)))))
2502
2503   (eval-when-compile
2504     (toplevel-compilation
2505      (ls-compile
2506       `(setq *literal-counter* ,*literal-counter*)))))
2507
2508
2509 ;;; Finally, we provide a couple of functions to easily bootstrap
2510 ;;; this. It just calls the compiler with this file as input.
2511
2512 #+common-lisp
2513 (progn
2514   (defun read-whole-file (filename)
2515     (with-open-file (in filename)
2516       (let ((seq (make-array (file-length in) :element-type 'character)))
2517         (read-sequence seq in)
2518         seq)))
2519
2520   (defun ls-compile-file (filename output)
2521     (let ((*compiling-file* t))
2522       (with-open-file (out output :direction :output :if-exists :supersede)
2523         (write-string (read-whole-file "prelude.js") out)
2524         (let* ((source (read-whole-file filename))
2525                (in (make-string-stream source)))
2526           (loop
2527              for x = (ls-read in)
2528              until (eq x *eof*)
2529              for compilation = (ls-compile-toplevel x)
2530              when (plusp (length compilation))
2531              do (write-string compilation out))))))
2532
2533   (defun bootstrap ()
2534     (setq *environment* (make-lexenv))
2535     (setq *literal-symbols* nil)
2536     (setq *variable-counter* 0
2537           *gensym-counter* 0
2538           *literal-counter* 0
2539           *block-counter* 0)
2540     (ls-compile-file "ecmalisp.lisp" "ecmalisp.js")))