X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=ecmalisp.lisp;h=07fe2f0cfdf67400c85cb74b2af5ca01f0014c58;hb=42a1f2ea0fc0080c3ff274442e5a12ad6c8c091e;hp=3eec9dd67b3f8b7bc5f70fdcd3fcce62242df701;hpb=d91eeceff8f1d679c935ec473115f72c9b3d6ec7;p=jscl.git diff --git a/ecmalisp.lisp b/ecmalisp.lisp index 3eec9dd..07fe2f0 100644 --- a/ecmalisp.lisp +++ b/ecmalisp.lisp @@ -24,8 +24,6 @@ #+ecmalisp (progn - - 'defmacro (eval-when-compile (%compile-defmacro 'defmacro '(lambda (name args &rest body) @@ -40,28 +38,42 @@ ,@body))) ',name)))) + (setq nil 'nil) + (setq t 't) + + (defmacro when (condition &body body) + `(if ,condition (progn ,@body) nil)) + + (defmacro unless (condition &body body) + `(if ,condition nil (progn ,@body))) + (defmacro defvar (name value) `(progn + (unless (boundp ',name) + (setq ,name ,value)) + ',name)) + + (defmacro defparameter (name value) + `(progn (setq ,name ,value) ',name)) - (defmacro named-lambda (name args &body body) + (defmacro named-lambda (name args &rest body) (let ((x (gensym "FN"))) `(let ((,x (lambda ,args ,@body))) (oset ,x "fname" ,name) ,x))) - (defmacro defun (name args &body body) + (defmacro defun (name args &rest body) `(progn - (fset ',name (named-lambda ,(symbol-name name) ,args - (block ,name ,@body))) + (fset ',name + (named-lambda ,(symbol-name name) + ,args + (block ,name ,@body))) ',name)) (defvar *package* (new)) - (defvar nil 'nil) - (defvar t 't) - (defun null (x) (eq x nil)) @@ -87,6 +99,9 @@ (setq *gensym-counter* (+ *gensym-counter* 1)) (make-symbol (concat-two prefix (integer-to-string *gensym-counter*)))) + (defun boundp (x) + (boundp x)) + ;; Basic functions (defun = (x y) (= x y)) (defun + (x y) (+ x y)) @@ -133,12 +148,6 @@ (defmacro push (x place) `(setq ,place (cons ,x ,place))) - (defmacro when (condition &body body) - `(if ,condition (progn ,@body) nil)) - - (defmacro unless (condition &body body) - `(if ,condition nil (progn ,@body))) - (defmacro dolist (iter &body body) (let ((var (first iter)) (g!list (gensym))) @@ -416,7 +425,20 @@ (car alist)) (defun string= (s1 s2) - (equal s1 s2))) + (equal s1 s2)) + + (defun fdefinition (x) + (cond + ((functionp x) + x) + ((symbolp x) + (symbol-function x)) + (t + (error "Invalid function")))) + + (defun disassemble (function) + (write-line (lambda-code (fdefinition function))) + nil)) ;;; The compiler offers some primitives and special forms which are @@ -798,6 +820,7 @@ (reverse (remove-if #'null-or-empty-p *toplevel-compilations*))) (defun %compile-defmacro (name lambda) + (toplevel-compilation (ls-compile `',name)) (push-to-lexenv (make-binding name 'macro lambda t) *environment* 'function)) (defvar *compilations* nil) @@ -957,7 +980,8 @@ ((symbolp sexp) (or (cdr (assoc sexp *literal-symbols*)) (let ((v (genlit)) - (s (concat "{name: \"" (escape-string (symbol-name sexp)) "\"}"))) + (s #+common-lisp (concat "{name: \"" (escape-string (symbol-name sexp)) "\"}") + #+ecmalisp (ls-compile `(intern ,(symbol-name sexp))))) (push (cons sexp v) *literal-symbols*) (toplevel-compilation (concat "var " v " = " s)) v))) @@ -1004,20 +1028,55 @@ (ls-compile-block (butlast body) env) "return " (ls-compile (car (last body)) env) ";" *newline*)) + +(defun dynamic-binding-wrapper (bindings body) + (if (null bindings) + body + (concat + "try {" *newline* + (indent + "var tmp;" *newline* + (join + (mapcar (lambda (b) + (let ((s (ls-compile `(quote ,(car b))))) + (concat "tmp = " s ".value;" *newline* + s ".value = " (cdr b) ";" *newline* + (cdr b) " = tmp;" *newline*))) + bindings)) + body) + "}" *newline* + "finally {" *newline* + (indent + (join-trailing + (mapcar (lambda (b) + (let ((s (ls-compile `(quote ,(car b))))) + (concat s ".value" " = " (cdr b)))) + bindings) + (concat ";" *newline*))) + "}" *newline*))) + + (define-compilation let (bindings &rest body) (let ((bindings (mapcar #'ensure-list bindings))) (let ((variables (mapcar #'first bindings)) (values (mapcar #'second bindings))) - (let ((new-env (extend-local-env variables env))) + (let ((new-env (extend-local-env (remove-if #'boundp variables) env)) + (dynamic-bindings)) (concat "(function(" (join (mapcar (lambda (x) - (translate-variable x new-env)) + (if (boundp x) + (let ((v (gvarname x))) + (push (cons x v) dynamic-bindings) + v) + (translate-variable x new-env))) variables) ",") "){" *newline* - (indent (ls-compile-block (butlast body) new-env) - "return " (ls-compile (car (last body)) new-env) - ";" *newline*) + (let ((body + (concat (ls-compile-block (butlast body) new-env) + "return " (ls-compile (car (last body)) new-env) + ";" *newline*))) + (indent (dynamic-binding-wrapper dynamic-bindings body))) "})(" (join (mapcar (lambda (x) (ls-compile x env)) values) ",") @@ -1200,9 +1259,10 @@ ;;; Primitives (defmacro define-builtin (name args &body body) - `(define-compilation ,name ,args - (let ,(mapcar (lambda (arg) `(,arg (ls-compile ,arg env))) args) - ,@body))) + `(progn + (define-compilation ,name ,args + (let ,(mapcar (lambda (arg) `(,arg (ls-compile ,arg env))) args) + ,@body)))) ;;; DECLS is a list of (JSVARNAME TYPE LISPFORM) declarations. (defmacro type-check (decls &body body) @@ -1290,10 +1350,13 @@ (concat "(" x ").name")) (define-builtin set (symbol value) - (concat "(" symbol ").value =" value)) + (concat "(" symbol ").value = " value)) (define-builtin fset (symbol value) - (concat "(" symbol ").function =" value)) + (concat "(" symbol ").function = " value)) + +(define-builtin boundp (x) + (js!bool (concat "(" x ".value !== undefined)"))) (define-builtin symbol-value (x) (js!selfcall @@ -1312,6 +1375,9 @@ (define-builtin symbol-plist (x) (concat "((" x ").plist || " (ls-compile nil) ")")) +(define-builtin lambda-code (x) + (concat "(" x ").toString()")) + (define-builtin eq (x y) (js!bool (concat "(" x " === " y ")"))) (define-builtin equal (x y) (js!bool (concat "(" x " == " y ")"))) @@ -1441,19 +1507,18 @@ (compile-funcall (car sexp) (cdr sexp) env)))))) (defun ls-compile-toplevel (sexp) - (setq *toplevel-compilations* nil) - (cond - ((and (consp sexp) (eq (car sexp) 'progn)) - (let ((subs (mapcar #'ls-compile-toplevel (cdr sexp)))) - (join (remove-if #'null-or-empty-p subs)))) - (t - (let ((code (ls-compile sexp))) - (prog1 - (concat (join-trailing (get-toplevel-compilations) (concat ";" *newline*)) - (if code - (concat code ";" *newline*) - "")) - (setq *toplevel-compilations* nil)))))) + (let ((*toplevel-compilations* nil)) + (cond + ((and (consp sexp) (eq (car sexp) 'progn)) + (let ((subs (mapcar #'ls-compile-toplevel (cdr sexp)))) + (join (remove-if #'null-or-empty-p subs)))) + (t + (let ((code (ls-compile sexp))) + (concat (join-trailing (get-toplevel-compilations) + (concat ";" *newline*)) + (if code + (concat code ";" *newline*) + ""))))))) ;;; Once we have the compiler, we define the runtime environment and