-(in-package :parenscript)
+(in-package "PARENSCRIPT")
;;; reserved symbols/literals
(gethash name *ps-special-forms*))
(defmacro define-ps-special-form (name lambda-list &rest body)
- "Define a special form NAME. The first argument given to the special
-form is a keyword indicating whether the form is expected to produce
-an :expression or a :statement. The resulting Parenscript language
-types are appended to the ongoing javascript compilation."
- (let ((arglist (gensym "ps-arglist-")))
+ "Define a special form NAME. The first argument (an anaphor called
+'expecting' automatically added to the arglist) to the special form is
+a keyword indicating whether the form is expected to produce
+an :expression or a :statement."
+ (let ((args (gensym "ps-arglist-")))
`(setf (gethash ',name *ps-special-forms*)
- (lambda (&rest ,arglist)
- (destructuring-bind ,lambda-list
- ,arglist
+ (lambda (&rest ,args)
+ (destructuring-bind ,(cons 'expecting lambda-list)
+ ,args
+ (declare (ignorable expecting))
,@body)))))
(defun undefine-ps-special-form (name)
',name))
(defmacro define-ps-symbol-macro (symbol expansion)
- `(progn (undefine-ps-special-form ',symbol)
- (setf (get-macro-spec ',symbol *ps-macro-toplevel*) (cons t (lambda () ',expansion)))
- ',symbol))
+ (let ((x (gensym)))
+ `(progn (undefine-ps-special-form ',symbol)
+ (setf (get-macro-spec ',symbol *ps-macro-toplevel*) (cons t (lambda (,x) (declare (ignore ,x)) ',expansion)))
+ ',symbol)))
(defun import-macros-from-lisp (&rest names)
"Import the named Lisp macros into the ParenScript macro
"Recursively macroexpands ParenScript macros and symbol-macros in
the given ParenScript form. Returns two values: the expanded form, and
whether any expansion was performed on the form or not."
- (if (consp form)
- (let ((op (car form))
- (args (cdr form)))
- (cond ((equal op 'quote) (values (if (equalp '(nil) args) nil form) ; leave quotes alone, unless it's a quoted nil
- nil))
- ((ps-macro-p op) (values (ps-macroexpand (funcall (lookup-macro-expansion-function op) form)) t))
- (t (values form nil))))
- (cond ((ps-symbol-macro-p form) (values (ps-macroexpand (funcall (lookup-macro-expansion-function form))) t))
- (t (values form nil)))))
+ (let ((macro-function (cond ((ps-symbol-macro-p form) form)
+ ((and (consp form) (ps-macro-p (car form))) (car form)))))
+ (if macro-function
+ (values (ps-macroexpand (funcall (lookup-macro-expansion-function macro-function) form)) t)
+ (values form nil))))
;;;; compiler interface
(defgeneric compile-parenscript-form (form &key expecting)
resultant symbol has an associated script-package. Raises an error if
the form cannot be compiled to a symbol."
(let ((exp (compile-parenscript-form form)))
- (when (or (eql (first exp) 'js-variable)
- (eql (first exp) 'ps-quote))
+ (when (eq (first exp) 'js:variable)
(setf exp (second exp)))
(assert (symbolp exp) ()
"~a is expected to be a symbol, but compiles to ~a (the ParenScript output for ~a alone is \"~a\"). This could be due to ~a being a special form." form exp form (ps* form) form)
(if (ps-literal-p symbol)
(funcall (get-ps-special-form symbol) :symbol)
(error "Attempting to use Parenscript special form ~a as variable" symbol)))
- (t (list 'js-variable symbol))))
-
-(defun compile-function-argument-forms (args)
- (let ((remaining-args args))
- (loop while remaining-args collecting
- (if (keywordp (first remaining-args))
- (prog2 (when (oddp (length remaining-args))
- (error "Odd number of keyword arguments: ~A." args))
- (compile-parenscript-form (cons 'create remaining-args) :expecting :expression)
- (setf remaining-args nil))
- (prog1 (compile-parenscript-form (first remaining-args) :expecting :expression)
- (setf remaining-args (cdr remaining-args)))))))
+ (t `(js:variable ,symbol))))
(defun ps-convert-op-name (op)
- (case (ensure-ps-symbol op)
+ (case op
(and '\&\&)
(or '\|\|)
(not '!)
(defmethod compile-parenscript-form ((form cons) &key (expecting :statement))
(let* ((name (car form))
(args (cdr form)))
- (cond ((eql name 'quote)
- (assert (= 1 (length args)) () "Wrong number of arguments to quote: ~s" args)
- (list 'ps-quote (first args)))
- ((ps-special-form-p form) (apply (get-ps-special-form name) (cons expecting args)))
+ (cond ((ps-special-form-p form) (apply (get-ps-special-form name) (cons expecting args)))
((op-form-p form)
- (list 'operator
- (ps-convert-op-name (compile-parenscript-form (first form) :expecting :symbol))
- (mapcar (lambda (form) (compile-parenscript-form form :expecting :expression)) (rest form))))
+ `(js:operator
+ ,(ps-convert-op-name (compile-parenscript-form (first form) :expecting :symbol))
+ ,@(mapcar (lambda (form) (compile-parenscript-form form :expecting :expression)) (rest form))))
((funcall-form-p form)
- (list 'js-funcall
- (compile-parenscript-form name :expecting :expression)
- (compile-function-argument-forms args)))
+ `(js:funcall ,(compile-parenscript-form name :expecting :expression)
+ ,@(mapcar (lambda (arg) (compile-parenscript-form arg :expecting :expression)) args)))
(t (error "Cannot compile ~S to a ParenScript form." form)))))
(defvar *ps-gensym-counter* 0)