8db7c46ed5287628fd02be8e49db6f369bdcc7f5
[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         (fargs '())
1934         (prelude ""))
1935     (dolist (x args)
1936       (if (numberp x)
1937           (push (integer-to-string x) fargs)
1938           (let ((v (code "x" (incf counter))))
1939             (push v fargs)
1940             (concatf prelude
1941               (code "var " v " = " (ls-compile x) ";" *newline*
1942                     "if (typeof " v " !== 'number') throw 'Not a number!';"
1943                     *newline*)))))
1944     (js!selfcall prelude (funcall function (reverse fargs)))))
1945
1946
1947 (defmacro variable-arity (args &body body)
1948   (unless (symbolp args)
1949     (error "Bad usage of VARIABLE-ARITY, you must pass a symbol"))
1950   `(variable-arity-call ,args
1951                         (lambda (,args)
1952                           (code "return " ,@body ";" *newline*))))
1953
1954 (defun num-op-num (x op y)
1955   (type-check (("x" "number" x) ("y" "number" y))
1956     (code "x" op "y")))
1957
1958 (define-raw-builtin + (&rest numbers)
1959   (if (null numbers)
1960       "0"
1961       (variable-arity numbers
1962         (join numbers "+"))))
1963
1964 (define-raw-builtin - (x &rest others)
1965   (let ((args (cons x others)))
1966     (variable-arity args
1967       (if (null others)
1968           (concat "-" (car args))
1969           (join args "-")))))
1970
1971 (define-raw-builtin * (&rest numbers)
1972   (if (null numbers)
1973       "1"
1974       (variable-arity numbers
1975         (join numbers "*"))))
1976
1977 (define-raw-builtin / (x &rest others)
1978   (let ((args (cons x others)))
1979     (variable-arity args
1980       (if (null others)
1981           (concat "1 /" (car args))
1982           (join args "/")))))
1983
1984 (define-builtin mod (x y) (num-op-num x "%" y))
1985
1986
1987 (defun comparison-conjuntion (vars op)
1988   (cond
1989     ((null (cdr vars))
1990      "true")
1991     ((null (cddr vars))
1992      (concat (car vars) op (cadr vars)))
1993     (t
1994      (concat (car vars) op (cadr vars)
1995              " && "
1996              (comparison-conjuntion (cdr vars) op)))))
1997
1998 (defmacro define-builtin-comparison (op sym)
1999   `(define-raw-builtin ,op (x &rest args)
2000      (let ((args (cons x args)))
2001        (variable-arity args
2002          (js!bool (comparison-conjuntion args ,sym))))))
2003
2004 (define-builtin-comparison > ">")
2005 (define-builtin-comparison < "<")
2006 (define-builtin-comparison >= ">=")
2007 (define-builtin-comparison <= "<=")
2008 (define-builtin-comparison = "==")
2009
2010 (define-builtin numberp (x)
2011   (js!bool (code "(typeof (" x ") == \"number\")")))
2012
2013 (define-builtin floor (x)
2014   (type-check (("x" "number" x))
2015     "Math.floor(x)"))
2016
2017 (define-builtin cons (x y)
2018   (code "({car: " x ", cdr: " y "})"))
2019
2020 (define-builtin consp (x)
2021   (js!bool
2022    (js!selfcall
2023      "var tmp = " x ";" *newline*
2024      "return (typeof tmp == 'object' && 'car' in tmp);" *newline*)))
2025
2026 (define-builtin car (x)
2027   (js!selfcall
2028     "var tmp = " x ";" *newline*
2029     "return tmp === " (ls-compile nil)
2030     "? " (ls-compile nil)
2031     ": tmp.car;" *newline*))
2032
2033 (define-builtin cdr (x)
2034   (js!selfcall
2035     "var tmp = " x ";" *newline*
2036     "return tmp === " (ls-compile nil) "? "
2037     (ls-compile nil)
2038     ": tmp.cdr;" *newline*))
2039
2040 (define-builtin rplaca (x new)
2041   (type-check (("x" "object" x))
2042     (code "(x.car = " new ", x)")))
2043
2044 (define-builtin rplacd (x new)
2045   (type-check (("x" "object" x))
2046     (code "(x.cdr = " new ", x)")))
2047
2048 (define-builtin symbolp (x)
2049   (js!bool
2050    (js!selfcall
2051      "var tmp = " x ";" *newline*
2052      "return (typeof tmp == 'object' && 'name' in tmp);" *newline*)))
2053
2054 (define-builtin make-symbol (name)
2055   (type-check (("name" "string" name))
2056     "({name: name})"))
2057
2058 (define-builtin symbol-name (x)
2059   (code "(" x ").name"))
2060
2061 (define-builtin set (symbol value)
2062   (code "(" symbol ").value = " value))
2063
2064 (define-builtin fset (symbol value)
2065   (code "(" symbol ").fvalue = " value))
2066
2067 (define-builtin boundp (x)
2068   (js!bool (code "(" x ".value !== undefined)")))
2069
2070 (define-builtin symbol-value (x)
2071   (js!selfcall
2072     "var symbol = " x ";" *newline*
2073     "var value = symbol.value;" *newline*
2074     "if (value === undefined) throw \"Variable `\" + symbol.name + \"' is unbound.\";" *newline*
2075     "return value;" *newline*))
2076
2077 (define-builtin symbol-function (x)
2078   (js!selfcall
2079     "var symbol = " x ";" *newline*
2080     "var func = symbol.fvalue;" *newline*
2081     "if (func === undefined) throw \"Function `\" + symbol.name + \"' is undefined.\";" *newline*
2082     "return func;" *newline*))
2083
2084 (define-builtin symbol-plist (x)
2085   (code "((" x ").plist || " (ls-compile nil) ")"))
2086
2087 (define-builtin lambda-code (x)
2088   (code "(" x ").toString()"))
2089
2090 (define-builtin eq    (x y) (js!bool (code "(" x " === " y ")")))
2091 (define-builtin equal (x y) (js!bool (code "(" x  " == " y ")")))
2092
2093 (define-builtin char-to-string (x)
2094   (type-check (("x" "number" x))
2095     "String.fromCharCode(x)"))
2096
2097 (define-builtin stringp (x)
2098   (js!bool (code "(typeof(" x ") == \"string\")")))
2099
2100 (define-builtin string-upcase (x)
2101   (type-check (("x" "string" x))
2102     "x.toUpperCase()"))
2103
2104 (define-builtin string-length (x)
2105   (type-check (("x" "string" x))
2106     "x.length"))
2107
2108 (define-raw-builtin slice (string a &optional b)
2109   (js!selfcall
2110     "var str = " (ls-compile string) ";" *newline*
2111     "var a = " (ls-compile a) ";" *newline*
2112     "var b;" *newline*
2113     (when b (code "b = " (ls-compile b) ";" *newline*))
2114     "return str.slice(a,b);" *newline*))
2115
2116 (define-builtin char (string index)
2117   (type-check (("string" "string" string)
2118                ("index" "number" index))
2119     "string.charCodeAt(index)"))
2120
2121 (define-builtin concat-two (string1 string2)
2122   (type-check (("string1" "string" string1)
2123                ("string2" "string" string2))
2124     "string1.concat(string2)"))
2125
2126 (define-raw-builtin funcall (func &rest args)
2127   (code "(" (ls-compile func) ")("
2128         (join (cons (if *multiple-value-p* "values" "pv")
2129                     (mapcar #'ls-compile args))
2130               ", ")
2131         ")"))
2132
2133 (define-raw-builtin apply (func &rest args)
2134   (if (null args)
2135       (code "(" (ls-compile func) ")()")
2136       (let ((args (butlast args))
2137             (last (car (last args))))
2138         (js!selfcall
2139           "var f = " (ls-compile func) ";" *newline*
2140           "var args = [" (join (cons (if *multiple-value-p* "values" "pv")
2141                                      (mapcar #'ls-compile args))
2142                                ", ")
2143           "];" *newline*
2144           "var tail = (" (ls-compile last) ");" *newline*
2145           "while (tail != " (ls-compile nil) "){" *newline*
2146           "    args.push(tail.car);" *newline*
2147           "    tail = tail.cdr;" *newline*
2148           "}" *newline*
2149           "return f.apply(this, args);" *newline*))))
2150
2151 (define-builtin js-eval (string)
2152   (type-check (("string" "string" string))
2153     (if *multiple-value-p*
2154         (js!selfcall
2155           "var v = eval.apply(window, [string]);" *newline*
2156           "if (typeof v !== 'object' || !('multiple-value' in v)){" *newline*
2157           (indent "v = [v];" *newline*
2158                   "v['multiple-value'] = true;" *newline*)
2159           "}" *newline*
2160           "return values.apply(this, v);" *newline*)
2161         "eval.apply(window, [string])")))
2162
2163 (define-builtin error (string)
2164   (js!selfcall "throw " string ";" *newline*))
2165
2166 (define-builtin new () "{}")
2167
2168 (define-builtin objectp (x)
2169   (js!bool (code "(typeof (" x ") === 'object')")))
2170
2171 (define-builtin oget (object key)
2172   (js!selfcall
2173     "var tmp = " "(" object ")[" key "];" *newline*
2174     "return tmp == undefined? " (ls-compile nil) ": tmp ;" *newline*))
2175
2176 (define-builtin oset (object key value)
2177   (code "((" object ")[" key "] = " value ")"))
2178
2179 (define-builtin in (key object)
2180   (js!bool (code "((" key ") in (" object "))")))
2181
2182 (define-builtin functionp (x)
2183   (js!bool (code "(typeof " x " == 'function')")))
2184
2185 (define-builtin write-string (x)
2186   (type-check (("x" "string" x))
2187     "lisp.write(x)"))
2188
2189 (define-builtin make-array (n)
2190   (js!selfcall
2191     "var r = [];" *newline*
2192     "for (var i = 0; i < " n "; i++)" *newline*
2193     (indent "r.push(" (ls-compile nil) ");" *newline*)
2194     "return r;" *newline*))
2195
2196 (define-builtin arrayp (x)
2197   (js!bool
2198    (js!selfcall
2199      "var x = " x ";" *newline*
2200      "return typeof x === 'object' && 'length' in x;")))
2201
2202 (define-builtin aref (array n)
2203   (js!selfcall
2204     "var x = " "(" array ")[" n "];" *newline*
2205     "if (x === undefined) throw 'Out of range';" *newline*
2206     "return x;" *newline*))
2207
2208 (define-builtin aset (array n value)
2209   (js!selfcall
2210     "var x = " array ";" *newline*
2211     "var i = " n ";" *newline*
2212     "if (i < 0 || i >= x.length) throw 'Out of range';" *newline*
2213     "return x[i] = " value ";" *newline*))
2214
2215 (define-builtin get-unix-time ()
2216   (code "(Math.round(new Date() / 1000))"))
2217
2218 (define-builtin values-array (array)
2219   (if *multiple-value-p*
2220       (code "values.apply(this, " array ")")
2221       (code "pv.apply(this, " array ")")))
2222
2223 (define-raw-builtin values (&rest args)
2224   (if *multiple-value-p*
2225       (code "values(" (join (mapcar #'ls-compile args) ", ") ")")
2226       (code "pv(" (join (mapcar #'ls-compile args) ", ") ")")))
2227
2228 (defun macro (x)
2229   (and (symbolp x)
2230        (let ((b (lookup-in-lexenv x *environment* 'function)))
2231          (and (eq (binding-type b) 'macro)
2232               b))))
2233
2234 (defun ls-macroexpand-1 (form)
2235   (let ((macro-binding (macro (car form))))
2236     (if macro-binding
2237         (let ((expander (binding-value macro-binding)))
2238           (when (listp expander)
2239             (let ((compiled (eval expander)))
2240               ;; The list representation are useful while
2241               ;; bootstrapping, as we can dump the definition of the
2242               ;; macros easily, but they are slow because we have to
2243               ;; evaluate them and compile them now and again. So, let
2244               ;; us replace the list representation version of the
2245               ;; function with the compiled one.
2246               ;;
2247               #+ecmalisp (set-binding-value macro-binding compiled)
2248               (setq expander compiled)))
2249           (apply expander (cdr form)))
2250         form)))
2251
2252 (defun compile-funcall (function args)
2253   (let* ((values-funcs (if *multiple-value-p* "values" "pv"))
2254          (arglist (concat "(" (join (cons values-funcs (mapcar #'ls-compile args)) ", ") ")")))
2255     (cond
2256       ((translate-function function)
2257        (concat (translate-function function) arglist))
2258       ((and (symbolp function)
2259             #+ecmalisp (eq (symbol-package function) (find-package "COMMON-LISP"))
2260             #+common-lisp t)
2261        (code (ls-compile `',function) ".fvalue" arglist))
2262       (t
2263        (code (ls-compile `#',function) arglist)))))
2264
2265 (defun ls-compile-block (sexps &optional return-last-p)
2266   (if return-last-p
2267       (code (ls-compile-block (butlast sexps))
2268             "return " (ls-compile (car (last sexps)) *multiple-value-p*) ";")
2269       (join-trailing
2270        (remove-if #'null-or-empty-p (mapcar #'ls-compile sexps))
2271        (concat ";" *newline*))))
2272
2273 (defun ls-compile (sexp &optional multiple-value-p)
2274   (let ((*multiple-value-p* multiple-value-p))
2275     (cond
2276       ((symbolp sexp)
2277        (let ((b (lookup-in-lexenv sexp *environment* 'variable)))
2278          (cond
2279            ((and b (not (member 'special (binding-declarations b))))
2280             (binding-value b))
2281            ((or (keywordp sexp)
2282                 (member 'constant (binding-declarations b)))
2283             (code (ls-compile `',sexp) ".value"))
2284            (t
2285             (ls-compile `(symbol-value ',sexp))))))
2286       ((integerp sexp) (integer-to-string sexp))
2287       ((stringp sexp) (code "\"" (escape-string sexp) "\""))
2288       ((arrayp sexp) (literal sexp))
2289       ((listp sexp)
2290        (let ((name (car sexp))
2291              (args (cdr sexp)))
2292          (cond
2293            ;; Special forms
2294            ((assoc name *compilations*)
2295             (let ((comp (second (assoc name *compilations*))))
2296               (apply comp args)))
2297            ;; Built-in functions
2298            ((and (assoc name *builtins*)
2299                  (not (claimp name 'function 'notinline)))
2300             (let ((comp (second (assoc name *builtins*))))
2301               (apply comp args)))
2302            (t
2303             (if (macro name)
2304                 (ls-compile (ls-macroexpand-1 sexp) multiple-value-p)
2305                 (compile-funcall name args))))))
2306       (t
2307        (error "How should I compile this?")))))
2308
2309 (defun ls-compile-toplevel (sexp &optional multiple-value-p)
2310   (let ((*toplevel-compilations* nil))
2311     (cond
2312       ((and (consp sexp) (eq (car sexp) 'progn))
2313        (let ((subs (mapcar (lambda (s)
2314                              (ls-compile-toplevel s t))
2315                            (cdr sexp))))
2316          (join (remove-if #'null-or-empty-p subs))))
2317       (t
2318        (let ((code (ls-compile sexp multiple-value-p)))
2319          (code (join-trailing (get-toplevel-compilations)
2320                               (code ";" *newline*))
2321                (when code
2322                  (code code ";" *newline*))))))))
2323
2324
2325 ;;; Once we have the compiler, we define the runtime environment and
2326 ;;; interactive development (eval), which works calling the compiler
2327 ;;; and evaluating the Javascript result globally.
2328
2329 #+ecmalisp
2330 (progn
2331   (defun eval (x)
2332     (js-eval (ls-compile-toplevel x t)))
2333
2334   (export '(&rest &key &optional &body * *gensym-counter* *package* +
2335             - / 1+ 1- < <= = = > >= and append apply aref arrayp assoc
2336             atom block boundp boundp butlast caar cadddr caddr cadr
2337             car car case catch cdar cdddr cddr cdr cdr char char-code
2338             char= code-char cond cons consp constantly copy-list decf
2339             declaim defconstant defparameter defun defmacro defvar
2340             digit-char digit-char-p disassemble do do* documentation
2341             dolist dotimes ecase eq eql equal error eval every export
2342             fdefinition find-package find-symbol first flet fourth
2343             fset funcall function functionp gensym get-universal-time
2344             go identity if in-package incf integerp integerp intern
2345             keywordp labels lambda last length let let*
2346             list-all-packages list listp make-array make-package
2347             make-symbol mapcar member minusp mod multiple-value-bind
2348             multiple-value-call multiple-value-list
2349             multiple-value-prog1 nil not nth nthcdr null numberp or
2350             package-name package-use-list packagep parse-integer plusp
2351             prin1-to-string print proclaim prog1 prog2 progn psetq
2352             push quote remove remove-if remove-if-not return
2353             return-from revappend reverse rplaca rplacd second set
2354             setq some string-upcase string string= stringp subseq
2355             symbol-function symbol-name symbol-package symbol-plist
2356             symbol-value symbolp t tagbody third throw truncate unless
2357             unwind-protect values values-list variable warn when
2358             write-line write-string zerop))
2359
2360   (setq *package* *user-package*)
2361
2362   (js-eval "var lisp")
2363   (js-vset "lisp" (new))
2364   (js-vset "lisp.read" #'ls-read-from-string)
2365   (js-vset "lisp.print" #'prin1-to-string)
2366   (js-vset "lisp.eval" #'eval)
2367   (js-vset "lisp.compile" (lambda (s) (ls-compile-toplevel s t)))
2368   (js-vset "lisp.evalString" (lambda (str) (eval (ls-read-from-string str))))
2369   (js-vset "lisp.compileString" (lambda (str) (ls-compile-toplevel (ls-read-from-string str) t)))
2370
2371   ;; Set the initial global environment to be equal to the host global
2372   ;; environment at this point of the compilation.
2373   (eval-when-compile
2374     (toplevel-compilation
2375      (ls-compile
2376       `(progn
2377          ,@(mapcar (lambda (s) `(%intern-symbol (js-vref ,(cdr s))))
2378                    *literal-symbols*)
2379          (setq *literal-symbols* ',*literal-symbols*)
2380          (setq *environment* ',*environment*)
2381          (setq *variable-counter* ,*variable-counter*)
2382          (setq *gensym-counter* ,*gensym-counter*)
2383          (setq *block-counter* ,*block-counter*)))))
2384
2385   (eval-when-compile
2386     (toplevel-compilation
2387      (ls-compile
2388       `(setq *literal-counter* ,*literal-counter*)))))
2389
2390
2391 ;;; Finally, we provide a couple of functions to easily bootstrap
2392 ;;; this. It just calls the compiler with this file as input.
2393
2394 #+common-lisp
2395 (progn
2396   (defun read-whole-file (filename)
2397     (with-open-file (in filename)
2398       (let ((seq (make-array (file-length in) :element-type 'character)))
2399         (read-sequence seq in)
2400         seq)))
2401
2402   (defun ls-compile-file (filename output)
2403     (let ((*compiling-file* t))
2404       (with-open-file (out output :direction :output :if-exists :supersede)
2405         (write-string (read-whole-file "prelude.js") out)
2406         (let* ((source (read-whole-file filename))
2407                (in (make-string-stream source)))
2408           (loop
2409              for x = (ls-read in)
2410              until (eq x *eof*)
2411              for compilation = (ls-compile-toplevel x)
2412              when (plusp (length compilation))
2413              do (write-string compilation out))))))
2414
2415   (defun bootstrap ()
2416     (setq *environment* (make-lexenv))
2417     (setq *literal-symbols* nil)
2418     (setq *variable-counter* 0
2419           *gensym-counter* 0
2420           *literal-counter* 0
2421           *block-counter* 0)
2422     (ls-compile-file "ecmalisp.lisp" "ecmalisp.js")))