Bootstrapped the grammar parser, yay! I should have done this long ago.
parent
1ee0049b08
commit
a43d1b33e3
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,217 @@
|
||||
grammar: __ rule+ {
|
||||
var result = {};
|
||||
for (var i = 0; i < $2.length; i++) { result[$2[i].getName()] = $2[i]; }
|
||||
return result;
|
||||
}
|
||||
|
||||
rule: identifier (literal / "") colon expression {
|
||||
return new PEG.Grammar.Rule($1, $2 !== "" ? $2 : null, $4);
|
||||
}
|
||||
|
||||
expression: choice
|
||||
|
||||
choice: sequence (slash sequence)* {
|
||||
return $2.length > 0
|
||||
? new PEG.Grammar.Choice([$1].concat(PEG.ArrayUtils.map(
|
||||
$2,
|
||||
function(element) { return element[1]; }
|
||||
)))
|
||||
: $1;
|
||||
}
|
||||
|
||||
sequence
|
||||
: prefixed* action {
|
||||
return new PEG.Grammar.Action(
|
||||
$1.length != 1 ? new PEG.Grammar.Sequence($1) : $1[0],
|
||||
$2
|
||||
);
|
||||
}
|
||||
/ prefixed* { return $1.length != 1 ? new PEG.Grammar.Sequence($1) : $1[0]; }
|
||||
|
||||
prefixed
|
||||
: and suffixed {
|
||||
return new PEG.Grammar.NotPredicate(new PEG.Grammar.NotPredicate($2));
|
||||
}
|
||||
/ not suffixed { return new PEG.Grammar.NotPredicate($2); }
|
||||
/ suffixed
|
||||
|
||||
suffixed
|
||||
: primary question {
|
||||
return new PEG.Grammar.Choice([$1, new PEG.Grammar.Literal("")]);
|
||||
}
|
||||
/ primary star { return new PEG.Grammar.ZeroOrMore($1); }
|
||||
/ primary plus {
|
||||
return new PEG.Grammar.Action(
|
||||
new PEG.Grammar.Sequence([$1, new PEG.Grammar.ZeroOrMore($1)]),
|
||||
function(first, rest) { return [first].concat(rest); }
|
||||
);
|
||||
}
|
||||
/ primary
|
||||
|
||||
primary
|
||||
: identifier !(( literal / "") colon) { return new PEG.Grammar.RuleRef($1); }
|
||||
/ literal { return new PEG.Grammar.Literal($1); }
|
||||
/ dot { return new PEG.Grammar.Any(); }
|
||||
/ class {
|
||||
return new PEG.Grammar.Choice(
|
||||
PEG.ArrayUtils.map(
|
||||
$1.split(""),
|
||||
function(character) { return new PEG.Grammar.Literal(character); }
|
||||
)
|
||||
);
|
||||
}
|
||||
/ lparen expression rparen { return $2; }
|
||||
|
||||
/* "Lexical" elements */
|
||||
|
||||
action "action": braced __ { return $1.substr(1, $1.length - 2); }
|
||||
|
||||
braced: "{" (braced / nonBraceCharacter)* "}" { return $1 + $2.join("") + $3; }
|
||||
|
||||
nonBraceCharacters: nonBraceCharacter+ { return $1.join(""); }
|
||||
|
||||
nonBraceCharacter: !("{" / "}") . { return $2; }
|
||||
|
||||
colon: ":" __ { return $1; }
|
||||
slash: "/" __ { return $1; }
|
||||
and: "&" __ { return $1; }
|
||||
not: "!" __ { return $1; }
|
||||
question: "?" __ { return $1; }
|
||||
star: "*" __ { return $1; }
|
||||
plus: "+" __ { return $1; }
|
||||
lparen: "(" __ { return $1; }
|
||||
rparen: ")" __ { return $1; }
|
||||
dot: "." __ { return $1; }
|
||||
|
||||
/*
|
||||
* Modelled after ECMA-262, 5th ed., 7.6, but much simplified:
|
||||
*
|
||||
* * no Unicode escape sequences
|
||||
*
|
||||
* * "Unicode combining marks" and "Unicode connection punctuation" can't be
|
||||
* part of the identifier
|
||||
*
|
||||
* * only [a-zA-Z] is considered a "Unicode letter"
|
||||
*
|
||||
* * only [0-9] is considered a "Unicode digit"
|
||||
*
|
||||
* The simplifications were made just to make the implementation little bit
|
||||
* easier, there is no "philosophical" reason behind them.
|
||||
*/
|
||||
identifier "identifier": (letter / "_" / "$") (letter / digit / "_" / "$")* __ {
|
||||
return $1 + $2.join("");
|
||||
}
|
||||
|
||||
/*
|
||||
* Modelled after ECMA-262, 5th ed., 7.8.4. (syntax & semantics, rules only
|
||||
* vaguely).
|
||||
*/
|
||||
literal "literal": (doubleQuotedLiteral / singleQuotedLiteral) __ { return $1; }
|
||||
|
||||
doubleQuotedLiteral: '"' doubleQuotedCharacter* '"' { return $2.join(""); }
|
||||
|
||||
doubleQuotedCharacter
|
||||
: simpleDoubleQuotedCharacter
|
||||
/ simpleEscapeSequence
|
||||
/ zeroEscapeSequence
|
||||
/ hexEscapeSequence
|
||||
/ unicodeEscapeSequence
|
||||
/ eolEscapeSequence
|
||||
|
||||
simpleDoubleQuotedCharacter: !('"' / "\\" / eolChar) . { return $2; }
|
||||
|
||||
singleQuotedLiteral: "'" singleQuotedCharacter* "'" { return $2.join(""); }
|
||||
|
||||
singleQuotedCharacter
|
||||
: simpleSingleQuotedCharacter
|
||||
/ simpleEscapeSequence
|
||||
/ zeroEscapeSequence
|
||||
/ hexEscapeSequence
|
||||
/ unicodeEscapeSequence
|
||||
/ eolEscapeSequence
|
||||
|
||||
simpleSingleQuotedCharacter: !("'" / "\\" / eolChar) . { return $2; }
|
||||
|
||||
class "character class": "[" (classCharacterRange / classCharacter)* "]" __ {
|
||||
return $2.join("");
|
||||
}
|
||||
|
||||
classCharacterRange: bracketDelimitedCharacter "-" bracketDelimitedCharacter {
|
||||
var beginCharCode = $1.charCodeAt(0);
|
||||
var endCharCode = $3.charCodeAt(0);
|
||||
if (beginCharCode > endCharCode) {
|
||||
throw new PEG.Parser.SyntaxError(
|
||||
"Invalid character range: " + $1 + "-" + $3 + "."
|
||||
);
|
||||
}
|
||||
|
||||
var result = "";
|
||||
for (var charCode = beginCharCode; charCode <= endCharCode; charCode++) {
|
||||
result += String.fromCharCode(charCode);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
classCharacter: bracketDelimitedCharacter
|
||||
|
||||
bracketDelimitedCharacter
|
||||
: simpleBracketDelimitedCharacter
|
||||
/ simpleEscapeSequence
|
||||
/ zeroEscapeSequence
|
||||
/ hexEscapeSequence
|
||||
/ unicodeEscapeSequence
|
||||
/ eolEscapeSequence
|
||||
|
||||
simpleBracketDelimitedCharacter: !("]" / "\\" / eolChar) . { return $2; }
|
||||
|
||||
simpleEscapeSequence: "\\" !(digit / "x" / "u" / eolChar) . {
|
||||
return $3
|
||||
.replace("b", "\b")
|
||||
.replace("f", "\f")
|
||||
.replace("n", "\n")
|
||||
.replace("r", "\r")
|
||||
.replace("t", "\t")
|
||||
.replace("v", "\v")
|
||||
}
|
||||
|
||||
zeroEscapeSequence: "\\0" !digit { return "\0"; }
|
||||
|
||||
hexEscapeSequence: "\\x" hexDigit hexDigit {
|
||||
return String.fromCharCode(parseInt("0x" + $2 + $3));
|
||||
}
|
||||
|
||||
unicodeEscapeSequence: "\\u" hexDigit hexDigit hexDigit hexDigit {
|
||||
return String.fromCharCode(parseInt("0x" + $2 + $3 + $4 + $5));
|
||||
}
|
||||
|
||||
eolEscapeSequence: "\\" eol { return $2; }
|
||||
|
||||
digit: [0-9]
|
||||
|
||||
hexDigit: [0-9a-fA-F]
|
||||
|
||||
letter: lowerCaseLetter / upperCaseLetter
|
||||
|
||||
lowerCaseLetter: [a-z]
|
||||
|
||||
upperCaseLetter: [A-Z]
|
||||
|
||||
__: (whitespace / eol / comment)*
|
||||
|
||||
/* Modelled after ECMA-262, 5th ed., 7.4. */
|
||||
comment "comment": singleLineComment / multiLineComment
|
||||
|
||||
singleLineComment: "//" (!eolChar .)*
|
||||
|
||||
multiLineComment: "/*" (!"*/" .)* "*/"
|
||||
|
||||
/* Modelled after ECMA-262, 5th ed., 7.3. */
|
||||
eol "end of line": "\n" / "\r\n" / "\r" / "\u2028" / "\u2029"
|
||||
|
||||
eolChar: [\n\r\u2028\u2029]
|
||||
|
||||
/*
|
||||
* Modelled after ECMA-262, 5th ed., 7.2. \uFEFF should be between the
|
||||
* characters too, but it causes infinite loop in Rhino.
|
||||
*/
|
||||
whitespace "whitespace": [ \t\v\f\xA0\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]
|
@ -0,0 +1,460 @@
|
||||
(function() {
|
||||
|
||||
var global = this;
|
||||
|
||||
/* ===== Helpers ===== */
|
||||
|
||||
global.grammarParserParses = function(input, expected) {
|
||||
global.parses(PEG.grammarParser, input, expected);
|
||||
};
|
||||
|
||||
global.grammarParserDoesNotParse = function(input) {
|
||||
global.doesNotParse(PEG.grammarParser, input);
|
||||
}
|
||||
|
||||
/* ===== Grammar Parser ===== */
|
||||
|
||||
module("Grammar Parser");
|
||||
|
||||
with (PEG.Grammar) {
|
||||
var literalEmpty = new Literal("");
|
||||
var literalAbcd = new Literal("abcd");
|
||||
var literalEfgh = new Literal("efgh");
|
||||
var literalIjkl = new Literal("ijkl");
|
||||
|
||||
var choice = new Choice([literalAbcd, literalEmpty]);
|
||||
|
||||
var notAbcd = new NotPredicate(literalAbcd);
|
||||
var notEfgh = new NotPredicate(literalEfgh);
|
||||
var notIjkl = new NotPredicate(literalIjkl);
|
||||
|
||||
var sequenceEmpty = new Sequence([]);
|
||||
var sequenceNots = new Sequence([notAbcd, notEfgh, notIjkl]);
|
||||
var sequenceLiterals = new Sequence([literalAbcd, literalEfgh, literalIjkl]);
|
||||
|
||||
function oneRuleGrammar(expression) {
|
||||
return { start: new PEG.Grammar.Rule("start", null, expression) };
|
||||
}
|
||||
|
||||
var simpleGrammar = oneRuleGrammar(new Literal("abcd"));
|
||||
|
||||
function identifierGrammar(identifier) {
|
||||
return oneRuleGrammar(new PEG.Grammar.RuleRef(identifier));
|
||||
}
|
||||
|
||||
function literalGrammar(literal) {
|
||||
return oneRuleGrammar(new PEG.Grammar.Literal(literal));
|
||||
}
|
||||
|
||||
function classGrammar(chars) {
|
||||
return oneRuleGrammar(new PEG.Grammar.Choice(
|
||||
PEG.ArrayUtils.map(
|
||||
chars.split(""),
|
||||
function(char) { return new PEG.Grammar.Literal(char); }
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
var anyGrammar = oneRuleGrammar(new Any());
|
||||
|
||||
function actionGrammar(action) {
|
||||
return oneRuleGrammar(new PEG.Grammar.Action(new PEG.Grammar.Literal("a"), action));
|
||||
}
|
||||
|
||||
/* Canonical grammar is "a: \"abcd\";\nb: \"efgh\";\nc: \"ijkl\";". */
|
||||
test("parses grammar", function() {
|
||||
grammarParserParses('a: "abcd"', { a: new Rule("a", null, literalAbcd) });
|
||||
grammarParserParses(
|
||||
'a: "abcd"\nb: "efgh"\nc: "ijkl"',
|
||||
{
|
||||
a: new Rule("a", null, literalAbcd),
|
||||
b: new Rule("b", null, literalEfgh),
|
||||
c: new Rule("c", null, literalIjkl)
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
/* Canonical rule is "a: \"abcd\"". */
|
||||
test("parses rule", function() {
|
||||
grammarParserParses(
|
||||
'start: "abcd" / "efgh" / "ijkl"',
|
||||
oneRuleGrammar(new Choice([literalAbcd, literalEfgh, literalIjkl]))
|
||||
);
|
||||
grammarParserParses(
|
||||
'start "start rule": "abcd" / "efgh" / "ijkl"',
|
||||
{
|
||||
start:
|
||||
new Rule(
|
||||
"start",
|
||||
"start rule",
|
||||
new Choice([literalAbcd, literalEfgh, literalIjkl])
|
||||
)
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
/* Canonical expression is "\"abcd\" / \"efgh\" / \"ijkl\"". */
|
||||
test("parses expression", function() {
|
||||
grammarParserParses(
|
||||
'start: "abcd" / "efgh" / "ijkl"',
|
||||
oneRuleGrammar(new Choice([literalAbcd, literalEfgh, literalIjkl]))
|
||||
);
|
||||
});
|
||||
|
||||
/* Canonical choice is "\"abcd\" / \"efgh\" / \"ijkl\"". */
|
||||
test("parses choice", function() {
|
||||
grammarParserParses(
|
||||
'start: "abcd" "efgh" "ijkl"',
|
||||
oneRuleGrammar(sequenceLiterals)
|
||||
);
|
||||
grammarParserParses(
|
||||
'start: "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl"',
|
||||
oneRuleGrammar(new Choice([
|
||||
sequenceLiterals,
|
||||
sequenceLiterals,
|
||||
sequenceLiterals
|
||||
]))
|
||||
);
|
||||
});
|
||||
|
||||
/* Canonical sequence is "\"abcd\" \"efgh\" \"ijkl\"". */
|
||||
test("parses sequence", function() {
|
||||
grammarParserParses(
|
||||
'start: { code }',
|
||||
oneRuleGrammar(new Action(sequenceEmpty, " code "))
|
||||
);
|
||||
grammarParserParses(
|
||||
'start: !"abcd" { code }',
|
||||
oneRuleGrammar(new Action(notAbcd, " code "))
|
||||
);
|
||||
grammarParserParses(
|
||||
'start: !"abcd" !"efgh" !"ijkl" { code }',
|
||||
oneRuleGrammar(new Action(sequenceNots, " code "))
|
||||
);
|
||||
|
||||
grammarParserParses('start: ', oneRuleGrammar(sequenceEmpty));
|
||||
grammarParserParses('start: !"abcd"', oneRuleGrammar(notAbcd));
|
||||
grammarParserParses(
|
||||
'start: !"abcd" !"efgh" !"ijkl"',
|
||||
oneRuleGrammar(sequenceNots)
|
||||
);
|
||||
});
|
||||
|
||||
/* Canonical prefixed is "!\"abcd\"". */
|
||||
test("parses prefixed", function() {
|
||||
grammarParserParses(
|
||||
'start: &"abcd"?',
|
||||
oneRuleGrammar(new NotPredicate(new NotPredicate(choice)))
|
||||
);
|
||||
grammarParserParses('start: !"abcd"?', oneRuleGrammar(new NotPredicate(choice)));
|
||||
grammarParserParses('start: "abcd"?', oneRuleGrammar(choice));
|
||||
});
|
||||
|
||||
/* Canonical suffixed is "\"abcd\"?". */
|
||||
test("parses suffixed", function() {
|
||||
grammarParserParses('start: "abcd"?', oneRuleGrammar(choice));
|
||||
grammarParserParses('start: "abcd"*', oneRuleGrammar(new ZeroOrMore(literalAbcd)));
|
||||
grammarParserParses(
|
||||
'start: "abcd"+',
|
||||
oneRuleGrammar(new Action(
|
||||
new Sequence([literalAbcd, new ZeroOrMore(literalAbcd)]),
|
||||
function(first, rest) { return [first].concat(rest); }
|
||||
))
|
||||
);
|
||||
grammarParserParses('start: "abcd"', literalGrammar("abcd"));
|
||||
});
|
||||
|
||||
/* Canonical primary is "\"abcd\"". */
|
||||
test("parses primary", function() {
|
||||
grammarParserParses('start: a', identifierGrammar("a"));
|
||||
grammarParserParses('start: "abcd"', literalGrammar("abcd"));
|
||||
grammarParserParses('start: .', anyGrammar);
|
||||
grammarParserParses('start: [a-d]', classGrammar("abcd"));
|
||||
grammarParserParses('start: ("abcd")', literalGrammar("abcd"));
|
||||
});
|
||||
|
||||
/* Canonical action is "{ code }". */
|
||||
test("parses action", function() {
|
||||
grammarParserParses('start: "a" { code }', actionGrammar(" code "));
|
||||
});
|
||||
|
||||
/* Canonical braced is "{ code }". */
|
||||
test("parses braced", function() {
|
||||
grammarParserParses('start: "a" {}', actionGrammar(""));
|
||||
grammarParserParses('start: "a" {a}', actionGrammar("a"));
|
||||
grammarParserParses('start: "a" {{a}}', actionGrammar("{a}"));
|
||||
grammarParserParses('start: "a" {aaa}', actionGrammar("aaa"));
|
||||
});
|
||||
|
||||
/* Trivial character rules are not tested. */
|
||||
|
||||
/* Canonical identifier is "a". */
|
||||
test("parses identifier", function() {
|
||||
grammarParserParses('start: a', identifierGrammar("a"));
|
||||
grammarParserParses('start: z', identifierGrammar("z"));
|
||||
grammarParserParses('start: A', identifierGrammar("A"));
|
||||
grammarParserParses('start: Z', identifierGrammar("Z"));
|
||||
grammarParserParses('start: _', identifierGrammar("_"));
|
||||
grammarParserParses('start: $', identifierGrammar("$"));
|
||||
grammarParserParses('start: aa', identifierGrammar("aa"));
|
||||
grammarParserParses('start: az', identifierGrammar("az"));
|
||||
grammarParserParses('start: aA', identifierGrammar("aA"));
|
||||
grammarParserParses('start: aZ', identifierGrammar("aZ"));
|
||||
grammarParserParses('start: a0', identifierGrammar("a0"));
|
||||
grammarParserParses('start: a9', identifierGrammar("a9"));
|
||||
grammarParserParses('start: a_', identifierGrammar("a_"));
|
||||
grammarParserParses('start: a$', identifierGrammar("a$"));
|
||||
grammarParserParses('start: abcd', identifierGrammar("abcd"));
|
||||
|
||||
grammarParserParses('start: a\n', identifierGrammar("a"));
|
||||
});
|
||||
|
||||
/* Canonical literal is "\"abcd\"". */
|
||||
test("parses literal", function() {
|
||||
grammarParserParses('start: "abcd"', literalGrammar("abcd"));
|
||||
grammarParserParses("start: 'abcd'", literalGrammar("abcd"));
|
||||
});
|
||||
|
||||
/* Canonical doubleQuotedLiteral is "\"abcd\"". */
|
||||
test("parses doubleQuotedLiteral", function() {
|
||||
grammarParserParses('start: ""', literalGrammar(""));
|
||||
grammarParserParses('start: "a"', literalGrammar("a"));
|
||||
grammarParserParses('start: "abc"', literalGrammar("abc"));
|
||||
|
||||
grammarParserParses('start: "abcd"\n', literalGrammar("abcd"));
|
||||
});
|
||||
|
||||
/* Canonical doubleQuotedCharacter is "a". */
|
||||
test("parses doubleQuotedCharacter", function() {
|
||||
grammarParserParses('start: "a"', literalGrammar("a"));
|
||||
grammarParserParses('start: "\\n"', literalGrammar("\n"));
|
||||
grammarParserParses('start: "\\0"', literalGrammar("\0"));
|
||||
grammarParserParses('start: "\\x00"', literalGrammar("\x00"));
|
||||
grammarParserParses('start: "\\u0120"', literalGrammar("\u0120"));
|
||||
grammarParserParses('start: "\\\n"', literalGrammar("\n"));
|
||||
});
|
||||
|
||||
/* Canonical simpleDoubleQuotedCharacter is "a". */
|
||||
test("parses simpleDoubleQuotedCharacter", function() {
|
||||
grammarParserParses('start: "a"', literalGrammar("a"));
|
||||
grammarParserParses('start: "\'"', literalGrammar("'"));
|
||||
grammarParserDoesNotParse('start: """');
|
||||
grammarParserDoesNotParse('start: "\\"');
|
||||
grammarParserDoesNotParse('start: "\n"');
|
||||
grammarParserDoesNotParse('start: "\r"');
|
||||
grammarParserDoesNotParse('start: "\u2028"');
|
||||
grammarParserDoesNotParse('start: "\u2029"');
|
||||
});
|
||||
|
||||
/* Canonical singleQuotedLiteral is "'abcd'". */
|
||||
test("parses singleQuotedLiteral", function() {
|
||||
grammarParserParses("start: ''", literalGrammar(""));
|
||||
grammarParserParses("start: 'a'", literalGrammar("a"));
|
||||
grammarParserParses("start: 'abc'", literalGrammar("abc"));
|
||||
|
||||
grammarParserParses("start: 'abcd'\n", literalGrammar("abcd"));
|
||||
});
|
||||
|
||||
/* Canonical singleQuotedCharacter is "a". */
|
||||
test("parses singleQuotedCharacter", function() {
|
||||
grammarParserParses("start: 'a'", literalGrammar("a"));
|
||||
grammarParserParses("start: '\\n'", literalGrammar("\n"));
|
||||
grammarParserParses("start: '\\0'", literalGrammar("\0"));
|
||||
grammarParserParses("start: '\\x00'", literalGrammar("\x00"));
|
||||
grammarParserParses("start: '\\u0120'", literalGrammar("\u0120"));
|
||||
grammarParserParses("start: '\\\n'", literalGrammar("\n"));
|
||||
});
|
||||
|
||||
/* Canonical simpleSingleQuotedCharacter is "a". */
|
||||
test("parses simpleSingleQuotedCharacter", function() {
|
||||
grammarParserParses("start: 'a'", literalGrammar("a"));
|
||||
grammarParserParses("start: '\"'", literalGrammar("\""));
|
||||
grammarParserDoesNotParse("start: '''");
|
||||
grammarParserDoesNotParse("start: '\\'");
|
||||
grammarParserDoesNotParse("start: '\n'");
|
||||
grammarParserDoesNotParse("start: '\r'");
|
||||
grammarParserDoesNotParse("start: '\u2028'");
|
||||
grammarParserDoesNotParse("start: '\u2029'");
|
||||
});
|
||||
|
||||
/* Canonical class is "[a-d]". */
|
||||
test("parses classCharacterRange", function() {
|
||||
grammarParserParses("start: []", classGrammar(""));
|
||||
grammarParserParses("start: [a-d]", classGrammar("abcd"));
|
||||
grammarParserParses("start: [a]", classGrammar("a"));
|
||||
grammarParserParses("start: [a-de-hi-l]", classGrammar("abcdefghijkl"));
|
||||
|
||||
grammarParserParses("start: [a-d]\n", classGrammar("abcd"));
|
||||
});
|
||||
|
||||
/* Canonical classCharacterRange is "a-d". */
|
||||
test("parses classCharacterRange", function() {
|
||||
grammarParserParses("start: [a-d]", classGrammar("abcd"));
|
||||
grammarParserParses("start: [a-a]", classGrammar("a"));
|
||||
grammarParserDoesNotParse("start: [b-a]");
|
||||
});
|
||||
|
||||
/* Canonical classCharacter is "a". */
|
||||
test("parses classCharacter", function() {
|
||||
grammarParserParses("start: [a]", classGrammar("a"));
|
||||
});
|
||||
|
||||
/* Canonical bracketDelimitedCharacter is "a". */
|
||||
test("parses bracketDelimitedCharacter", function() {
|
||||
grammarParserParses("start: [a]", classGrammar("a"));
|
||||
grammarParserParses("start: [\\n]", classGrammar("\n"));
|
||||
grammarParserParses("start: [\\0]", classGrammar("\0"));
|
||||
grammarParserParses("start: [\\x00]", classGrammar("\x00"));
|
||||
grammarParserParses("start: [\\u0120]", classGrammar("\u0120"));
|
||||
grammarParserParses("start: [\\\n]", classGrammar("\n"));
|
||||
});
|
||||
|
||||
/* Canonical simpleBracketDelimiedCharacter is "a". */
|
||||
test("parses simpleBracketDelimitedCharacter", function() {
|
||||
grammarParserParses("start: [a]", classGrammar("a"));
|
||||
grammarParserParses("start: [[]", classGrammar("["));
|
||||
grammarParserDoesNotParse("start: []]");
|
||||
grammarParserDoesNotParse("start: [\\]");
|
||||
grammarParserDoesNotParse("start: [\n]");
|
||||
grammarParserDoesNotParse("start: [\r]");
|
||||
grammarParserDoesNotParse("start: [\u2028]");
|
||||
grammarParserDoesNotParse("start: [\u2029]");
|
||||
});
|
||||
|
||||
/* Canonical simpleEscapeSequence is "\\n". */
|
||||
test("parses simpleEscapeSequence", function() {
|
||||
grammarParserParses('start: "\\\'"', literalGrammar("'"));
|
||||
grammarParserParses('start: "\\""', literalGrammar("\""));
|
||||
grammarParserParses('start: "\\\\"', literalGrammar("\\"));
|
||||
grammarParserParses('start: "\\b"', literalGrammar("\b"));
|
||||
grammarParserParses('start: "\\f"', literalGrammar("\f"));
|
||||
grammarParserParses('start: "\\n"', literalGrammar("\n"));
|
||||
grammarParserParses('start: "\\r"', literalGrammar("\r"));
|
||||
grammarParserParses('start: "\\t"', literalGrammar("\t"));
|
||||
grammarParserParses('start: "\\v"', literalGrammar("\v"));
|
||||
|
||||
grammarParserParses('start: "\\a"', literalGrammar("a"));
|
||||
});
|
||||
|
||||
/* Canonical zeroEscapeSequence is "\\0". */
|
||||
test("parses zeroEscapeSequence", function() {
|
||||
grammarParserParses('start: "\\0"', literalGrammar("\0"));
|
||||
grammarParserDoesNotParse('start: "\\00"');
|
||||
grammarParserDoesNotParse('start: "\\09"');
|
||||
});
|
||||
|
||||
/* Canonical hexEscapeSequence is "\\x00". */
|
||||
test("parses hexEscapeSequence", function() {
|
||||
grammarParserParses('start: "\\x00"', literalGrammar("\x00"));
|
||||
grammarParserParses('start: "\\x09"', literalGrammar("\x09"));
|
||||
grammarParserParses('start: "\\x0a"', literalGrammar("\x0a"));
|
||||
grammarParserParses('start: "\\x0f"', literalGrammar("\x0f"));
|
||||
grammarParserParses('start: "\\x0A"', literalGrammar("\x0A"));
|
||||
grammarParserParses('start: "\\x0F"', literalGrammar("\x0F"));
|
||||
grammarParserDoesNotParse('start: "\\x0"');
|
||||
grammarParserParses('start: "\\x000"', literalGrammar("\x000"));
|
||||
});
|
||||
|
||||
/* Canonical unicodeEscapeSequence is "\\u0120". */
|
||||
test("parses unicodeEscapeSequence", function() {
|
||||
grammarParserParses('start: "\\u0120"', literalGrammar("\u0120"));
|
||||
grammarParserParses('start: "\\u0129"', literalGrammar("\u0129"));
|
||||
grammarParserParses('start: "\\u012a"', literalGrammar("\u012a"));
|
||||
grammarParserParses('start: "\\u012f"', literalGrammar("\u012f"));
|
||||
grammarParserParses('start: "\\u012A"', literalGrammar("\u012A"));
|
||||
grammarParserParses('start: "\\u012F"', literalGrammar("\u012F"));
|
||||
grammarParserDoesNotParse('start: "\\u012"');
|
||||
grammarParserParses('start: "\\u01234"', literalGrammar("\u01234"));
|
||||
});
|
||||
|
||||
/* Canonical eolEscapeSequence is "\\\n". */
|
||||
test("parses eolEscapeSequence", function() {
|
||||
grammarParserParses('start: "\\\n"', literalGrammar("\n"));
|
||||
grammarParserParses('start: "\\\r\n"', literalGrammar("\r\n"));
|
||||
grammarParserParses('start: "\\\r"', literalGrammar("\r"));
|
||||
grammarParserParses('start: "\\\u2028"', literalGrammar("\u2028"));
|
||||
grammarParserParses('start: "\\\u2029"', literalGrammar("\u2029"));
|
||||
});
|
||||
|
||||
/* Canonical __ is "\n". */
|
||||
test("parses __", function() {
|
||||
grammarParserParses('start:"abcd"', simpleGrammar);
|
||||
grammarParserParses('start: "abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\n"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:/* comment */"abcd"', simpleGrammar);
|
||||
grammarParserParses('start: "abcd"', simpleGrammar);
|
||||
});
|
||||
|
||||
/* Trivial character class rules are not tested. */
|
||||
|
||||
/* Canonical comment is "\/* comment *\/". */
|
||||
test("parses comment", function() {
|
||||
grammarParserParses('start:// comment\n"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:/* comment */"abcd"', simpleGrammar);
|
||||
});
|
||||
/* Canonical singleLineComment is "// comment". */
|
||||
test("parses singleLineComment", function() {
|
||||
grammarParserParses('start://\n"abcd"', simpleGrammar);
|
||||
grammarParserParses('start://a\n"abcd"', simpleGrammar);
|
||||
grammarParserParses('start://aaa\n"abcd"', simpleGrammar);
|
||||
grammarParserParses('start: "abcd"//', simpleGrammar);
|
||||
});
|
||||
|
||||
/* Canonical multiLineComment is "\/* comment *\/". */
|
||||
test("parses multiLineComment", function() {
|
||||
grammarParserParses('start:/**/"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:/*a*/"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:/*aaa*/"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:/*\n*/"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:/***/"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:/*a/*/"abcd"', simpleGrammar);
|
||||
|
||||
grammarParserDoesNotParse('start:/*"abcd"');
|
||||
grammarParserDoesNotParse('start:/*/"abcd"');
|
||||
grammarParserDoesNotParse('start:/*/**/*/"abcd"');
|
||||
});
|
||||
|
||||
/* Canonical eol is "\n". */
|
||||
test("parses eol", function() {
|
||||
grammarParserParses('start:\n"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\r\n"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\r"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2028"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2029"abcd"', simpleGrammar);
|
||||
});
|
||||
|
||||
/* Canonical eolChar is "\n". */
|
||||
test("parses eolChar", function() {
|
||||
grammarParserParses('start:\n"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\r"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2028"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2029"abcd"', simpleGrammar);
|
||||
});
|
||||
|
||||
/* Canonical whitespace is " ". */
|
||||
test("parses whitespace", function() {
|
||||
grammarParserParses('start:\t"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\v"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\f"abcd"', simpleGrammar);
|
||||
grammarParserParses('start: "abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\xA0"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u1680"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u180E"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2000"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2001"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2002"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2003"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2004"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2005"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2006"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2007"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2008"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u2009"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u200A"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u202F"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u205F"abcd"', simpleGrammar);
|
||||
grammarParserParses('start:\u3000"abcd"', simpleGrammar);
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
Loading…
Reference in New Issue