+;;; VARIABLE-ARITY compiles variable arity operations. ARGS stands for
+;;; a variable which holds a list of forms. It will compile them and
+;;; store the result in some Javascript variables. BODY is evaluated
+;;; with ARGS bound to the list of these variables to generate the
+;;; code which performs the transformation on these variables.
+
+(defun variable-arity-call (args function)
+ (unless (consp args)
+ (error "ARGS must be a non-empty list"))
+ (let ((counter 0)
+ (variables '())
+ (prelude))
+ (dolist (x args)
+ (let ((v (concat "x" (integer-to-string (incf counter)))))
+ (push v variables)
+ (concatf prelude
+ (concat "var " v " = " (ls-compile x) ";" *newline*
+ "if (typeof " v " !=== 'number') throw 'Not a number!';"
+ *newline*))))
+ (js!selfcall prelude (funcall function (reverse variables)))))
+
+
+(defmacro variable-arity (args &body body)
+ (unless (symbolp args)
+ (error "Bad usage of VARIABLE-ARITY, you must pass a symbol"))
+ `(variable-arity-call ,args
+ (lambda (,args)
+ (concat "return " ,@body ";" *newline*))))
+
+
+(define-raw-builtin plus (&rest numbers)
+ (variable-arity numbers
+ (join numbers "+")))
+
+(define-raw-builtin minus (x &rest others)
+ (let ((args (cons x others)))
+ (variable-arity args
+ (if (null others)
+ (concat "-" (car args))
+ (join args "+")))))
+
+