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