From 41f31884e0be58584c3ec47f78e32f305833d3a0 Mon Sep 17 00:00:00 2001 From: Owen Rodley Date: Tue, 4 Jun 2013 16:42:44 +1200 Subject: [PATCH] Smarter string escaping. Fixes #114 If the string contains no single quotes, use a single-quoted string. If the string contains no double quotes, use a double-quoted string. If it contains both, single-quote it and escape the single-quotes. In all cases backslashes and newlines are escaped. --- src/compiler.lisp | 56 ++++++++++++++++++++++++++++++++++++----------------- src/print.lisp | 2 +- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/compiler.lisp b/src/compiler.lisp index e2f9fca..fb9f62d 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 = " (escape-string name) ";" *newline*)) (when docstring - (code "func.docstring = \"" (escape-string docstring) "\";" *newline*)) + (code "func.docstring = " (escape-string docstring) ";" *newline*)) "return func;" *newline*) (apply #'code strs))) @@ -482,21 +482,41 @@ ;;; Compilation of literals an object dumping - (defun 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)) - output)) + (let ((index 0) + (size (length string)) + (seen-single-quote nil) + (seen-double-quote nil)) + (flet ((%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 "'" (%escape-string string nil) "'")) + ((not seen-double-quote) + (concat "\"" (%escape-string string nil) "\"")) + (t (concat "'" (%escape-string string t) "'")))))) ;;; BOOTSTRAP MAGIC: We record the macro definitions as lists during ;;; the bootstrap. Once everything is compiled, we want to dump the @@ -550,13 +570,13 @@ (concat "[" (join (mapcar #'literal elements) ", ") "]"))) (defun dump-string (string) - (code "make_lisp_string(\"" (escape-string string) "\")")) + (code "make_lisp_string(" (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) (escape-string (string sexp))) (t (or (cdr (assoc sexp *literal-table* :test #'eql)) (let ((dumped (typecase sexp diff --git a/src/print.lisp b/src/print.lisp index 7daa143..f5e3f3b 100644 --- a/src/print.lisp +++ b/src/print.lisp @@ -194,7 +194,7 @@ (#\space "space") (otherwise (string form))))) ((stringp form) (if *print-escape* - (concat "\"" (escape-string form) "\"") + (escape-string form) form)) ((functionp form) (let ((name (oget form "fname"))) -- 1.7.10.4