X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcompiler.lisp;fp=src%2Fcompiler.lisp;h=806c9e0810d086846adcebed4d8c093e76602c52;hb=bf2a019d267d23ce1ed6b0eb09da07310bb7e758;hp=449bb3e988eb44488947c6e9065e11857f60335e;hpb=3328a5d8e03ed74ff1871fc22403a3e25e001fe9;p=jscl.git diff --git a/src/compiler.lisp b/src/compiler.lisp index 449bb3e..806c9e0 100644 --- a/src/compiler.lisp +++ b/src/compiler.lisp @@ -266,9 +266,9 @@ (js!selfcall "var func = " (join strs) ";" *newline* (when name - (code "func.fname = \"" (escape-string name) "\";" *newline*)) + (code "func.fname = " (js-escape-string name) ";" *newline*)) (when docstring - (code "func.docstring = \"" (escape-string docstring) "\";" *newline*)) + (code "func.docstring = " (js-escape-string docstring) ";" *newline*)) "return func;" *newline*) (apply #'code strs))) @@ -483,7 +483,53 @@ ;;; Compilation of literals an object dumping -(defun escape-string (string) +;;; 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))) @@ -496,7 +542,7 @@ (setq ch #\n)) (setq output (concat output (string ch)))) (incf index)) - output)) + (concat "\"" output "\""))) ;;; BOOTSTRAP MAGIC: We record the macro definitions as lists during ;;; the bootstrap. Once everything is compiled, we want to dump the @@ -550,13 +596,13 @@ (concat "[" (join (mapcar #'literal elements) ", ") "]"))) (defun dump-string (string) - (code "make_lisp_string(\"" (escape-string string) "\")")) + (code "make_lisp_string(" (js-escape-string string) ")")) (defun literal (sexp &optional recursive) (cond ((integerp sexp) (integer-to-string sexp)) ((floatp sexp) (float-to-string sexp)) - ((characterp sexp) (code "\"" (escape-string (string sexp)) "\"")) + ((characterp sexp) (js-escape-string (string sexp))) (t (or (cdr (assoc sexp *literal-table* :test #'eql)) (let ((dumped (typecase sexp