Browse Source

Use literal raw text in error messages

Fixes #127.
redux
David Majda 6 years ago
parent
commit
69a0f769fc
  1. 4
      lib/compiler/passes/generate-bytecode.js
  2. 7
      lib/parser.js
  3. 2
      spec/api/plugin-api.spec.js
  4. 2
      spec/unit/compiler/passes/generate-bytecode.spec.js
  5. 87
      spec/unit/parser.spec.js
  6. 1
      src/parser.pegjs

4
lib/compiler/passes/generate-bytecode.js

@ -536,9 +536,7 @@ function generateBytecode(ast) {
'{',
'type: "literal",',
'value: "' + js.stringEscape(node.value) + '",',
'description: "'
+ js.stringEscape('"' + js.stringEscape(node.value) + '"')
+ '"',
'description: "' + js.stringEscape(node.rawText) + '"',
'}'
].join(' '));

7
lib/parser.js

@ -149,13 +149,13 @@ module.exports = (function() {
peg$c36 = "\t",
peg$c37 = { type: "literal", value: "\t", description: "\"\\t\"" },
peg$c38 = "\x0B",
peg$c39 = { type: "literal", value: "\x0B", description: "\"\\x0B\"" },
peg$c39 = { type: "literal", value: "\x0B", description: "\"\\v\"" },
peg$c40 = "\f",
peg$c41 = { type: "literal", value: "\f", description: "\"\\f\"" },
peg$c42 = " ",
peg$c43 = { type: "literal", value: " ", description: "\" \"" },
peg$c44 = "\xA0",
peg$c45 = { type: "literal", value: "\xA0", description: "\"\\xA0\"" },
peg$c45 = { type: "literal", value: "\xA0", description: "\"\\u00A0\"" },
peg$c46 = "\uFEFF",
peg$c47 = { type: "literal", value: "\uFEFF", description: "\"\\uFEFF\"" },
peg$c48 = /^[\n\r\u2028\u2029]/,
@ -198,12 +198,13 @@ module.exports = (function() {
type: "literal",
value: value,
ignoreCase: ignoreCase !== null,
rawText: text(),
location: location()
};
},
peg$c84 = { type: "other", description: "string" },
peg$c85 = "\"",
peg$c86 = { type: "literal", value: "\"", description: "\"\\\"\"" },
peg$c86 = { type: "literal", value: "\"", description: "'\"'" },
peg$c87 = function(chars) { return chars.join(""); },
peg$c88 = "'",
peg$c89 = { type: "literal", value: "'", description: "\"'\"" },

2
spec/api/plugin-api.spec.js

@ -108,7 +108,7 @@ describe("plugin API", function() {
' {',
' type: "rule",',
' name: "start",',
' expression: { type: "literal", value: text(), ignoreCase: false }',
' expression: { type: "literal", value: text(), ignoreCase: false, rawText: text() }',
' }',
' ]',
' };',

2
spec/unit/compiler/passes/generate-bytecode.spec.js

@ -572,7 +572,7 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'{ type: "literal", value: "A", description: "\\"A\\"" }'
'{ type: "literal", value: "A", description: "\\"A\\"i" }'
]));
});
});

87
spec/unit/parser.spec.js

@ -4,10 +4,10 @@
"use strict";
describe("PEG.js grammar parser", function() {
var literalAbcd = { type: "literal", value: "abcd", ignoreCase: false },
literalEfgh = { type: "literal", value: "efgh", ignoreCase: false },
literalIjkl = { type: "literal", value: "ijkl", ignoreCase: false },
literalMnop = { type: "literal", value: "mnop", ignoreCase: false },
var literalAbcd = { type: "literal", value: "abcd", ignoreCase: false, rawText: '"abcd"' },
literalEfgh = { type: "literal", value: "efgh", ignoreCase: false, rawText: '"efgh"' },
literalIjkl = { type: "literal", value: "ijkl", ignoreCase: false, rawText: '"ijkl"' },
literalMnop = { type: "literal", value: "mnop", ignoreCase: false, rawText: '"mnop"' },
semanticAnd = { type: "semantic_and", code: " code " },
semanticNot = { type: "semantic_not", code: " code " },
optional = { type: "optional", expression: literalAbcd },
@ -72,10 +72,13 @@ describe("PEG.js grammar parser", function() {
);
}
function literalGrammar(value, ignoreCase) {
return oneRuleGrammar(
{ type: "literal", value: value, ignoreCase: ignoreCase }
);
function literalGrammar(value, ignoreCase, rawText) {
return oneRuleGrammar({
type: "literal",
value: value,
ignoreCase: ignoreCase,
rawText: rawText
});
}
function classGrammar(parts, inverted, ignoreCase, rawText) {
@ -96,7 +99,7 @@ describe("PEG.js grammar parser", function() {
return oneRuleGrammar({ type: "rule_ref", name: name });
}
var trivialGrammar = literalGrammar("abcd", false),
var trivialGrammar = literalGrammar("abcd", false, '"abcd"'),
twoRuleGrammar = {
type: "grammar",
initializer: null,
@ -488,26 +491,26 @@ describe("PEG.js grammar parser", function() {
/* Canonical LiteralMatcher is "\"abcd\"". */
it("parses LiteralMatcher", function() {
expect('start = "abcd"' ).toParseAs(literalGrammar("abcd", false));
expect('start = "abcd"i').toParseAs(literalGrammar("abcd", true));
expect('start = "abcd"' ).toParseAs(literalGrammar("abcd", false, '"abcd"'));
expect('start = "abcd"i').toParseAs(literalGrammar("abcd", true, '"abcd"i'));
});
/* Canonical StringLiteral is "\"abcd\"". */
it("parses StringLiteral", function() {
expect('start = ""' ).toParseAs(literalGrammar("", false));
expect('start = "a"' ).toParseAs(literalGrammar("a", false));
expect('start = "abc"').toParseAs(literalGrammar("abc", false));
expect('start = ""' ).toParseAs(literalGrammar("", false, '""'));
expect('start = "a"' ).toParseAs(literalGrammar("a", false, '"a"'));
expect('start = "abc"').toParseAs(literalGrammar("abc", false, '"abc"'));
expect("start = ''" ).toParseAs(literalGrammar("", false));
expect("start = 'a'" ).toParseAs(literalGrammar("a", false));
expect("start = 'abc'").toParseAs(literalGrammar("abc", false));
expect("start = ''" ).toParseAs(literalGrammar("", false, "''"));
expect("start = 'a'" ).toParseAs(literalGrammar("a", false, "'a'"));
expect("start = 'abc'").toParseAs(literalGrammar("abc", false, "'abc'"));
});
/* Canonical DoubleStringCharacter is "a". */
it("parses DoubleStringCharacter", function() {
expect('start = "a"' ).toParseAs(literalGrammar("a", false));
expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false));
expect('start = "\\\n"').toParseAs(literalGrammar("", false));
expect('start = "a"' ).toParseAs(literalGrammar("a", false, '"a"'));
expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false, '"\\n"'));
expect('start = "\\\n"').toParseAs(literalGrammar("", false, '"\\\n"'));
expect('start = """' ).toFailToParse();
expect('start = "\\"').toFailToParse();
@ -516,9 +519,9 @@ describe("PEG.js grammar parser", function() {
/* Canonical SingleStringCharacter is "a". */
it("parses SingleStringCharacter", function() {
expect("start = 'a'" ).toParseAs(literalGrammar("a", false));
expect("start = '\\n'" ).toParseAs(literalGrammar("\n", false));
expect("start = '\\\n'").toParseAs(literalGrammar("", false));
expect("start = 'a'" ).toParseAs(literalGrammar("a", false, "'a'"));
expect("start = '\\n'" ).toParseAs(literalGrammar("\n", false, "'\\n'"));
expect("start = '\\\n'").toParseAs(literalGrammar("", false, "'\\\n'"));
expect("start = '''" ).toFailToParse();
expect("start = '\\'").toFailToParse();
@ -589,41 +592,41 @@ describe("PEG.js grammar parser", function() {
/* Canonical LineContinuation is "\\\n". */
it("parses LineContinuation", function() {
expect('start = "\\\r\n"').toParseAs(literalGrammar("", false));
expect('start = "\\\r\n"').toParseAs(literalGrammar("", false, '"\\\r\n"'));
});
/* Canonical EscapeSequence is "n". */
it("parses EscapeSequence", function() {
expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false));
expect('start = "\\0"' ).toParseAs(literalGrammar("\x00", false));
expect('start = "\\xFF"' ).toParseAs(literalGrammar("\xFF", false));
expect('start = "\\uFFFF"').toParseAs(literalGrammar("\uFFFF", false));
expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false, '"\\n"'));
expect('start = "\\0"' ).toParseAs(literalGrammar("\x00", false, '"\\0"'));
expect('start = "\\xFF"' ).toParseAs(literalGrammar("\xFF", false, '"\\xFF"'));
expect('start = "\\uFFFF"').toParseAs(literalGrammar("\uFFFF", false, '"\\uFFFF"'));
expect('start = "\\09"').toFailToParse();
});
/* Canonical CharacterEscapeSequence is "n". */
it("parses CharacterEscapeSequence", function() {
expect('start = "\\n"').toParseAs(literalGrammar("\n", false));
expect('start = "\\a"').toParseAs(literalGrammar("a", false));
expect('start = "\\n"').toParseAs(literalGrammar("\n", false, '"\\n"'));
expect('start = "\\a"').toParseAs(literalGrammar("a", false, '"\\a"'));
});
/* Canonical SingleEscapeCharacter is "n". */
it("parses SingleEscapeCharacter", function() {
expect('start = "\\\'"').toParseAs(literalGrammar("'", false));
expect('start = "\\""' ).toParseAs(literalGrammar('"', false));
expect('start = "\\\\"').toParseAs(literalGrammar("\\", false));
expect('start = "\\b"' ).toParseAs(literalGrammar("\b", false));
expect('start = "\\f"' ).toParseAs(literalGrammar("\f", false));
expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false));
expect('start = "\\r"' ).toParseAs(literalGrammar("\r", false));
expect('start = "\\t"' ).toParseAs(literalGrammar("\t", false));
expect('start = "\\v"' ).toParseAs(literalGrammar("\x0B", false)); // no "\v" in IE
expect('start = "\\\'"').toParseAs(literalGrammar("'", false, '"\\\'"'));
expect('start = "\\""' ).toParseAs(literalGrammar('"', false, '"\\""'));
expect('start = "\\\\"').toParseAs(literalGrammar("\\", false, '"\\\\"'));
expect('start = "\\b"' ).toParseAs(literalGrammar("\b", false, '"\\b"'));
expect('start = "\\f"' ).toParseAs(literalGrammar("\f", false, '"\\f"'));
expect('start = "\\n"' ).toParseAs(literalGrammar("\n", false, '"\\n"'));
expect('start = "\\r"' ).toParseAs(literalGrammar("\r", false, '"\\r"'));
expect('start = "\\t"' ).toParseAs(literalGrammar("\t", false, '"\\t"'));
expect('start = "\\v"' ).toParseAs(literalGrammar("\x0B", false, '"\\v"')); // no "\v" in IE
});
/* Canonical NonEscapeCharacter is "a". */
it("parses NonEscapeCharacter", function() {
expect('start = "\\a"').toParseAs(literalGrammar("a", false));
expect('start = "\\a"').toParseAs(literalGrammar("a", false, '"\\a"'));
/*
* The negative predicate is impossible to test with PEG.js grammar
@ -638,12 +641,12 @@ describe("PEG.js grammar parser", function() {
/* Canonical HexEscapeSequence is "xFF". */
it("parses HexEscapeSequence", function() {
expect('start = "\\xFF"').toParseAs(literalGrammar("\xFF", false));
expect('start = "\\xFF"').toParseAs(literalGrammar("\xFF", false, '"\\xFF"'));
});
/* Canonical UnicodeEscapeSequence is "uFFFF". */
it("parses UnicodeEscapeSequence", function() {
expect('start = "\\uFFFF"').toParseAs(literalGrammar("\uFFFF", false));
expect('start = "\\uFFFF"').toParseAs(literalGrammar("\uFFFF", false, '"\\uFFFF"'));
});
/* Digit rules are not tested. */

1
src/parser.pegjs

@ -345,6 +345,7 @@ LiteralMatcher "literal"
type: "literal",
value: value,
ignoreCase: ignoreCase !== null,
rawText: text(),
location: location()
};
}

Loading…
Cancel
Save