Use only double quotes for strings

See #443
redux
David Majda 8 years ago
parent 6294bb5b13
commit 12112310f2

@ -12,19 +12,19 @@ let js = {
//
// For portability, we also escape all control and non-ASCII characters.
return s
.replace(/\\/g, '\\\\') // backslash
.replace(/"/g, '\\"') // closing double quote
.replace(/\0/g, '\\0') // null
.replace(/\x08/g, '\\b') // backspace
.replace(/\t/g, '\\t') // horizontal tab
.replace(/\n/g, '\\n') // line feed
.replace(/\v/g, '\\v') // vertical tab
.replace(/\f/g, '\\f') // form feed
.replace(/\r/g, '\\r') // carriage return
.replace(/[\x00-\x0F]/g, ch => '\\x0' + hex(ch))
.replace(/[\x10-\x1F\x7F-\xFF]/g, ch => '\\x' + hex(ch))
.replace(/[\u0100-\u0FFF]/g, ch => '\\u0' + hex(ch))
.replace(/[\u1000-\uFFFF]/g, ch => '\\u' + hex(ch));
.replace(/\\/g, "\\\\") // backslash
.replace(/"/g, "\\\"") // closing double quote
.replace(/\0/g, "\\0") // null
.replace(/\x08/g, "\\b") // backspace
.replace(/\t/g, "\\t") // horizontal tab
.replace(/\n/g, "\\n") // line feed
.replace(/\v/g, "\\v") // vertical tab
.replace(/\f/g, "\\f") // form feed
.replace(/\r/g, "\\r") // carriage return
.replace(/[\x00-\x0F]/g, ch => "\\x0" + hex(ch))
.replace(/[\x10-\x1F\x7F-\xFF]/g, ch => "\\x" + hex(ch))
.replace(/[\u0100-\u0FFF]/g, ch => "\\u0" + hex(ch))
.replace(/[\u1000-\uFFFF]/g, ch => "\\u" + hex(ch));
},
regexpClassEscape: function(s) {
@ -32,22 +32,22 @@ let js = {
//
// For portability, we also escape all control and non-ASCII characters.
return s
.replace(/\\/g, '\\\\') // backslash
.replace(/\//g, '\\/') // closing slash
.replace(/\]/g, '\\]') // closing bracket
.replace(/\^/g, '\\^') // caret
.replace(/-/g, '\\-') // dash
.replace(/\0/g, '\\0') // null
.replace(/\x08/g, '\\b') // backspace
.replace(/\t/g, '\\t') // horizontal tab
.replace(/\n/g, '\\n') // line feed
.replace(/\v/g, '\\v') // vertical tab
.replace(/\f/g, '\\f') // form feed
.replace(/\r/g, '\\r') // carriage return
.replace(/[\x00-\x0F]/g, ch => '\\x0' + hex(ch))
.replace(/[\x10-\x1F\x7F-\xFF]/g, ch => '\\x' + hex(ch))
.replace(/[\u0100-\u0FFF]/g, ch => '\\u0' + hex(ch))
.replace(/[\u1000-\uFFFF]/g, ch => '\\u' + hex(ch));
.replace(/\\/g, "\\\\") // backslash
.replace(/\//g, "\\/") // closing slash
.replace(/\]/g, "\\]") // closing bracket
.replace(/\^/g, "\\^") // caret
.replace(/-/g, "\\-") // dash
.replace(/\0/g, "\\0") // null
.replace(/\x08/g, "\\b") // backspace
.replace(/\t/g, "\\t") // horizontal tab
.replace(/\n/g, "\\n") // line feed
.replace(/\v/g, "\\v") // vertical tab
.replace(/\f/g, "\\f") // form feed
.replace(/\r/g, "\\r") // carriage return
.replace(/[\x00-\x0F]/g, ch => "\\x0" + hex(ch))
.replace(/[\x10-\x1F\x7F-\xFF]/g, ch => "\\x" + hex(ch))
.replace(/[\u0100-\u0FFF]/g, ch => "\\u0" + hex(ch))
.replace(/[\u1000-\uFFFF]/g, ch => "\\u" + hex(ch));
}
};

@ -304,7 +304,7 @@ function generateBytecode(ast) {
named: function(node, context) {
let nameIndex = addConst(
'peg$otherExpectation("' + js.stringEscape(node.name) + '")'
"peg$otherExpectation(\"" + js.stringEscape(node.name) + "\")"
);
// The code generated below is slightly suboptimal because |FAIL| pushes
@ -535,17 +535,17 @@ function generateBytecode(ast) {
literal: function(node) {
if (node.value.length > 0) {
let stringIndex = addConst('"'
let stringIndex = addConst("\""
+ js.stringEscape(
node.ignoreCase ? node.value.toLowerCase() : node.value
)
+ '"'
+ "\""
);
let expectedIndex = addConst(
'peg$literalExpectation('
+ '"' + js.stringEscape(node.value) + '", '
"peg$literalExpectation("
+ "\"" + js.stringEscape(node.value) + "\", "
+ node.ignoreCase
+ ')'
+ ")"
);
// For case-sensitive strings the value must match the beginning of the
@ -561,37 +561,37 @@ function generateBytecode(ast) {
[op.FAIL, expectedIndex]
);
} else {
let stringIndex = addConst('""');
let stringIndex = addConst("\"\"");
return [op.PUSH, stringIndex];
}
},
"class": function(node) {
let regexp = '/^['
+ (node.inverted ? '^' : '')
let regexp = "/^["
+ (node.inverted ? "^" : "")
+ node.parts.map(part =>
Array.isArray(part)
? js.regexpClassEscape(part[0])
+ '-'
+ "-"
+ js.regexpClassEscape(part[1])
: js.regexpClassEscape(part)
).join('')
+ ']/' + (node.ignoreCase ? 'i' : '');
let parts = '['
).join("")
+ "]/" + (node.ignoreCase ? "i" : "");
let parts = "["
+ node.parts.map(part =>
Array.isArray(part)
? '["' + js.stringEscape(part[0]) + '", "' + js.stringEscape(part[1]) + '"]'
: '"' + js.stringEscape(part) + '"'
).join(', ')
+ ']';
? "[\"" + js.stringEscape(part[0]) + "\", \"" + js.stringEscape(part[1]) + "\"]"
: "\"" + js.stringEscape(part) + "\""
).join(", ")
+ "]";
let regexpIndex = addConst(regexp);
let expectedIndex = addConst(
'peg$classExpectation('
+ parts + ', '
+ node.inverted + ', '
"peg$classExpectation("
+ parts + ", "
+ node.inverted + ", "
+ node.ignoreCase
+ ')'
+ ")"
);
return buildCondition(
@ -602,7 +602,7 @@ function generateBytecode(ast) {
},
any: function() {
let expectedIndex = addConst('peg$anyExpectation()');
let expectedIndex = addConst("peg$anyExpectation()");
return buildCondition(
[op.MATCH_ANY],

File diff suppressed because it is too large Load Diff

@ -62,28 +62,28 @@ peg$SyntaxError.buildMessage = function(expected, found) {
function literalEscape(s) {
return s
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\0/g, '\\0')
.replace(/\t/g, '\\t')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); });
.replace(/\\/g, "\\\\")
.replace(/"/g, "\\\"")
.replace(/\0/g, "\\0")
.replace(/\t/g, "\\t")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
}
function classEscape(s) {
return s
.replace(/\\/g, '\\\\')
.replace(/\]/g, '\\]')
.replace(/\^/g, '\\^')
.replace(/-/g, '\\-')
.replace(/\0/g, '\\0')
.replace(/\t/g, '\\t')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/[\x00-\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x' + hex(ch); });
.replace(/\\/g, "\\\\")
.replace(/\]/g, "\\]")
.replace(/\^/g, "\\^")
.replace(/-/g, "\\-")
.replace(/\0/g, "\\0")
.replace(/\t/g, "\\t")
.replace(/\n/g, "\\n")
.replace(/\r/g, "\\r")
.replace(/[\x00-\x0F]/g, function(ch) { return "\\x0" + hex(ch); })
.replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return "\\x" + hex(ch); });
}
function describeExpectation(expectation) {
@ -238,7 +238,7 @@ function peg$parse(input, options) {
// don't need to put it around nodes that can't contain any labels or
// nodes that already isolate label scope themselves. This leaves us with
// "labeled" and "sequence".
return expression.type === 'labeled' || expression.type === 'sequence'
return expression.type === "labeled" || expression.type === "sequence"
? { type: "group", expression: expression }
: expression;
};

@ -8,22 +8,22 @@ let peg = require("../../lib/peg");
describe("generated parser API", function() {
describe("parse", function() {
it("parses input", function() {
let parser = peg.generate('start = "a"');
let parser = peg.generate("start = 'a'");
expect(parser.parse("a")).toBe("a");
});
it("throws an exception on syntax error", function() {
let parser = peg.generate('start = "a"');
let parser = peg.generate("start = 'a'");
expect(() => { parser.parse("b"); }).toThrow();
});
describe("start rule", function() {
let parser = peg.generate([
'a = "x" { return "a"; }',
'b = "x" { return "b"; }',
'c = "x" { return "c"; }'
"a = 'x' { return 'a'; }",
"b = 'x' { return 'b'; }",
"c = 'x' { return 'c'; }"
].join("\n"), { allowedStartRules: ["b", "c"] });
describe("when |startRule| is not set", function() {
@ -48,9 +48,9 @@ describe("generated parser API", function() {
describe("tracing", function() {
let parser = peg.generate([
'start = a / b',
'a = "a"',
'b = "b"'
"start = a / b",
"a = 'a'",
"b = 'b'"
].join("\n"), { trace: true });
describe("default tracer", function() {
@ -135,7 +135,7 @@ describe("generated parser API", function() {
});
it("accepts custom options", function() {
let parser = peg.generate('start = "a"');
let parser = peg.generate("start = 'a'");
parser.parse("a", { foo: 42 });
});

@ -5,25 +5,25 @@ let peg = require("../../lib/peg");
describe("PEG.js API", function() {
describe("generate", function() {
it("generates a parser", function() {
let parser = peg.generate('start = "a"');
let parser = peg.generate("start = 'a'");
expect(typeof parser).toBe("object");
expect(parser.parse("a")).toBe("a");
});
it("throws an exception on syntax error", function() {
expect(() => { peg.generate('start = @'); }).toThrow();
expect(() => { peg.generate("start = @"); }).toThrow();
});
it("throws an exception on semantic error", function() {
expect(() => { peg.generate('start = undefined'); }).toThrow();
expect(() => { peg.generate("start = undefined"); }).toThrow();
});
describe("allowed start rules", function() {
let grammar = [
'a = "x"',
'b = "x"',
'c = "x"'
"a = 'x'",
"b = 'x'",
"c = 'x'"
].join("\n");
// The |allowedStartRules| option is implemented separately for each
@ -82,9 +82,9 @@ describe("PEG.js API", function() {
describe("intermediate results caching", function() {
let grammar = [
'{ var n = 0; }',
'start = (a "b") / (a "c") { return n; }',
'a = "a" { n++; }'
"{ var n = 0; }",
"start = (a 'b') / (a 'c') { return n; }",
"a = 'a' { n++; }"
].join("\n");
describe("when |cache| is not set", function() {
@ -113,7 +113,7 @@ describe("PEG.js API", function() {
});
describe("tracing", function() {
let grammar = 'start = "a"';
let grammar = "start = 'a'";
describe("when |trace| is not set", function() {
it("generated parser doesn't trace", function() {
@ -153,7 +153,7 @@ describe("PEG.js API", function() {
// write the specs without turning this into a performance test.
describe("output", function() {
let grammar = 'start = "a"';
let grammar = "start = 'a'";
describe("when |output| is not set", function() {
it("returns generated parser object", function() {
@ -190,7 +190,7 @@ describe("PEG.js API", function() {
// The |plugins| option is tested in plugin API specs.
it("accepts custom options", function() {
peg.generate('start = "a"', { foo: 42 });
peg.generate("start = 'a'", { foo: 42 });
});
});
});

@ -35,7 +35,7 @@ describe("plugin API", function() {
});
describe("use", function() {
let grammar = 'start = "a"';
let grammar = "start = 'a'";
it("is called for each plugin", function() {
let pluginsUsed = [false, false, false];
@ -56,7 +56,7 @@ describe("plugin API", function() {
expect(config).toBeObject();
expect(config.parser).toBeObject();
expect(config.parser.parse('start = "a"')).toBeObject();
expect(config.parser.parse("start = 'a'")).toBeObject();
expect(config.passes).toBeObject();
@ -95,24 +95,24 @@ describe("plugin API", function() {
let plugin = {
use: function(config) {
let parser = peg.generate([
'start = .* {',
' return {',
' type: "grammar",',
' rules: [',
' {',
' type: "rule",',
' name: "start",',
' expression: { type: "literal", value: text(), ignoreCase: false }',
' }',
' ]',
' };',
'}'
"start = .* {",
" return {",
" type: 'grammar',",
" rules: [",
" {",
" type: 'rule',",
" name: 'start',",
" expression: { type: 'literal', value: text(), ignoreCase: false }",
" }",
" ]",
" };",
"}"
].join("\n"));
config.parser = parser;
}
};
let parser = peg.generate('a', { plugins: [plugin] });
let parser = peg.generate("a", { plugins: [plugin] });
expect(parser.parse("a")).toBe("a");
});
@ -121,7 +121,7 @@ describe("plugin API", function() {
let plugin = {
use: function(config) {
let pass = ast => {
ast.code = '({ parse: function() { return 42; } })';
ast.code = "({ parse: function() { return 42; } })";
};
config.passes.generate = [pass];
@ -134,9 +134,9 @@ describe("plugin API", function() {
it("can change options", function() {
let grammar = [
'a = "x"',
'b = "x"',
'c = "x"'
"a = 'x'",
"b = 'x'",
"c = 'x'"
].join("\n");
let plugin = {
use: function(config, options) {

File diff suppressed because it is too large Load Diff

@ -16,9 +16,9 @@ describe("compiler pass |generateBytecode|", function() {
describe("for grammar", function() {
it("generates correct bytecode", function() {
expect(pass).toChangeAST([
'a = "a"',
'b = "b"',
'c = "c"'
"a = 'a'",
"b = 'b'",
"c = 'c'"
].join("\n"), {
rules: [
{ bytecode: [18, 0, 2, 2, 22, 0, 23, 1] },
@ -30,30 +30,30 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST([
'a = "a"',
'b = "b"',
'c = "c"'
"a = 'a'",
"b = 'b'",
"c = 'c'"
].join("\n"), constsDetails([
'"a"',
'peg$literalExpectation("a", false)',
'"b"',
'peg$literalExpectation("b", false)',
'"c"',
'peg$literalExpectation("c", false)'
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"\"b\"",
"peg$literalExpectation(\"b\", false)",
"\"c\"",
"peg$literalExpectation(\"c\", false)"
]));
});
});
describe("for rule", function() {
it("generates correct bytecode", function() {
expect(pass).toChangeAST('start = "a"', bytecodeDetails([
expect(pass).toChangeAST("start = 'a'", bytecodeDetails([
18, 0, 2, 2, 22, 0, 23, 1 // <expression>
]));
});
});
describe("for named", function() {
let grammar = 'start "start" = "a"';
let grammar = "start 'start' = 'a'";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -67,16 +67,16 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'peg$otherExpectation("start")',
'"a"',
'peg$literalExpectation("a", false)'
"peg$otherExpectation(\"start\")",
"\"a\"",
"peg$literalExpectation(\"a\", false)"
]));
});
});
describe("for choice", function() {
it("generates correct bytecode", function() {
expect(pass).toChangeAST('start = "a" / "b" / "c"', bytecodeDetails([
expect(pass).toChangeAST("start = 'a' / 'b' / 'c'", bytecodeDetails([
18, 0, 2, 2, 22, 0, 23, 1, // <alternatives[0]>
14, 21, 0, // IF_ERROR
6, // * POP
@ -90,7 +90,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for action", function() {
describe("without labels", function() {
let grammar = 'start = "a" { code }';
let grammar = "start = 'a' { code }";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -105,15 +105,15 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)',
'function() { code }'
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"function() { code }"
]));
});
});
describe("with one label", function() {
let grammar = 'start = a:"a" { code }';
let grammar = "start = a:'a' { code }";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -128,15 +128,15 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)',
'function(a) { code }'
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"function(a) { code }"
]));
});
});
describe("with multiple labels", function() {
let grammar = 'start = a:"a" b:"b" c:"c" { code }';
let grammar = "start = a:'a' b:'b' c:'c' { code }";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -164,20 +164,20 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)',
'"b"',
'peg$literalExpectation("b", false)',
'"c"',
'peg$literalExpectation("c", false)',
'function(a, b, c) { code }'
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"\"b\"",
"peg$literalExpectation(\"b\", false)",
"\"c\"",
"peg$literalExpectation(\"c\", false)",
"function(a, b, c) { code }"
]));
});
});
});
describe("for sequence", function() {
let grammar = 'start = "a" "b" "c"';
let grammar = "start = 'a' 'b' 'c'";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -204,19 +204,19 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)',
'"b"',
'peg$literalExpectation("b", false)',
'"c"',
'peg$literalExpectation("c", false)'
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"\"b\"",
"peg$literalExpectation(\"b\", false)",
"\"c\"",
"peg$literalExpectation(\"c\", false)"
]));
});
});
describe("for labeled", function() {
it("generates correct bytecode", function() {
expect(pass).toChangeAST('start = a:"a"', bytecodeDetails([
expect(pass).toChangeAST("start = a:'a'", bytecodeDetails([
18, 0, 2, 2, 22, 0, 23, 1 // <expression>
]));
});
@ -224,7 +224,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for text", function() {
it("generates correct bytecode", function() {
expect(pass).toChangeAST('start = $"a"', bytecodeDetails([
expect(pass).toChangeAST("start = $'a'", bytecodeDetails([
5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <expression>
15, 2, 1, // IF_NOT_ERROR
@ -236,7 +236,7 @@ describe("compiler pass |generateBytecode|", function() {
});
describe("for simple_and", function() {
let grammar = 'start = &"a"';
let grammar = "start = &'a'";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -256,14 +256,14 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)'
"\"a\"",
"peg$literalExpectation(\"a\", false)"
]));
});
});
describe("for simple_not", function() {
let grammar = 'start = !"a"';
let grammar = "start = !'a'";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -283,14 +283,14 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)'
"\"a\"",
"peg$literalExpectation(\"a\", false)"
]));
});
});
describe("for optional", function() {
let grammar = 'start = "a"?';
let grammar = "start = 'a'?";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -303,14 +303,14 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)'
"\"a\"",
"peg$literalExpectation(\"a\", false)"
]));
});
});
describe("for zero_or_more", function() {
let grammar = 'start = "a"*';
let grammar = "start = 'a'*";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -325,14 +325,14 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)'
"\"a\"",
"peg$literalExpectation(\"a\", false)"
]));
});
});
describe("for one_or_more", function() {
let grammar = 'start = "a"+';
let grammar = "start = 'a'+";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -351,15 +351,15 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)'
"\"a\"",
"peg$literalExpectation(\"a\", false)"
]));
});
});
describe("for group", function() {
it("generates correct bytecode", function() {
expect(pass).toChangeAST('start = ("a")', bytecodeDetails([
expect(pass).toChangeAST("start = ('a')", bytecodeDetails([
18, 0, 2, 2, 22, 0, 23, 1 // <expression>
]));
});
@ -367,7 +367,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for semantic_and", function() {
describe("without labels", function() {
let grammar = 'start = &{ code }';
let grammar = "start = &{ code }";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -384,13 +384,13 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(
grammar,
constsDetails(['function() { code }'])
constsDetails(["function() { code }"])
);
});
});
describe("with labels", function() {
let grammar = 'start = a:"a" b:"b" c:"c" &{ code }';
let grammar = "start = a:'a' b:'b' c:'c' &{ code }";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -428,13 +428,13 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)',
'"b"',
'peg$literalExpectation("b", false)',
'"c"',
'peg$literalExpectation("c", false)',
'function(a, b, c) { code }'
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"\"b\"",
"peg$literalExpectation(\"b\", false)",
"\"c\"",
"peg$literalExpectation(\"c\", false)",
"function(a, b, c) { code }"
]));
});
});
@ -442,7 +442,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for semantic_not", function() {
describe("without labels", function() {
let grammar = 'start = !{ code }';
let grammar = "start = !{ code }";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -459,13 +459,13 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(
grammar,
constsDetails(['function() { code }'])
constsDetails(["function() { code }"])
);
});
});
describe("with labels", function() {
let grammar = 'start = a:"a" b:"b" c:"c" !{ code }';
let grammar = "start = a:'a' b:'b' c:'c' !{ code }";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -503,13 +503,13 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)',
'"b"',
'peg$literalExpectation("b", false)',
'"c"',
'peg$literalExpectation("c", false)',
'function(a, b, c) { code }'
"\"a\"",
"peg$literalExpectation(\"a\", false)",
"\"b\"",
"peg$literalExpectation(\"b\", false)",
"\"c\"",
"peg$literalExpectation(\"c\", false)",
"function(a, b, c) { code }"
]));
});
});
@ -518,8 +518,8 @@ describe("compiler pass |generateBytecode|", function() {
describe("for rule_ref", function() {
it("generates correct bytecode", function() {
expect(pass).toChangeAST([
'start = other',
'other = "other"'
"start = other",
"other = 'other'"
].join("\n"), {
rules: [
{
@ -533,7 +533,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for literal", function() {
describe("empty", function() {
let grammar = 'start = ""';
let grammar = "start = ''";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -542,12 +542,12 @@ describe("compiler pass |generateBytecode|", function() {
});
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails(['""']));
expect(pass).toChangeAST(grammar, constsDetails(["\"\""]));
});
});
describe("non-empty case-sensitive", function() {
let grammar = 'start = "a"';
let grammar = "start = 'a'";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -559,14 +559,14 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("a", false)'
"\"a\"",
"peg$literalExpectation(\"a\", false)"
]));
});
});
describe("non-empty case-insensitive", function() {
let grammar = 'start = "A"i';
let grammar = "start = 'A'i";
it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -578,8 +578,8 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([
'"a"',
'peg$literalExpectation("A", true)'
"\"a\"",
"peg$literalExpectation(\"A\", true)"
]));
});
});
@ -587,7 +587,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for class", function() {
it("generates correct bytecode", function() {
expect(pass).toChangeAST('start = [a]', bytecodeDetails([
expect(pass).toChangeAST("start = [a]", bytecodeDetails([
20, 0, 2, 2, // MATCH_REGEXP
21, 1, // * ACCEPT_N
23, 1 // * FAIL
@ -596,43 +596,43 @@ describe("compiler pass |generateBytecode|", function() {
describe("non-inverted case-sensitive", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST('start = [a]', constsDetails([
'/^[a]/',
'peg$classExpectation(["a"], false, false)'
expect(pass).toChangeAST("start = [a]", constsDetails([
"/^[a]/",
"peg$classExpectation([\"a\"], false, false)"
]));
});
});
describe("inverted case-sensitive", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST('start = [^a]', constsDetails([
'/^[^a]/',
'peg$classExpectation(["a"], true, false)'
expect(pass).toChangeAST("start = [^a]", constsDetails([
"/^[^a]/",
"peg$classExpectation([\"a\"], true, false)"
]));
});
});
describe("non-inverted case-insensitive", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST('start = [a]i', constsDetails([
'/^[a]/i',
'peg$classExpectation(["a"], false, true)'
expect(pass).toChangeAST("start = [a]i", constsDetails([
"/^[a]/i",
"peg$classExpectation([\"a\"], false, true)"
]));
});
});
describe("complex", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST('start = [ab-def-hij-l]', constsDetails([
'/^[ab-def-hij-l]/',
'peg$classExpectation(["a", ["b", "d"], "e", ["f", "h"], "i", ["j", "l"]], false, false)'
expect(pass).toChangeAST("start = [ab-def-hij-l]", constsDetails([
"/^[ab-def-hij-l]/",
"peg$classExpectation([\"a\", [\"b\", \"d\"], \"e\", [\"f\", \"h\"], \"i\", [\"j\", \"l\"]], false, false)"
]));
});
});
});
describe("for any", function() {
let grammar = 'start = .';
let grammar = "start = .";
it("generates bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([
@ -645,7 +645,7 @@ describe("compiler pass |generateBytecode|", function() {
it("defines correct constants", function() {
expect(pass).toChangeAST(
grammar,
constsDetails(['peg$anyExpectation()'])
constsDetails(["peg$anyExpectation()"])
);
});
});

@ -9,9 +9,9 @@ describe("compiler pass |removeProxyRules|", function() {
it("updates references and removes it", function() {
expect(pass).toChangeAST(
[
'start = proxy',
'proxy = proxied',
'proxied = "a"'
"start = proxy",
"proxy = proxied",
"proxied = 'a'"
].join("\n"),
{
rules: [
@ -31,9 +31,9 @@ describe("compiler pass |removeProxyRules|", function() {
it("updates references but doesn't remove it", function() {
expect(pass).toChangeAST(
[
'start = proxy',
'proxy = proxied',
'proxied = "a"'
"start = proxy",
"proxy = proxied",
"proxied = 'a'"
].join("\n"),
{
rules: [

@ -7,8 +7,8 @@ describe("compiler pass |reportDuplicateLabels|", function() {
describe("in a sequence", function() {
it("reports labels duplicate with labels of preceding elements", function() {
expect(pass).toReportError('start = a:"a" a:"a"', {
message: 'Label "a" is already defined at line 1, column 9.',
expect(pass).toReportError("start = a:'a' a:'a'", {
message: "Label \"a\" is already defined at line 1, column 9.",
location: {
start: { offset: 14, line: 1, column: 15 },
end: { offset: 19, line: 1, column: 20 }
@ -17,30 +17,30 @@ describe("compiler pass |reportDuplicateLabels|", function() {
});
it("doesn't report labels duplicate with labels in subexpressions", function() {
expect(pass).not.toReportError('start = ("a" / a:"a" / "a") a:"a"');
expect(pass).not.toReportError('start = (a:"a" { }) a:"a"');
expect(pass).not.toReportError('start = ("a" a:"a" "a") a:"a"');
expect(pass).not.toReportError('start = b:(a:"a") a:"a"');
expect(pass).not.toReportError('start = $(a:"a") a:"a"');
expect(pass).not.toReportError('start = &(a:"a") a:"a"');
expect(pass).not.toReportError('start = !(a:"a") a:"a"');
expect(pass).not.toReportError('start = (a:"a")? a:"a"');
expect(pass).not.toReportError('start = (a:"a")* a:"a"');
expect(pass).not.toReportError('start = (a:"a")+ a:"a"');
expect(pass).not.toReportError('start = (a:"a") a:"a"');
expect(pass).not.toReportError("start = ('a' / a:'a' / 'a') a:'a'");
expect(pass).not.toReportError("start = (a:'a' { }) a:'a'");
expect(pass).not.toReportError("start = ('a' a:'a' 'a') a:'a'");
expect(pass).not.toReportError("start = b:(a:'a') a:'a'");
expect(pass).not.toReportError("start = $(a:'a') a:'a'");
expect(pass).not.toReportError("start = &(a:'a') a:'a'");
expect(pass).not.toReportError("start = !(a:'a') a:'a'");
expect(pass).not.toReportError("start = (a:'a')? a:'a'");
expect(pass).not.toReportError("start = (a:'a')* a:'a'");
expect(pass).not.toReportError("start = (a:'a')+ a:'a'");
expect(pass).not.toReportError("start = (a:'a') a:'a'");
});
});
describe("in a choice", function() {
it("doesn't report labels duplicate with labels of preceding alternatives", function() {
expect(pass).not.toReportError('start = a:"a" / a:"a"');
expect(pass).not.toReportError("start = a:'a' / a:'a'");
});
});
describe("in outer sequence", function() {
it("reports labels duplicate with labels of preceding elements", function() {
expect(pass).toReportError('start = a:"a" (a:"a")', {
message: 'Label "a" is already defined at line 1, column 9.',
expect(pass).toReportError("start = a:'a' (a:'a')", {
message: "Label \"a\" is already defined at line 1, column 9.",
location: {
start: { offset: 15, line: 1, column: 16 },
end: { offset: 20, line: 1, column: 21 }
@ -49,11 +49,11 @@ describe("compiler pass |reportDuplicateLabels|", function() {
});
it("doesn't report labels duplicate with the label of the current element", function() {
expect(pass).not.toReportError('start = a:(a:"a")');
expect(pass).not.toReportError("start = a:(a:'a')");
});
it("doesn't report labels duplicate with labels of following elements", function() {
expect(pass).not.toReportError('start = (a:"a") a:"a"');
expect(pass).not.toReportError("start = (a:'a') a:'a'");
});
});
});

@ -7,10 +7,10 @@ describe("compiler pass |reportDuplicateRules|", function() {
it("reports duplicate rules", function() {
expect(pass).toReportError([
'start = "a"',
'start = "b"'
].join('\n'), {
message: 'Rule "start" is already defined at line 1, column 1.',
"start = 'a'",
"start = 'b'"
].join("\n"), {
message: "Rule \"start\" is already defined at line 1, column 1.",
location: {
start: { offset: 12, line: 2, column: 1 },
end: { offset: 23, line: 2, column: 12 }

@ -6,8 +6,8 @@ describe("compiler pass |reportInfiniteRecursion|", function() {
let pass = peg.compiler.passes.check.reportInfiniteRecursion;
it("reports direct left recursion", function() {
expect(pass).toReportError('start = start', {
message: 'Possible infinite loop when parsing (left recursion: start -> start).',
expect(pass).toReportError("start = start", {
message: "Possible infinite loop when parsing (left recursion: start -> start).",
location: {
start: { offset: 8, line: 1, column: 9 },
end: { offset: 13, line: 1, column: 14 }
@ -17,10 +17,10 @@ describe("compiler pass |reportInfiniteRecursion|", function() {
it("reports indirect left recursion", function() {
expect(pass).toReportError([
'start = stop',
'stop = start'
"start = stop",
"stop = start"
].join("\n"), {
message: 'Possible infinite loop when parsing (left recursion: start -> stop -> start).',
message: "Possible infinite loop when parsing (left recursion: start -> stop -> start).",
location: {
start: { offset: 21, line: 2, column: 9 },
end: { offset: 26, line: 2, column: 14 }
@ -30,86 +30,86 @@ describe("compiler pass |reportInfiniteRecursion|", function() {
describe("in sequences", function() {
it("reports left recursion if all preceding elements match empty string", function() {
expect(pass).toReportError('start = "" "" "" start');
expect(pass).toReportError("start = '' '' '' start");
});
it("doesn't report left recursion if some preceding element doesn't match empty string", function() {
expect(pass).not.toReportError('start = "a" "" "" start');
expect(pass).not.toReportError('start = "" "a" "" start');
expect(pass).not.toReportError('start = "" "" "a" start');
expect(pass).not.toReportError("start = 'a' '' '' start");
expect(pass).not.toReportError("start = '' 'a' '' start");
expect(pass).not.toReportError("start = '' '' 'a' start");
});
// Regression test for #359.
it("reports left recursion when rule reference is wrapped in an expression", function() {
expect(pass).toReportError('start = "" start?');
expect(pass).toReportError("start = '' start?");
});
it("computes expressions that always consume input on success correctly", function() {
expect(pass).toReportError([
'start = a start',
'a "a" = ""'
].join('\n'));
"start = a start",
"a 'a' = ''"
].join("\n"));
expect(pass).not.toReportError([
'start = a start',
'a "a" = "a"'
].join('\n'));
"start = a start",
"a 'a' = 'a'"
].join("\n"));
expect(pass).toReportError('start = ("" / "a" / "b") start');
expect(pass).toReportError('start = ("a" / "" / "b") start');
expect(pass).toReportError('start = ("a" / "b" / "") start');
expect(pass).not.toReportError('start = ("a" / "b" / "c") start');
expect(pass).toReportError("start = ('' / 'a' / 'b') start");
expect(pass).toReportError("start = ('a' / '' / 'b') start");
expect(pass).toReportError("start = ('a' / 'b' / '') start");
expect(pass).not.toReportError("start = ('a' / 'b' / 'c') start");
expect(pass).toReportError('start = ("" { }) start');
expect(pass).not.toReportError('start = ("a" { }) start');
expect(pass).toReportError("start = ('' { }) start");
expect(pass).not.toReportError("start = ('a' { }) start");
expect(pass).toReportError('start = ("" "" "") start');
expect(pass).not.toReportError('start = ("a" "" "") start');
expect(pass).not.toReportError('start = ("" "a" "") start');
expect(pass).not.toReportError('start = ("" "" "a") start');
expect(pass).toReportError("start = ('' '' '') start");
expect(pass).not.toReportError("start = ('a' '' '') start");
expect(pass).not.toReportError("start = ('' 'a' '') start");
expect(pass).not.toReportError("start = ('' '' 'a') start");
expect(pass).toReportError('start = a:"" start');
expect(pass).not.toReportError('start = a:"a" start');
expect(pass).toReportError("start = a:'' start");
expect(pass).not.toReportError("start = a:'a' start");
expect(pass).toReportError('start = $"" start');
expect(pass).not.toReportError('start = $"a" start');
expect(pass).toReportError("start = $'' start");
expect(pass).not.toReportError("start = $'a' start");
expect(pass).toReportError('start = &"" start');
expect(pass).toReportError('start = &"a" start');
expect(pass).toReportError("start = &'' start");
expect(pass).toReportError("start = &'a' start");
expect(pass).toReportError('start = !"" start');
expect(pass).toReportError('start = !"a" start');
expect(pass).toReportError("start = !'' start");
expect(pass).toReportError("start = !'a' start");
expect(pass).toReportError('start = ""? start');
expect(pass).toReportError('start = "a"? start');
expect(pass).toReportError("start = ''? start");
expect(pass).toReportError("start = 'a'? start");
expect(pass).toReportError('start = ""* start');
expect(pass).toReportError('start = "a"* start');
expect(pass).toReportError("start = ''* start");
expect(pass).toReportError("start = 'a'* start");
expect(pass).toReportError('start = ""+ start');
expect(pass).not.toReportError('start = "a"+ start');
expect(pass).toReportError("start = ''+ start");
expect(pass).not.toReportError("start = 'a'+ start");
expect(pass).toReportError('start = ("") start');
expect(pass).not.toReportError('start = ("a") start');
expect(pass).toReportError("start = ('') start");
expect(pass).not.toReportError("start = ('a') start");
expect(pass).toReportError('start = &{ } start');
expect(pass).toReportError("start = &{ } start");
expect(pass).toReportError('start = !{ } start');
expect(pass).toReportError("start = !{ } start");
expect(pass).toReportError([
'start = a start',
'a = ""'
].join('\n'));
"start = a start",
"a = ''"
].join("\n"));
expect(pass).not.toReportError([
'start = a start',
'a = "a"'
].join('\n'));
"start = a start",
"a = 'a'"
].join("\n"));
expect(pass).toReportError('start = "" start');
expect(pass).not.toReportError('start = "a" start');
expect(pass).toReportError("start = '' start");
expect(pass).not.toReportError("start = 'a' start");
expect(pass).not.toReportError('start = [a-d] start');
expect(pass).not.toReportError("start = [a-d] start");
expect(pass).not.toReportError('start = . start');
expect(pass).not.toReportError("start = . start");
});
});
});

@ -6,7 +6,7 @@ describe("compiler pass |reportInfiniteRepetition|", function() {
let pass = peg.compiler.passes.check.reportInfiniteRepetition;
it("reports infinite loops for zero_or_more", function() {
expect(pass).toReportError('start = ("")*', {
expect(pass).toReportError("start = ('')*", {
message: "Possible infinite loop when parsing (repetition used with an expression that may not consume any input).",
location: {
start: { offset: 8, line: 1, column: 9 },
@ -16,7 +16,7 @@ describe("compiler pass |reportInfiniteRepetition|", function() {
});
it("reports infinite loops for one_or_more", function() {
expect(pass).toReportError('start = ("")+', {
expect(pass).toReportError("start = ('')+", {
message: "Possible infinite loop when parsing (repetition used with an expression that may not consume any input).",
location: {
start: { offset: 8, line: 1, column: 9 },
@ -27,69 +27,69 @@ describe("compiler pass |reportInfiniteRepetition|", function() {
it("computes expressions that always consume input on success correctly", function() {
expect(pass).toReportError([
'start = a*',
'a "a" = ""'
].join('\n'));
"start = a*",
"a 'a' = ''"
].join("\n"));
expect(pass).not.toReportError([
'start = a*',
'a "a" = "a"'
].join('\n'));
"start = a*",
"a 'a' = 'a'"
].join("\n"));
expect(pass).toReportError('start = ("" / "a" / "b")*');
expect(pass).toReportError('start = ("a" / "" / "b")*');
expect(pass).toReportError('start = ("a" / "b" / "")*');
expect(pass).not.toReportError('start = ("a" / "b" / "c")*');
expect(pass).toReportError("start = ('' / 'a' / 'b')*");
expect(pass).toReportError("start = ('a' / '' / 'b')*");
expect(pass).toReportError("start = ('a' / 'b' / '')*");
expect(pass).not.toReportError("start = ('a' / 'b' / 'c')*");
expect(pass).toReportError('start = ("" { })*');
expect(pass).not.toReportError('start = ("a" { })*');
expect(pass).toReportError("start = ('' { })*");
expect(pass).not.toReportError("start = ('a' { })*");
expect(pass).toReportError('start = ("" "" "")*');
expect(pass).not.toReportError('start = ("a" "" "")*');
expect(pass).not.toReportError('start = ("" "a" "")*');
expect(pass).not.toReportError('start = ("" "" "a")*');
expect(pass).toReportError("start = ('' '' '')*");
expect(pass).not.toReportError("start = ('a' '' '')*");
expect(pass).not.toReportError("start = ('' 'a' '')*");
expect(pass).not.toReportError("start = ('' '' 'a')*");
expect(pass).toReportError('start = (a:"")*');
expect(pass).not.toReportError('start = (a:"a")*');
expect(pass).toReportError("start = (a:'')*");
expect(pass).not.toReportError("start = (a:'a')*");
expect(pass).toReportError('start = ($"")*');
expect(pass).not.toReportError('start = ($"a")*');
expect(pass).toReportError("start = ($'')*");
expect(pass).not.toReportError("start = ($'a')*");
expect(pass).toReportError('start = (&"")*');
expect(pass).toReportError('start = (&"a")*');
expect(pass).toReportError("start = (&'')*");
expect(pass).toReportError("start = (&'a')*");
expect(pass).toReportError('start = (!"")*');
expect(pass).toReportError('start = (!"a")*');
expect(pass).toReportError("start = (!'')*");
expect(pass).toReportError("start = (!'a')*");
expect(pass).toReportError('start = (""?)*');
expect(pass).toReportError('start = ("a"?)*');
expect(pass).toReportError("start = (''?)*");
expect(pass).toReportError("start = ('a'?)*");
expect(pass).toReportError('start = (""*)*');
expect(pass).toReportError('start = ("a"*)*');
expect(pass).toReportError("start = (''*)*");
expect(pass).toReportError("start = ('a'*)*");
expect(pass).toReportError('start = (""+)*');
expect(pass).not.toReportError('start = ("a"+)*');
expect(pass).toReportError("start = (''+)*");
expect(pass).not.toReportError("start = ('a'+)*");
expect(pass).toReportError('start = ("")*');
expect(pass).not.toReportError('start = ("a")*');
expect(pass).toReportError("start = ('')*");
expect(pass).not.toReportError("start = ('a')*");
expect(pass).toReportError('start = (&{ })*');
expect(pass).toReportError("start = (&{ })*");
expect(pass).toReportError('start = (!{ })*');
expect(pass).toReportError("start = (!{ })*");
expect(pass).toReportError([
'start = a*',
'a = ""'
].join('\n'));
"start = a*",
"a = ''"
].join("\n"));
expect(pass).not.toReportError([
'start = a*',
'a = "a"'
].join('\n'));
"start = a*",
"a = 'a'"
].join("\n"));
expect(pass).toReportError('start = ""*');
expect(pass).not.toReportError('start = "a"*');
expect(pass).toReportError("start = ''*");
expect(pass).not.toReportError("start = 'a'*");
expect(pass).not.toReportError('start = [a-d]*');
expect(pass).not.toReportError("start = [a-d]*");
expect(pass).not.toReportError('start = .*');
expect(pass).not.toReportError("start = .*");
});
});

@ -6,8 +6,8 @@ describe("compiler pass |reportUndefinedRules|", function() {
let pass = peg.compiler.passes.check.reportUndefinedRules;
it("reports undefined rules", function() {
expect(pass).toReportError('start = undefined', {
message: 'Rule "undefined" is not defined.',
expect(pass).toReportError("start = undefined", {
message: "Rule \"undefined\" is not defined.",
location: {
start: { offset: 8, line: 1, column: 9 },
end: { offset: 17, line: 1, column: 18 }

@ -236,252 +236,252 @@ describe("PEG.js grammar parser", function() {
});
});
// Canonical Grammar is "a = \"abcd\"; b = \"efgh\"; c = \"ijkl\";".
// Canonical Grammar is "a = 'abcd'; b = 'efgh'; c = 'ijkl';".
it("parses Grammar", function() {
expect('\na = "abcd";\n').toParseAs(
expect("\na = 'abcd';\n").toParseAs(
{ type: "grammar", initializer: null, rules: [ruleA] }
);
expect('\na = "abcd";\nb = "efgh";\nc = "ijkl";\n').toParseAs(
expect("\na = 'abcd';\nb = 'efgh';\nc = 'ijkl';\n").toParseAs(
{ type: "grammar", initializer: null, rules: [ruleA, ruleB, ruleC] }
);
expect('\n{ code };\na = "abcd";\n').toParseAs(
expect("\n{ code };\na = 'abcd';\n").toParseAs(
{ type: "grammar", initializer: initializer, rules: [ruleA] }
);
});
// Canonical Initializer is "{ code }".
it("parses Initializer", function() {
expect('{ code };start = "abcd"').toParseAs(
expect("{ code };start = 'abcd'").toParseAs(
{ type: "grammar", initializer: initializer, rules: [ruleStart] }
);
});
// Canonical Rule is "a = \"abcd\";".
// Canonical Rule is "a = 'abcd';".
it("parses Rule", function() {
expect('start\n=\n"abcd";').toParseAs(
expect("start\n=\n'abcd';").toParseAs(
oneRuleGrammar(literalAbcd)
);
expect('start\n"start rule"\n=\n"abcd";').toParseAs(
expect("start\n'start rule'\n=\n'abcd';").toParseAs(
oneRuleGrammar(named)
);
});
// Canonical Expression is "\"abcd\"".
// Canonical Expression is "'abcd'".
it("parses Expression", function() {
expect('start = "abcd" / "efgh" / "ijkl"').toParseAs(
expect("start = 'abcd' / 'efgh' / 'ijkl'").toParseAs(
oneRuleGrammar(choice)
);
});
// Canonical ChoiceExpression is "\"abcd\" / \"efgh\" / \"ijkl\"".
// Canonical ChoiceExpression is "'abcd' / 'efgh' / 'ijkl'".
it("parses ChoiceExpression", function() {
expect('start = "abcd" { code }').toParseAs(
expect("start = 'abcd' { code }").toParseAs(
oneRuleGrammar(actionAbcd)
);
expect('start = "abcd" { code }\n/\n"efgh" { code }').toParseAs(
expect("start = 'abcd' { code }\n/\n'efgh' { code }").toParseAs(
oneRuleGrammar(choice2)
);
expect(
'start = "abcd" { code }\n/\n"efgh" { code }\n/\n"ijkl" { code }\n/\n"mnop" { code }'
"start = 'abcd' { code }\n/\n'efgh' { code }\n/\n'ijkl' { code }\n/\n'mnop' { code }"
).toParseAs(
oneRuleGrammar(choice4)
);
});
// Canonical ActionExpression is "\"abcd\" { code }".
// Canonical ActionExpression is "'abcd' { code }".
it("parses ActionExpression", function() {
expect('start = "abcd" "efgh" "ijkl"').toParseAs(
expect("start = 'abcd' 'efgh' 'ijkl'").toParseAs(
oneRuleGrammar(sequence)
);
expect('start = "abcd" "efgh" "ijkl"\n{ code }').toParseAs(
expect("start = 'abcd' 'efgh' 'ijkl'\n{ code }").toParseAs(
oneRuleGrammar(actionSequence)
);
});
// Canonical SequenceExpression is "\"abcd\" \"efgh\" \"ijkl\"".
// Canonical SequenceExpression is "'abcd' 'efgh' 'ijkl'".
it("parses SequenceExpression", function() {
expect('start = a:"abcd"').toParseAs(
expect("start = a:'abcd'").toParseAs(
oneRuleGrammar(labeledAbcd)
);
expect('start = a:"abcd"\nb:"efgh"').toParseAs(
expect("start = a:'abcd'\nb:'efgh'").toParseAs(
oneRuleGrammar(sequence2)
);
expect('start = a:"abcd"\nb:"efgh"\nc:"ijkl"\nd:"mnop"').toParseAs(
expect("start = a:'abcd'\nb:'efgh'\nc:'ijkl'\nd:'mnop'").toParseAs(
oneRuleGrammar(sequence4)
);
});
// Canonical LabeledExpression is "a:\"abcd\"".
// Canonical LabeledExpression is "a:'abcd'".
it("parses LabeledExpression", function() {
expect('start = a\n:\n!"abcd"').toParseAs(oneRuleGrammar(labeledSimpleNot));
expect('start = !"abcd"' ).toParseAs(oneRuleGrammar(simpleNotAbcd));
expect("start = a\n:\n!'abcd'").toParseAs(oneRuleGrammar(labeledSimpleNot));
expect("start = !'abcd'" ).toParseAs(oneRuleGrammar(simpleNotAbcd));
});
// Canonical PrefixedExpression is "!\"abcd\"".
// Canonical PrefixedExpression is "!'abcd'".
it("parses PrefixedExpression", function() {
expect('start = !\n"abcd"?' ).toParseAs(oneRuleGrammar(simpleNotOptional));
expect('start = "abcd"?' ).toParseAs(oneRuleGrammar(optional));
expect("start = !\n'abcd'?" ).toParseAs(oneRuleGrammar(simpleNotOptional));
expect("start = 'abcd'?" ).toParseAs(oneRuleGrammar(optional));
});
// Canonical PrefixedOperator is "!".
it("parses PrefixedOperator", function() {
expect('start = $"abcd"?').toParseAs(oneRuleGrammar(textOptional));
expect('start = &"abcd"?').toParseAs(oneRuleGrammar(simpleAndOptional));
expect('start = !"abcd"?').toParseAs(oneRuleGrammar(simpleNotOptional));
expect("start = $'abcd'?").toParseAs(oneRuleGrammar(textOptional));
expect("start = &'abcd'?").toParseAs(oneRuleGrammar(simpleAndOptional));
expect("start = !'abcd'?").toParseAs(oneRuleGrammar(simpleNotOptional));
});
// Canonical SuffixedExpression is "\"ebcd\"?".
// Canonical SuffixedExpression is "'ebcd'?".
it("parses SuffixedExpression", function() {
expect('start = "abcd"\n?').toParseAs(oneRuleGrammar(optional));
expect('start = "abcd"' ).toParseAs(oneRuleGrammar(literalAbcd));
expect("start = 'abcd'\n?").toParseAs(oneRuleGrammar(optional));
expect("start = 'abcd'" ).toParseAs(oneRuleGrammar(literalAbcd));
});
// Canonical SuffixedOperator is "?".
it("parses SuffixedOperator", function() {
expect('start = "abcd"?').toParseAs(oneRuleGrammar(optional));
expect('start = "abcd"*').toParseAs(oneRuleGrammar(zeroOrMore));
expect('start = "abcd"+').toParseAs(oneRuleGrammar(oneOrMore));
expect("start = 'abcd'?").toParseAs(oneRuleGrammar(optional));
expect("start = 'abcd'*").toParseAs(oneRuleGrammar(zeroOrMore));
expect("start = 'abcd'+").toParseAs(oneRuleGrammar(oneOrMore));
});
// Canonical PrimaryExpression is "\"abcd\"".
// Canonical PrimaryExpression is "'abcd'".
it("parses PrimaryExpression", function() {
expect('start = "abcd"' ).toParseAs(trivialGrammar);
expect('start = [a-d]' ).toParseAs(classGrammar([["a", "d"]], false, false));
expect('start = .' ).toParseAs(anyGrammar());
expect('start = a' ).toParseAs(ruleRefGrammar("a"));
expect('start = &{ code }').toParseAs(oneRuleGrammar(semanticAnd));
expect("start = 'abcd'" ).toParseAs(trivialGrammar);
expect("start = [a-d]" ).toParseAs(classGrammar([["a", "d"]], false, false));
expect("start = ." ).toParseAs(anyGrammar());
expect("start = a" ).toParseAs(ruleRefGrammar("a"));
expect("start = &{ code }").toParseAs(oneRuleGrammar(semanticAnd));
expect('start = (\na:"abcd"\n)' ).toParseAs(oneRuleGrammar(groupLabeled));
expect('start = (\n"abcd" "efgh" "ijkl"\n)').toParseAs(oneRuleGrammar(groupSequence));
expect('start = (\n"abcd"\n)' ).toParseAs(trivialGrammar);
expect("start = (\na:'abcd'\n)" ).toParseAs(oneRuleGrammar(groupLabeled));
expect("start = (\n'abcd' 'efgh' 'ijkl'\n)").toParseAs(oneRuleGrammar(groupSequence));
expect("start = (\n'abcd'\n)" ).toParseAs(trivialGrammar);
});
// Canonical RuleReferenceExpression is "a".
it("parses RuleReferenceExpression", function() {
expect('start = a').toParseAs(ruleRefGrammar("a"));
expect("start = a").toParseAs(ruleRefGrammar("a"));
expect('start = a\n=' ).toFailToParse();
expect('start = a\n"abcd"\n=').toFailToParse();
expect("start = a\n=" ).toFailToParse();
expect("start = a\n'abcd'\n=").toFailToParse();
});
// Canonical SemanticPredicateExpression is "!{ code }".
it("parses SemanticPredicateExpression", function() {
expect('start = !\n{ code }').toParseAs(oneRuleGrammar(semanticNot));
expect("start = !\n{ code }").toParseAs(oneRuleGrammar(semanticNot));
});
// Canonical SemanticPredicateOperator is "!".
it("parses SemanticPredicateOperator", function() {
expect('start = &{ code }').toParseAs(oneRuleGrammar(semanticAnd));
expect('start = !{ code }').toParseAs(oneRuleGrammar(semanticNot));
expect("start = &{ code }").toParseAs(oneRuleGrammar(semanticAnd));
expect("start = !{ code }").toParseAs(oneRuleGrammar(semanticNot));
});
// The SourceCharacter rule is not tested.
// Canonical WhiteSpace is " ".
it("parses WhiteSpace", function() {
expect('start =\t"abcd"' ).toParseAs(trivialGrammar);
expect('start =\v"abcd"' ).toParseAs(trivialGrammar);
expect('start =\f"abcd"' ).toParseAs(trivialGrammar);
expect('start = "abcd"' ).toParseAs(trivialGrammar);
expect('start =\u00A0"abcd"').toParseAs(trivialGrammar);
expect('start =\uFEFF"abcd"').toParseAs(trivialGrammar);
expect('start =\u1680"abcd"').toParseAs(trivialGrammar);
expect("start =\t'abcd'" ).toParseAs(trivialGrammar);
expect("start =\v'abcd'" ).toParseAs(trivialGrammar);
expect("start =\f'abcd'" ).toParseAs(trivialGrammar);
expect("start = 'abcd'" ).toParseAs(trivialGrammar);
expect("start =\u00A0'abcd'").toParseAs(trivialGrammar);
expect("start =\uFEFF'abcd'").toParseAs(trivialGrammar);
expect("start =\u1680'abcd'").toParseAs(trivialGrammar);
});
// Canonical LineTerminator is "\n".
it("parses LineTerminator", function() {
expect('start = "\n"' ).toFailToParse();
expect('start = "\r"' ).toFailToParse();
expect('start = "\u2028"').toFailToParse();
expect('start = "\u2029"').toFailToParse();
expect("start = '\n'" ).toFailToParse();
expect("start = '\r'" ).toFailToParse();
expect("start = '\u2028'").toFailToParse();
expect("start = '\u2029'").toFailToParse();
});
// Canonical LineTerminatorSequence is "\r\n".
it("parses LineTerminatorSequence", function() {
expect('start =\n"abcd"' ).toParseAs(trivialGrammar);
expect('start =\r\n"abcd"' ).toParseAs(trivialGrammar);
expect('start =\r"abcd"' ).toParseAs(trivialGrammar);
expect('start =\u2028"abcd"').toParseAs(trivialGrammar);
expect('start =\u2029"abcd"').toParseAs(trivialGrammar);
expect("start =\n'abcd'" ).toParseAs(trivialGrammar);
expect("start =\r\n'abcd'" ).toParseAs(trivialGrammar);
expect("start =\r'abcd'" ).toParseAs(trivialGrammar);
expect("start =\u2028'abcd'").toParseAs(trivialGrammar);
expect("start =\u2029'abcd'").toParseAs(trivialGrammar);
});
// Canonical Comment is "/* comment */".
it("parses Comment", function() {
expect('start =// comment\n"abcd"' ).toParseAs(trivialGrammar);
expect('start =/* comment */"abcd"').toParseAs(trivialGrammar);
expect("start =// comment\n'abcd'" ).toParseAs(trivialGrammar);
expect("start =/* comment */'abcd'").toParseAs(trivialGrammar);
});
// Canonical MultiLineComment is "/* comment */".
it("parses MultiLineComment", function() {
expect('start =/**/"abcd"' ).toParseAs(trivialGrammar);
expect('start =/*a*/"abcd"' ).toParseAs(trivialGrammar);
expect('start =/*abc*/"abcd"').toParseAs(trivialGrammar);
expect("start =/**/'abcd'" ).toParseAs(trivialGrammar);
expect("start =/*a*/'abcd'" ).toParseAs(trivialGrammar);
expect("start =/*abc*/'abcd'").toParseAs(trivialGrammar);
expect('start =/**/*/"abcd"').toFailToParse();
expect("start =/**/*/'abcd'").toFailToParse();
});
// Canonical MultiLineCommentNoLineTerminator is "/* comment */".
it("parses MultiLineCommentNoLineTerminator", function() {
expect('a = "abcd"/**/\r\nb = "efgh"' ).toParseAs(twoRuleGrammar);
expect('a = "abcd"/*a*/\r\nb = "efgh"' ).toParseAs(twoRuleGrammar);
expect('a = "abcd"/*abc*/\r\nb = "efgh"').toParseAs(twoRuleGrammar);
expect("a = 'abcd'/**/\r\nb = 'efgh'" ).toParseAs(twoRuleGrammar);
expect("a = 'abcd'/*a*/\r\nb = 'efgh'" ).toParseAs(twoRuleGrammar);
expect("a = 'abcd'/*abc*/\r\nb = 'efgh'").toParseAs(twoRuleGrammar);
expect('a = "abcd"/**/*/\r\nb = "efgh"').toFailToParse();
expect('a = "abcd"/*\n*/\r\nb = "efgh"').toFailToParse();
expect("a = 'abcd'/**/*/\r\nb = 'efgh'").toFailToParse();
expect("a = 'abcd'/*\n*/\r\nb = 'efgh'").toFailToParse();
});
// Canonical SingleLineComment is "// comment".
it("parses SingleLineComment", function() {
expect('start =//\n"abcd"' ).toParseAs(trivialGrammar);
expect('start =//a\n"abcd"' ).toParseAs(trivialGrammar);
expect('start =//abc\n"abcd"').toParseAs(trivialGrammar);
expect("start =//\n'abcd'" ).toParseAs(trivialGrammar);
expect("start =//a\n'abcd'" ).toParseAs(trivialGrammar);
expect("start =//abc\n'abcd'").toParseAs(trivialGrammar);
expect('start =//\n@\n"abcd"').toFailToParse();
expect("start =//\n@\n'abcd'").toFailToParse();
});
// Canonical Identifier is "a".
it("parses Identifier", function() {
expect('start = a:"abcd"').toParseAs(oneRuleGrammar(labeledAbcd));
expect("start = a:'abcd'").toParseAs(oneRuleGrammar(labeledAbcd));
});
// Canonical IdentifierName is "a".
it("parses IdentifierName", function() {
expect('start = a' ).toParseAs(ruleRefGrammar("a"));
expect('start = ab' ).toParseAs(ruleRefGrammar("ab"));
expect('start = abcd').toParseAs(ruleRefGrammar("abcd"));
expect("start = a" ).toParseAs(ruleRefGrammar("a"));
expect("start = ab" ).toParseAs(ruleRefGrammar("ab"));
expect("start = abcd").toParseAs(ruleRefGrammar("abcd"));
});
// Canonical IdentifierStart is "a".
it("parses IdentifierStart", function() {
expect('start = a' ).toParseAs(ruleRefGrammar("a"));
expect('start = $' ).toParseAs(ruleRefGrammar("$"));
expect('start = _' ).toParseAs(ruleRefGrammar("_"));
expect('start = \\u0061').toParseAs(ruleRefGrammar("a"));
expect("start = a" ).toParseAs(ruleRefGrammar("a"));
expect("start = $" ).toParseAs(ruleRefGrammar("$"));
expect("start = _" ).toParseAs(ruleRefGrammar("_"));
expect("start = \\u0061").toParseAs(ruleRefGrammar("a"));
});
// Canonical IdentifierPart is "a".
it("parses IdentifierPart", function() {
expect('start = aa' ).toParseAs(ruleRefGrammar("aa"));
expect('start = a\u0300').toParseAs(ruleRefGrammar("a\u0300"));
expect('start = a0' ).toParseAs(ruleRefGrammar("a0"));
expect('start = a\u203F').toParseAs(ruleRefGrammar("a\u203F"));
expect('start = a\u200C').toParseAs(ruleRefGrammar("a\u200C"));
expect('start = a\u200D').toParseAs(ruleRefGrammar("a\u200D"));
expect("start = aa" ).toParseAs(ruleRefGrammar("aa"));
expect("start = a\u0300").toParseAs(ruleRefGrammar("a\u0300"));
expect("start = a0" ).toParseAs(ruleRefGrammar("a0"));
expect("start = a\u203F").toParseAs(ruleRefGrammar("a\u203F"));
expect("start = a\u200C").toParseAs(ruleRefGrammar("a\u200C"));
expect("start = a\u200D").toParseAs(ruleRefGrammar("a\u200D"));
});
// Unicode rules and reserved word rules are not tested.
// Canonical LiteralMatcher is "\"abcd\"".
// 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));
expect("start = 'abcd'i").toParseAs(literalGrammar("abcd", true));
});
// Canonical StringLiteral is "\"abcd\"".
// 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));
expect("start = \"abc\"").toParseAs(literalGrammar("abc", false));
expect("start = ''" ).toParseAs(literalGrammar("", false));
expect("start = 'a'" ).toParseAs(literalGrammar("a", false));
@ -490,13 +490,13 @@ describe("PEG.js grammar parser", function() {
// 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));
expect("start = \"\\n\"" ).toParseAs(literalGrammar("\n", false));
expect("start = \"\\\n\"").toParseAs(literalGrammar("", false));
expect('start = """' ).toFailToParse();
expect('start = "\\"').toFailToParse();
expect('start = "\n"').toFailToParse();
expect("start = \"\"\"").toFailToParse();
expect("start = \"\\\"").toFailToParse();
expect("start = \"\n\"").toFailToParse();
});
// Canonical SingleStringCharacter is "a".
@ -512,92 +512,92 @@ describe("PEG.js grammar parser", function() {
// Canonical CharacterClassMatcher is "[a-d]".
it("parses CharacterClassMatcher", function() {
expect('start = []').toParseAs(
expect("start = []").toParseAs(
classGrammar([], false, false)
);
expect('start = [a-d]').toParseAs(
expect("start = [a-d]").toParseAs(
classGrammar([["a", "d"]], false, false)
);
expect('start = [a]').toParseAs(
expect("start = [a]").toParseAs(
classGrammar(["a"], false, false)
);
expect('start = [a-de-hi-l]').toParseAs(
expect("start = [a-de-hi-l]").toParseAs(
classGrammar(
[["a", "d"], ["e", "h"], ["i", "l"]],
false,
false
)
);
expect('start = [^a-d]').toParseAs(
expect("start = [^a-d]").toParseAs(
classGrammar([["a", "d"]], true, false)
);
expect('start = [a-d]i').toParseAs(
expect("start = [a-d]i").toParseAs(
classGrammar([["a", "d"]], false, true)
);
expect('start = [\\\n]').toParseAs(
expect("start = [\\\n]").toParseAs(
classGrammar([], false, false)
);
});
// Canonical ClassCharacterRange is "a-d".
it("parses ClassCharacterRange", function() {
expect('start = [a-d]').toParseAs(classGrammar([["a", "d"]], false, false));
expect("start = [a-d]").toParseAs(classGrammar([["a", "d"]], false, false));
expect('start = [a-a]').toParseAs(classGrammar([["a", "a"]], false, false));
expect('start = [b-a]').toFailToParse({
expect("start = [a-a]").toParseAs(classGrammar([["a", "a"]], false, false));
expect("start = [b-a]").toFailToParse({
message: "Invalid character range: b-a."
});
});
// Canonical ClassCharacter is "a".
it("parses ClassCharacter", function() {
expect('start = [a]' ).toParseAs(classGrammar(["a"], false, false));
expect('start = [\\n]' ).toParseAs(classGrammar(["\n"], false, false));
expect('start = [\\\n]').toParseAs(classGrammar([], false, false));
expect("start = [a]" ).toParseAs(classGrammar(["a"], false, false));
expect("start = [\\n]" ).toParseAs(classGrammar(["\n"], false, false));
expect("start = [\\\n]").toParseAs(classGrammar([], false, false));
expect('start = []]' ).toFailToParse();
expect('start = [\\]').toFailToParse();
expect('start = [\n]').toFailToParse();
expect("start = []]" ).toFailToParse();
expect("start = [\\]").toFailToParse();
expect("start = [\n]").toFailToParse();
});
// Canonical LineContinuation is "\\\n".
it("parses LineContinuation", function() {
expect('start = "\\\r\n"').toParseAs(literalGrammar("", false));
expect("start = '\\\r\n'").toParseAs(literalGrammar("", false));
});
// 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));
expect("start = '\\0'" ).toParseAs(literalGrammar("\x00", false));
expect("start = '\\xFF'" ).toParseAs(literalGrammar("\xFF", false));
expect("start = '\\uFFFF'").toParseAs(literalGrammar("\uFFFF", false));
expect('start = "\\09"').toFailToParse();
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));
expect("start = '\\a'").toParseAs(literalGrammar("a", false));
});
// 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("\v", false));
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("\v", false));
});
// Canonical NonEscapeCharacter is "a".
it("parses NonEscapeCharacter", function() {
expect('start = "\\a"').toParseAs(literalGrammar("a", false));
expect("start = '\\a'").toParseAs(literalGrammar("a", false));
// The negative predicate is impossible to test with PEG.js grammar
// structure.
@ -608,66 +608,66 @@ 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));
});
// Canonical UnicodeEscapeSequence is "uFFFF".
it("parses UnicodeEscapeSequence", function() {
expect('start = "\\uFFFF"').toParseAs(literalGrammar("\uFFFF", false));
expect("start = '\\uFFFF'").toParseAs(literalGrammar("\uFFFF", false));
});
// Digit rules are not tested.
// Canonical AnyMatcher is ".".
it("parses AnyMatcher", function() {
expect('start = .').toParseAs(anyGrammar());
expect("start = .").toParseAs(anyGrammar());
});
// Canonical CodeBlock is "{ code }".
it("parses CodeBlock", function() {
expect('start = "abcd" { code }').toParseAs(actionGrammar(" code "));
expect("start = 'abcd' { code }").toParseAs(actionGrammar(" code "));
});
// Canonical Code is " code ".
it("parses Code", function() {
expect('start = "abcd" {a}' ).toParseAs(actionGrammar("a"));
expect('start = "abcd" {abc}' ).toParseAs(actionGrammar("abc"));
expect('start = "abcd" {{a}}' ).toParseAs(actionGrammar("{a}"));
expect('start = "abcd" {{a}{b}{c}}').toParseAs(actionGrammar("{a}{b}{c}"));
expect("start = 'abcd' {a}" ).toParseAs(actionGrammar("a"));
expect("start = 'abcd' {abc}" ).toParseAs(actionGrammar("abc"));
expect("start = 'abcd' {{a}}" ).toParseAs(actionGrammar("{a}"));
expect("start = 'abcd' {{a}{b}{c}}").toParseAs(actionGrammar("{a}{b}{c}"));
expect('start = "abcd" {{}').toFailToParse();
expect('start = "abcd" {}}').toFailToParse();
expect("start = 'abcd' {{}").toFailToParse();
expect("start = 'abcd' {}}").toFailToParse();
});
// Unicode character category rules and token rules are not tested.
// Canonical __ is "\n".
it("parses __", function() {
expect('start ="abcd"' ).toParseAs(trivialGrammar);
expect('start = "abcd"' ).toParseAs(trivialGrammar);
expect('start =\r\n"abcd"' ).toParseAs(trivialGrammar);
expect('start =/* comment */"abcd"').toParseAs(trivialGrammar);
expect('start = "abcd"' ).toParseAs(trivialGrammar);
expect("start ='abcd'" ).toParseAs(trivialGrammar);
expect("start = 'abcd'" ).toParseAs(trivialGrammar);
expect("start =\r\n'abcd'" ).toParseAs(trivialGrammar);
expect("start =/* comment */'abcd'").toParseAs(trivialGrammar);
expect("start = 'abcd'" ).toParseAs(trivialGrammar);
});
// Canonical _ is " ".
it("parses _", function() {
expect('a = "abcd"\r\nb = "efgh"' ).toParseAs(twoRuleGrammar);
expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar);
expect('a = "abcd"/* comment */\r\nb = "efgh"').toParseAs(twoRuleGrammar);
expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar);
expect("a = 'abcd'\r\nb = 'efgh'" ).toParseAs(twoRuleGrammar);
expect("a = 'abcd' \r\nb = 'efgh'" ).toParseAs(twoRuleGrammar);
expect("a = 'abcd'/* comment */\r\nb = 'efgh'").toParseAs(twoRuleGrammar);
expect("a = 'abcd' \r\nb = 'efgh'" ).toParseAs(twoRuleGrammar);
});
// Canonical EOS is ";".
it("parses EOS", function() {
expect('a = "abcd"\n;b = "efgh"' ).toParseAs(twoRuleGrammar);
expect('a = "abcd" \r\nb = "efgh"' ).toParseAs(twoRuleGrammar);
expect('a = "abcd" // comment\r\nb = "efgh"').toParseAs(twoRuleGrammar);
expect('a = "abcd"\nb = "efgh"' ).toParseAs(twoRuleGrammar);
expect("a = 'abcd'\n;b = 'efgh'" ).toParseAs(twoRuleGrammar);
expect("a = 'abcd' \r\nb = 'efgh'" ).toParseAs(twoRuleGrammar);
expect("a = 'abcd' // comment\r\nb = 'efgh'").toParseAs(twoRuleGrammar);
expect("a = 'abcd'\nb = 'efgh'" ).toParseAs(twoRuleGrammar);
});
// Canonical EOF is the end of input.
it("parses EOF", function() {
expect('start = "abcd"\n').toParseAs(trivialGrammar);
expect("start = 'abcd'\n").toParseAs(trivialGrammar);
});
});

@ -179,7 +179,7 @@ PrimaryExpression
// don't need to put it around nodes that can't contain any labels or
// nodes that already isolate label scope themselves. This leaves us with
// "labeled" and "sequence".
return expression.type === 'labeled' || expression.type === 'sequence'
return expression.type === "labeled" || expression.type === "sequence"
? { type: "group", expression: expression }
: expression;
}

Loading…
Cancel
Save