- (t op)))
-
-(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)))
- ((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))))
- ((funcall-form-p form)
- (list 'js-funcall
- (compile-parenscript-form name :expecting :expression)
- (compile-function-argument-forms args)))
- (t (error "Cannot compile ~S to a ParenScript form." form)))))
+ (t op)))
+
+(defun maybe-fix-nary-comparison-form (form)
+ (if (< 2 (length (cdr form)))
+ (values
+ (let* ((operator (car form))
+ (tmp-var-forms (butlast (cddr form)))
+ (tmp-vars (loop repeat (length tmp-var-forms)
+ collect (ps-gensym "_cmp")))
+ (all-comparisons (append (list (cadr form))
+ tmp-vars
+ (last form))))
+ `(let ,(mapcar #'list tmp-vars tmp-var-forms)
+ (and ,@(loop for x1 in all-comparisons
+ for x2 in (cdr all-comparisons)
+ collect (list operator x1 x2)))))
+ t)
+ form))
+
+(defun compile-op-form (form)
+ `(js:operator ,(ps-convert-op-name (ps-compile-symbol (car form)))
+ ,@(mapcar (lambda (form)
+ (ps-compile-expression (ps-macroexpand form)))
+ (cdr form))))
+
+(defun compile-method-call-form (form)
+ (compile-funcall-form
+ `((js:slot-value ,(second form)
+ ',(make-symbol (subseq (symbol-name (first form)) 1)))
+ ,@(cddr form))))
+
+(defun function-name->js-expression (name)
+ (aif (compound-symbol-p name)
+ it
+ `(js:variable ,(maybe-rename-local-function name))))
+
+(defun compile-funcall-form (form)
+ `(js:funcall
+ ,(if (symbolp (car form))
+ (function-name->js-expression (car form))
+ (ps-compile-expression (ps-macroexpand (car form))))
+ ,@(mapcar #'ps-compile-expression (cdr form))))
+
+(defvar compile-expression?)
+
+(defmethod ps-compile ((form cons))
+ (multiple-value-bind (form expanded-p)
+ (ps-macroexpand form)
+ (let ((*ps-compilation-level*
+ (if expanded-p
+ *ps-compilation-level*
+ (adjust-ps-compilation-level form *ps-compilation-level*))))
+ (cond (expanded-p
+ (ps-compile form))
+ ((ps-special-form-p form)
+ (apply (get-ps-special-form (car form)) (cdr form)))
+ ((comparison-form-p form)
+ (multiple-value-bind (form fixed?)
+ (maybe-fix-nary-comparison-form form)
+ (if fixed?
+ (ps-compile form)
+ (compile-op-form form))))
+ ((op-form-p form)
+ (compile-op-form form))
+ ((method-call-form-p form)
+ (compile-method-call-form form))
+ ((funcall-form-p form)
+ (compile-funcall-form form))
+ (t (error "Cannot compile ~S to a ParenScript form." form))))))
+
+(defun ps-compile-statement (form)
+ (let ((compile-expression? nil))
+ (ps-compile form)))
+
+(defun ps-compile-expression (form)
+ (let ((compile-expression? t))
+ (ps-compile form)))