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