X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=ecmalisp.lisp;h=d8806141993b254c4e1f0070e8e3d34d91dbc051;hb=2d5ef7b50ce3a117e48eaa5bf04e6735a746b3a8;hp=feb80481f84d5712eb5a5fa72fd53277e479d087;hpb=95ff3b61c01f76e6564554a6c83fa8d2c1d9a581;p=jscl.git diff --git a/ecmalisp.lisp b/ecmalisp.lisp index feb8048..d880614 100644 --- a/ecmalisp.lisp +++ b/ecmalisp.lisp @@ -23,27 +23,20 @@ ;;; language to the compiler to be able to run. #+ecmalisp -(js-eval "function pv (x) { return x; }") - -#+ecmalisp -(js-eval "function mv(){ var r = []; r['multiple-value'] = true; for (var i=0; i " - (integer-to-string (+ 1 n-required-arguments n-optional-arguments)) - ") throw 'too many arguments';" *newline*) - "") + ;; Check number of arguments + (lambda-check-argument-count n-required-arguments + n-optional-arguments + rest-argument) ;; Optional arguments (if optional-arguments (concat "switch(arguments.length-1){" *newline* @@ -1215,7 +1234,6 @@ "") ;; Body (let ((*multiple-value-p* t)) (ls-compile-block body t))) - *newline* "})")))) @@ -1288,13 +1306,19 @@ (toplevel-compilation (concat "var " v " = " s)) v))) ((consp sexp) - (let ((c (concat "{car: " (literal (car sexp) t) ", " - "cdr: " (literal (cdr sexp) t) "}"))) + (let* ((head (butlast sexp)) + (tail (last sexp)) + (c (concat "QIList(" + (join-trailing (mapcar (lambda (x) (literal x t)) head) ",") + (literal (car tail) t) + "," + (literal (cdr tail) t) + ")"))) (if recursive c (let ((v (genlit))) - (toplevel-compilation (concat "var " v " = " c)) - v)))) + (toplevel-compilation (concat "var " v " = " c)) + v)))) ((arrayp sexp) (let ((elements (vector-to-list sexp))) (let ((c (concat "[" (join (mapcar #'literal elements) ", ") "]"))) @@ -1317,20 +1341,26 @@ (define-compilation function (x) (cond ((and (listp x) (eq (car x) 'lambda)) - (ls-compile x)) + (compile-lambda (cadr x) (cddr x))) ((symbolp x) (ls-compile `(symbol-function ',x))))) +(defvar *compiling-file* nil) (define-compilation eval-when-compile (&rest body) - (eval (cons 'progn body)) - nil) + (if *compiling-file* + (progn + (eval (cons 'progn body)) + nil) + (ls-compile `(progn ,@body)))) (defmacro define-transformation (name args form) `(define-compilation ,name ,args (ls-compile ,form))) (define-compilation progn (&rest body) - (js!selfcall (ls-compile-block body t))) + (if (null (cdr body)) + (ls-compile (car body) *multiple-value-p*) + (js!selfcall (ls-compile-block body t)))) (defun special-variable-p (x) (and (claimp x 'variable 'special) t)) @@ -1434,52 +1464,68 @@ (defvar *block-counter* 0) (define-compilation block (name &rest body) - (let ((tr (integer-to-string (incf *block-counter*)))) - (let ((b (make-binding name 'block tr))) - (js!selfcall - "try {" *newline* - (let ((*environment* (extend-lexenv (list b) *environment* 'block))) - (indent "return " (ls-compile `(progn ,@body) *multiple-value-p*) ";" *newline*)) - "}" *newline* - "catch (cf){" *newline* - " if (cf.type == 'block' && cf.id == " tr ")" *newline* - " return cf.value;" *newline* - " else" *newline* - " throw cf;" *newline* - "}" *newline*)))) + (let* ((tr (integer-to-string (incf *block-counter*))) + (b (make-binding name 'block tr))) + (when *multiple-value-p* + (push-binding-declaration 'multiple-value b)) + (let* ((*environment* (extend-lexenv (list b) *environment* 'block)) + (cbody (ls-compile-block body t))) + (if (member 'used (binding-declarations b)) + (js!selfcall + "try {" *newline* + (indent cbody) + "}" *newline* + "catch (cf){" *newline* + " if (cf.type == 'block' && cf.id == " tr ")" *newline* + (if *multiple-value-p* + " return values.apply(this, forcemv(cf.values));" + " return cf.values;") + *newline* + " else" *newline* + " throw cf;" *newline* + "}" *newline*) + (js!selfcall cbody))))) (define-compilation return-from (name &optional value) - (let ((b (lookup-in-lexenv name *environment* 'block))) - (if b - (js!selfcall - "throw ({" - "type: 'block', " - "id: " (binding-value b) ", " - "value: " (ls-compile value) ", " - "message: 'Return from unknown block " (symbol-name name) ".'" - "})") - (error (concat "Unknown block `" (symbol-name name) "'."))))) + (let* ((b (lookup-in-lexenv name *environment* 'block)) + (multiple-value-p (member 'multiple-value (binding-declarations b)))) + (when (null b) + (error (concat "Unknown block `" (symbol-name name) "'."))) + (push-binding-declaration 'used b) + (js!selfcall + (if multiple-value-p + (concat "var values = mv;" *newline*) + "") + "throw ({" + "type: 'block', " + "id: " (binding-value b) ", " + "values: " (ls-compile value multiple-value-p) ", " + "message: 'Return from unknown block " (symbol-name name) ".'" + "})"))) (define-compilation catch (id &rest body) (js!selfcall "var id = " (ls-compile id) ";" *newline* "try {" *newline* - (indent "return " (ls-compile `(progn ,@body)) - ";" *newline*) + (indent (ls-compile-block body t)) *newline* "}" *newline* "catch (cf){" *newline* " if (cf.type == 'catch' && cf.id == id)" *newline* - " return cf.value;" *newline* + (if *multiple-value-p* + " return values.apply(this, forcemv(cf.values));" + " return pv.apply(this, forcemv(cf.values));") + *newline* " else" *newline* " throw cf;" *newline* "}" *newline*)) (define-compilation throw (id value) (js!selfcall + "var values = mv;" *newline* "throw ({" "type: 'catch', " "id: " (ls-compile id) ", " - "value: " (ls-compile value) ", " + "values: " (ls-compile value t) ", " "message: 'Throw uncatched.'" "})")) @@ -1566,9 +1612,11 @@ "return ret;" *newline*)) (define-compilation multiple-value-call (func-form &rest forms) - (let ((func (ls-compile func-form))) + (js!selfcall + "var func = " (ls-compile func-form) ";" *newline* + "var args = [" (if *multiple-value-p* "values" "pv") "];" *newline* + "return " (js!selfcall - "var args = [values];" *newline* "var values = mv;" *newline* "var vs;" *newline* (mapconcat (lambda (form) @@ -1578,7 +1626,13 @@ "else" *newline* (indent "args.push(vs);" *newline*))) forms) - "return (" func ").apply(window, args);" *newline*))) + "return func.apply(window, args);" *newline*) ";" *newline*)) + +(define-compilation multiple-value-prog1 (first-form &rest forms) + (js!selfcall + "var args = " (ls-compile first-form *multiple-value-p*) ";" *newline* + (ls-compile-block forms) + "return args;" *newline*)) @@ -1856,7 +1910,8 @@ (define-raw-builtin funcall (func &rest args) (concat "(" (ls-compile func) ")(" - (join (cons "pv" (mapcar #'ls-compile args)) + (join (cons (if *multiple-value-p* "values" "pv") + (mapcar #'ls-compile args)) ", ") ")")) @@ -1867,7 +1922,8 @@ (last (car (last args)))) (js!selfcall "var f = " (ls-compile func) ";" *newline* - "var args = [" (join (cons "pv" (mapcar #'ls-compile args)) + "var args = [" (join (cons (if *multiple-value-p* "values" "pv") + (mapcar #'ls-compile args)) ", ") "];" *newline* "var tail = (" (ls-compile last) ");" *newline* @@ -1881,7 +1937,7 @@ (type-check (("string" "string" string)) (if *multiple-value-p* (js!selfcall - "var v = eval.apply(window, [string]));" + "var v = eval.apply(window, [string]);" *newline* "if (typeof v !== 'object' || !('multiple-value' in v)){" *newline* (indent "v = [v];" *newline* "v['multiple-value'] = true;" *newline*) @@ -1981,7 +2037,8 @@ (defun compile-funcall (function args) (let ((values-funcs (if *multiple-value-p* "values" "pv"))) (if (and (symbolp function) - (claimp function 'function 'non-overridable)) + #+ecmalisp (eq (symbol-package function) (find-package "COMMON-LISP")) + #+common-lisp t) (concat (ls-compile `',function) ".fvalue(" (join (cons values-funcs (mapcar #'ls-compile args)) ", ") @@ -1994,7 +2051,7 @@ (defun ls-compile-block (sexps &optional return-last-p) (if return-last-p (concat (ls-compile-block (butlast sexps)) - "return "(ls-compile (car (last sexps)) *multiple-value-p*) ";") + "return " (ls-compile (car (last sexps)) *multiple-value-p*) ";") (join-trailing (remove-if #'null-or-empty-p (mapcar #'ls-compile sexps)) (concat ";" *newline*)))) @@ -2030,7 +2087,7 @@ (apply comp args))) (t (if (macro name) - (ls-compile (ls-macroexpand-1 sexp)) + (ls-compile (ls-macroexpand-1 sexp) multiple-value-p) (compile-funcall name args)))))) (t (error "How should I compile this?"))))) @@ -2039,7 +2096,9 @@ (let ((*toplevel-compilations* nil)) (cond ((and (consp sexp) (eq (car sexp) 'progn)) - (let ((subs (mapcar #'ls-compile-toplevel (cdr sexp)))) + (let ((subs (mapcar (lambda (s) + (ls-compile-toplevel s t)) + (cdr sexp)))) (join (remove-if #'null-or-empty-p subs)))) (t (let ((code (ls-compile sexp multiple-value-p))) @@ -2063,20 +2122,22 @@ = > >= and append apply aref arrayp aset assoc atom block boundp boundp butlast caar cadddr caddr cadr car car case catch cdar cdddr cddr cdr cdr char char-code char= code-char cond cons consp copy-list - decf declaim defparameter defun defmacro defvar digit-char-p disassemble - documentation dolist dotimes ecase eq eql equal error eval every - export fdefinition find-package find-symbol first fourth fset funcall - function functionp gensym get-universal-time go identity if in-package - incf integerp integerp intern keywordp lambda last length let let* - list-all-packages list listp make-array make-package make-symbol - mapcar member minusp mod multiple-value-call nil not nth nthcdr null - numberp or package-name package-use-list packagep plusp prin1-to-string - print proclaim prog1 prog2 progn psetq push quote remove remove-if - remove-if-not return return-from revappend reverse second set setq - some string-upcase string string= stringp subseq symbol-function - symbol-name symbol-package symbol-plist symbol-value symbolp t tagbody - third throw truncate unless unwind-protect values values-list variable - warn when write-line write-string zerop)) + decf declaim defparameter defun defmacro defvar digit-char-p + disassemble documentation dolist dotimes ecase eq eql equal error eval + every export fdefinition find-package find-symbol first fourth fset + funcall function functionp gensym get-universal-time go identity if + in-package incf integerp integerp intern keywordp lambda last length + let let* list-all-packages list listp make-array make-package + make-symbol mapcar member minusp mod multiple-value-bind + multiple-value-call multiple-value-list multiple-value-prog1 nil not + nth nthcdr null numberp or package-name package-use-list packagep + plusp prin1-to-string print proclaim prog1 prog2 progn psetq push + quote remove remove-if remove-if-not return return-from revappend + reverse second set setq some string-upcase string string= stringp + subseq symbol-function symbol-name symbol-package symbol-plist + symbol-value symbolp t tagbody third throw truncate unless + unwind-protect values values-list variable warn when write-line + write-string zerop)) (setq *package* *user-package*) @@ -2085,9 +2146,9 @@ (js-vset "lisp.read" #'ls-read-from-string) (js-vset "lisp.print" #'prin1-to-string) (js-vset "lisp.eval" #'eval) - (js-vset "lisp.compile" #'ls-compile-toplevel) + (js-vset "lisp.compile" (lambda (s) (ls-compile-toplevel s t))) (js-vset "lisp.evalString" (lambda (str) (eval (ls-read-from-string str)))) - (js-vset "lisp.compileString" (lambda (str) (ls-compile-toplevel (ls-read-from-string str)))) + (js-vset "lisp.compileString" (lambda (str) (ls-compile-toplevel (ls-read-from-string str) t))) ;; Set the initial global environment to be equal to the host global ;; environment at this point of the compilation. @@ -2121,19 +2182,17 @@ seq))) (defun ls-compile-file (filename output) - (setq *compilation-unit-checks* nil) - (with-open-file (out output :direction :output :if-exists :supersede) - (let* ((source (read-whole-file filename)) - (in (make-string-stream source))) - (loop - for x = (ls-read in) - until (eq x *eof*) - for compilation = (ls-compile-toplevel x) - when (plusp (length compilation)) - do (write-string compilation out)) - (dolist (check *compilation-unit-checks*) - (funcall check)) - (setq *compilation-unit-checks* nil)))) + (let ((*compiling-file* t)) + (with-open-file (out output :direction :output :if-exists :supersede) + (write-string (read-whole-file "prelude.js") out) + (let* ((source (read-whole-file filename)) + (in (make-string-stream source))) + (loop + for x = (ls-read in) + until (eq x *eof*) + for compilation = (ls-compile-toplevel x) + when (plusp (length compilation)) + do (write-string compilation out)))))) (defun bootstrap () (setq *environment* (make-lexenv))