X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=ecmalisp.lisp;h=cb89dfc00a43213f12029305a49d9f4663ddfb77;hb=04eb2ffe0a6043e3d1f979088f4ca90463b07b79;hp=b5606f72a82fe934effcedabf3b3751f42d34f1d;hpb=405ed6112fbcd4790ed61bcaa2395e5edf8a8a58;p=jscl.git diff --git a/ecmalisp.lisp b/ecmalisp.lisp index b5606f7..cb89dfc 100644 --- a/ecmalisp.lisp +++ b/ecmalisp.lisp @@ -23,38 +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* @@ -1237,13 +1257,14 @@ function mv(){ "") ;; Body (let ((*multiple-value-p* t)) (ls-compile-block body t))) - *newline* "})")))) (defun setq-pair (var val) (let ((b (lookup-in-lexenv var *environment* 'variable))) - (if (eq (binding-type b) 'lexical-variable) + (if (and (eq (binding-type b) 'variable) + (not (member 'special (binding-declarations b))) + (not (member 'constant (binding-declarations b)))) (concat (binding-value b) " = " (ls-compile val)) (ls-compile `(set ',var ,val))))) @@ -1310,13 +1331,19 @@ function mv(){ (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) ", ") "]"))) @@ -1339,20 +1366,26 @@ function mv(){ (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)) @@ -1407,7 +1440,7 @@ function mv(){ ;;; Return the code to initialize BINDING, and push it extending the -;;; current lexical environment if the variable is special. +;;; current lexical environment if the variable is not special. (defun let*-initialize-value (binding) (let ((var (first binding)) (value (second binding))) @@ -1456,52 +1489,68 @@ function mv(){ (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.'" "})")) @@ -1588,9 +1637,11 @@ function mv(){ "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) @@ -1600,7 +1651,13 @@ function mv(){ "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*)) @@ -1788,13 +1845,13 @@ function mv(){ (ls-compile nil) ": tmp.cdr;" *newline*)) -(define-builtin setcar (x new) +(define-builtin rplaca (x new) (type-check (("x" "object" x)) - (concat "(x.car = " new ")"))) + (concat "(x.car = " new ", x)"))) -(define-builtin setcdr (x new) +(define-builtin rplacd (x new) (type-check (("x" "object" x)) - (concat "(x.cdr = " new ")"))) + (concat "(x.cdr = " new ", x)"))) (define-builtin symbolp (x) (js!bool @@ -2005,7 +2062,8 @@ function mv(){ (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)) ", ") @@ -2018,7 +2076,7 @@ function mv(){ (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*)))) @@ -2054,7 +2112,7 @@ function mv(){ (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?"))))) @@ -2086,28 +2144,25 @@ function mv(){ (js-eval (ls-compile-toplevel x t))) (export '(&rest &optional &body * *gensym-counter* *package* + - / 1+ 1- < <= = - = > >= 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-bind - multiple-value-call multiple-value-list 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)) + = > >= 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 do do* 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 rplaca rplacd 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*) @@ -2152,19 +2207,17 @@ function mv(){ 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))