(mapconcat #'parse-keyword keyword-arguments))))
;; Check for unknown keywords
(when keyword-arguments
- (code "for (i=" (+ n-required-arguments n-optional-arguments)
- "; i<nargs; i+=2){" *newline*
+ (code "var start = " (+ n-required-arguments n-optional-arguments) ";" *newline*
+ "if ((nargs - start) % 2 == 1){" *newline*
+ (indent "throw 'Odd number of keyword arguments';" *newline*)
+ "}" *newline*
+ "for (i = start; i<nargs; i+=2){" *newline*
(indent "if ("
(join (mapcar (lambda (x)
(concat "arguments[i+2] !== " (ls-compile (caar x))))
" && ")
")" *newline*
(indent
- "throw 'Unknown keyword argument ' + xstring(arguments[i].name);" *newline*))
+ "throw 'Unknown keyword argument ' + xstring(arguments[i+2].name);" *newline*))
"}" *newline*)))))
(defun parse-lambda-list (ll)
;;; Compilation of literals an object dumping
-;;; Two seperate functions are needed for escaping strings:
-;;; One for producing JavaScript string literals (which are singly or
-;;; doubly quoted)
-;;; And one for producing Lisp strings (which are only doubly quoted)
-;;;
-;;; The same function would suffice for both, but for javascript string
-;;; literals it is neater to use either depending on the context, e.g:
-;;; foo's => "foo's"
-;;; "foo" => '"foo"'
-;;; which avoids having to escape quotes where possible
-(defun js-escape-string (string)
- (let ((index 0)
- (size (length string))
- (seen-single-quote nil)
- (seen-double-quote nil))
- (flet ((%js-escape-string (string escape-single-quote-p)
- (let ((output "")
- (index 0))
- (while (< index size)
- (let ((ch (char string index)))
- (when (char= ch #\\)
- (setq output (concat output "\\")))
- (when (and escape-single-quote-p (char= ch #\'))
- (setq output (concat output "\\")))
- (when (char= ch #\newline)
- (setq output (concat output "\\"))
- (setq ch #\n))
- (setq output (concat output (string ch))))
- (incf index))
- output)))
- ;; First, scan the string for single/double quotes
- (while (< index size)
- (let ((ch (char string index)))
- (when (char= ch #\')
- (setq seen-single-quote t))
- (when (char= ch #\")
- (setq seen-double-quote t)))
- (incf index))
- ;; Then pick the appropriate way to escape the quotes
- (cond
- ((not seen-single-quote)
- (concat "'" (%js-escape-string string nil) "'"))
- ((not seen-double-quote)
- (concat "\"" (%js-escape-string string nil) "\""))
- (t (concat "'" (%js-escape-string string t) "'"))))))
-
-(defun lisp-escape-string (string)
- (let ((output "")
- (index 0)
- (size (length string)))
- (while (< index size)
- (let ((ch (char string index)))
- (when (or (char= ch #\") (char= ch #\\))
- (setq output (concat output "\\")))
- (when (or (char= ch #\newline))
- (setq output (concat output "\\"))
- (setq ch #\n))
- (setq output (concat output (string ch))))
- (incf index))
- (concat "\"" output "\"")))
-
;;; BOOTSTRAP MAGIC: We record the macro definitions as lists during
;;; the bootstrap. Once everything is compiled, we want to dump the
;;; whole global environment to the output file to reproduce it in the
",")
")")))
+(define-compilation macrolet (definitions &rest body)
+ (let ((*environment* (copy-lexenv *environment*)))
+ (dolist (def definitions)
+ (destructuring-bind (name lambda-list &body body) def
+ (let ((binding (make-binding :name name :type 'macro :value
+ (let ((g!form (gensym)))
+ `(lambda (,g!form)
+ (destructuring-bind ,lambda-list ,g!form
+ ,@body))))))
+ (push-to-lexenv binding *environment* 'function))))
+ (ls-compile `(progn ,@body) *multiple-value-p*)))
+
+
(defun special-variable-p (x)
(and (claimp x 'variable 'special) t))
(js!selfcall
"var tmp = (" (ls-compile object) ")[xstring(" (ls-compile key) ")];" *newline*
(mapconcat (lambda (key)
- (code "if (tmp === undefined) return " (ls-compile nil) ";" *newline*)
- (code "tmp = tmp[xstring(" (ls-compile key) ")];" *newline*))
+ (code "if (tmp === undefined) return " (ls-compile nil) ";" *newline*
+ "tmp = tmp[xstring(" (ls-compile key) ")];" *newline*))
keys)
"return tmp === undefined? " (ls-compile nil) " : tmp;" *newline*))
(js!selfcall
"var obj = " (ls-compile object) ";" *newline*
(mapconcat (lambda (key)
- "obj = obj[xstring(" (ls-compile key) ")];"
- "if (obj === undefined) throw 'Impossible to set Javascript property.';" *newline*)
+ (code "obj = obj[xstring(" (ls-compile key) ")];"
+ "if (obj === undefined) throw 'Impossible to set Javascript property.';" *newline*))
(butlast keys))
"var tmp = obj[xstring(" (ls-compile (car (last keys))) ")] = " (ls-compile value) ";" *newline*
"return tmp === undefined? " (ls-compile nil) " : tmp;" *newline*)))