diff --git a/src/emitter.js b/src/emitter.js index a7b87f0..2ccc8fd 100644 --- a/src/emitter.js +++ b/src/emitter.js @@ -162,13 +162,20 @@ PEG.compiler.emitter = function(ast) { " * string literal except for the closing quote character, backslash,", " * carriage return, line separator, paragraph separator, and line feed.", " * Any character may appear in the form of an escape sequence.", + " *", + " * For portability, we also escape escape all control and non-ASCII", + " * characters. Note that \"\\0\" and \"\\v\" escape sequences are not used", + " * because JSHint does not like the first and IE the second.", " */", " return '\"' + s", - " .replace(/\\\\/g, '\\\\\\\\') // backslash", - " .replace(/\"/g, '\\\\\"') // closing quote character", - " .replace(/\\r/g, '\\\\r') // carriage return", - " .replace(/\\n/g, '\\\\n') // line feed", - " .replace(/[\\x80-\\uFFFF]/g, escape) // non-ASCII characters", + " .replace(/\\\\/g, '\\\\\\\\') // backslash", + " .replace(/\"/g, '\\\\\"') // closing quote character", + " .replace(/\\x08/g, '\\\\b') // backspace", + " .replace(/\\t/g, '\\\\t') // horizontal tab", + " .replace(/\\n/g, '\\\\n') // line feed", + " .replace(/\\f/g, '\\\\f') // form feed", + " .replace(/\\r/g, '\\\\r') // carriage return", + " .replace(/[\\x00-\\x07\\x0B\\x0E-\\x1F\\x80-\\uFFFF]/g, escape)", " + '\"';", " }", " ", diff --git a/src/parser.js b/src/parser.js index 8b8c3ca..91ce674 100644 --- a/src/parser.js +++ b/src/parser.js @@ -114,13 +114,20 @@ PEG.parser = (function(){ * string literal except for the closing quote character, backslash, * carriage return, line separator, paragraph separator, and line feed. * Any character may appear in the form of an escape sequence. + * + * For portability, we also escape escape all control and non-ASCII + * characters. Note that "\0" and "\v" escape sequences are not used + * because JSHint does not like the first and IE the second. */ return '"' + s - .replace(/\\/g, '\\\\') // backslash - .replace(/"/g, '\\"') // closing quote character - .replace(/\r/g, '\\r') // carriage return - .replace(/\n/g, '\\n') // line feed - .replace(/[\x80-\uFFFF]/g, escape) // non-ASCII characters + .replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing quote character + .replace(/\x08/g, '\\b') // backspace + .replace(/\t/g, '\\t') // horizontal tab + .replace(/\n/g, '\\n') // line feed + .replace(/\f/g, '\\f') // form feed + .replace(/\r/g, '\\r') // carriage return + .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + '"'; } @@ -3610,7 +3617,7 @@ PEG.parser = (function(){ } else { result0 = null; if (reportFailures === 0) { - matchFailed("[ \\xA0\\uFEFF\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]"); + matchFailed("[ \t\x0B\f\\xA0\\uFEFF\\u1680\\u180E\\u2000-\\u200A\\u202F\\u205F\\u3000]"); } } reportFailures--; diff --git a/src/utils.js b/src/utils.js index d292dfc..fc04a4d 100644 --- a/src/utils.js +++ b/src/utils.js @@ -96,14 +96,19 @@ function quote(s) { * line separator, paragraph separator, and line feed. Any character may * appear in the form of an escape sequence. * - * For portability, we also escape escape all non-ASCII characters. + * For portability, we also escape escape all control and non-ASCII + * characters. Note that "\0" and "\v" escape sequences are not used because + * JSHint does not like the first and IE the second. */ return '"' + s - .replace(/\\/g, '\\\\') // backslash - .replace(/"/g, '\\"') // closing quote character - .replace(/\r/g, '\\r') // carriage return - .replace(/\n/g, '\\n') // line feed - .replace(/[\x80-\uFFFF]/g, escape) // non-ASCII characters + .replace(/\\/g, '\\\\') // backslash + .replace(/"/g, '\\"') // closing quote character + .replace(/\x08/g, '\\b') // backspace + .replace(/\t/g, '\\t') // horizontal tab + .replace(/\n/g, '\\n') // line feed + .replace(/\f/g, '\\f') // form feed + .replace(/\r/g, '\\r') // carriage return + .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + '"'; }