From: David Vázquez Date: Wed, 19 Jun 2013 04:08:23 +0000 (+0200) Subject: Escape Javascript strings X-Git-Url: http://repo.macrolet.net/gitweb/?a=commitdiff_plain;h=7ea618363a66c91643ac286287d2c3aa7f978a37;p=jscl.git Escape Javascript strings --- diff --git a/experimental/codegen.lisp b/experimental/codegen.lisp index ea52dfd..0fa2c5c 100644 --- a/experimental/codegen.lisp +++ b/experimental/codegen.lisp @@ -12,8 +12,63 @@ x (list x))) +(defun concat (&rest strs) + (apply #'concatenate 'string strs)) + +(defmacro while (condition &body body) + `(do () + ((not ,condition)) + ,@body)) + (defvar *js-output* t) +;;; 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 js-format (fmt &rest args) (apply #'format *js-output* fmt args)) @@ -44,7 +99,7 @@ ((numberp form) (js-format "~a" form)) ((stringp form) - (js-format "'~a'" form)) + (js-format "~a" (js-escape-string form))) ((symbolp form) (case form (true (js-format "true"))