AST refactoring 5/6: Make AST classless
This commit is contained in:
parent
41abb7ad92
commit
b4bf49443a
|
@ -153,75 +153,6 @@ PEG.Grammar.GrammarError = function(message) {
|
|||
|
||||
PEG.Grammar.GrammarError.prototype = Error.prototype;
|
||||
|
||||
/* ===== PEG.Grammar.* ===== */
|
||||
|
||||
PEG.Grammar.Rule = function(name, displayName, expression) {
|
||||
this.type = "rule";
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
this.expression = expression;
|
||||
};
|
||||
|
||||
PEG.Grammar.Choice = function(alternatives) {
|
||||
this.type = "choice";
|
||||
this.alternatives = alternatives;
|
||||
};
|
||||
|
||||
PEG.Grammar.Sequence = function(elements) {
|
||||
this.type = "sequence";
|
||||
this.elements = elements;
|
||||
};
|
||||
|
||||
PEG.Grammar.AndPredicate = function(expression) {
|
||||
this.type = "and_predicate";
|
||||
this.expression = expression;
|
||||
};
|
||||
|
||||
PEG.Grammar.NotPredicate = function(expression) {
|
||||
this.type = "not_predicate";
|
||||
this.expression = expression;
|
||||
};
|
||||
|
||||
PEG.Grammar.Optional = function(expression) {
|
||||
this.type = "optional";
|
||||
this.expression = expression;
|
||||
};
|
||||
|
||||
PEG.Grammar.ZeroOrMore = function(expression) {
|
||||
this.type = "zero_or_more";
|
||||
this.expression = expression;
|
||||
};
|
||||
|
||||
PEG.Grammar.OneOrMore = function(expression) {
|
||||
this.type = "one_or_more";
|
||||
this.expression = expression;
|
||||
};
|
||||
|
||||
PEG.Grammar.Action = function(expression, action) {
|
||||
this.type = "action";
|
||||
this.expression = expression;
|
||||
this.action = action;
|
||||
};
|
||||
|
||||
PEG.Grammar.RuleRef = function(name) {
|
||||
this.type = "rule_ref";
|
||||
this.name = name;
|
||||
};
|
||||
|
||||
PEG.Grammar.Literal = function(value) {
|
||||
this.type = "literal";
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
PEG.Grammar.Any = function() {
|
||||
this.type = "any";
|
||||
};
|
||||
|
||||
PEG.Grammar.Class = function(characters) {
|
||||
this.type = "class";
|
||||
this.characters = characters;
|
||||
};
|
||||
|
||||
/* ===== PEG.Compiler ===== */
|
||||
|
||||
PEG.Compiler = {
|
||||
|
@ -715,7 +646,7 @@ PEG.Compiler = {
|
|||
|
||||
var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result");
|
||||
|
||||
if (node.expression instanceof PEG.Grammar.Sequence) {
|
||||
if (node.expression.type === "sequence") {
|
||||
var params = PEG.ArrayUtils.map(
|
||||
PEG.ArrayUtils.range(1, node.expression.elements.length + 1),
|
||||
function(n) { return "$" + n; }
|
||||
|
|
|
@ -154,7 +154,12 @@ PEG.grammarParser = (function(){
|
|||
}
|
||||
var result5 = result6 !== null
|
||||
? (function($1, $2, $3, $4) {
|
||||
return new PEG.Grammar.Rule($1, $2 !== "" ? $2 : null, $4);
|
||||
return {
|
||||
type: "rule",
|
||||
name: $1,
|
||||
displayName: $2 !== "" ? $2 : null,
|
||||
expression: $4
|
||||
};
|
||||
}).apply(null, result6)
|
||||
: null;
|
||||
|
||||
|
@ -247,12 +252,18 @@ PEG.grammarParser = (function(){
|
|||
}
|
||||
var result14 = result15 !== null
|
||||
? (function($1, $2) {
|
||||
return $2.length > 0
|
||||
? new PEG.Grammar.Choice([$1].concat(PEG.ArrayUtils.map(
|
||||
if ($2.length > 0) {
|
||||
var alternatives = [$1].concat(PEG.ArrayUtils.map(
|
||||
$2,
|
||||
function(element) { return element[1]; }
|
||||
)))
|
||||
: $1;
|
||||
));
|
||||
return {
|
||||
type: "choice",
|
||||
alternatives: alternatives
|
||||
}
|
||||
} else {
|
||||
return $1;
|
||||
}
|
||||
}).apply(null, result15)
|
||||
: null;
|
||||
|
||||
|
@ -297,10 +308,17 @@ PEG.grammarParser = (function(){
|
|||
}
|
||||
var result25 = result26 !== null
|
||||
? (function($1, $2) {
|
||||
return new PEG.Grammar.Action(
|
||||
$1.length != 1 ? new PEG.Grammar.Sequence($1) : $1[0],
|
||||
$2
|
||||
);
|
||||
var expression = $1.length != 1
|
||||
? {
|
||||
type: "sequence",
|
||||
elements: $1
|
||||
}
|
||||
: $1[0];
|
||||
return {
|
||||
type: "action",
|
||||
expression: expression,
|
||||
action: $2
|
||||
};
|
||||
}).apply(null, result26)
|
||||
: null;
|
||||
if (result25 !== null) {
|
||||
|
@ -313,7 +331,14 @@ PEG.grammarParser = (function(){
|
|||
var result24 = this._parse_prefixed(context);
|
||||
}
|
||||
var result22 = result23 !== null
|
||||
? (function($1) { return $1.length != 1 ? new PEG.Grammar.Sequence($1) : $1[0]; })(result23)
|
||||
? (function($1) {
|
||||
return $1.length != 1
|
||||
? {
|
||||
type: "sequence",
|
||||
elements: $1
|
||||
}
|
||||
: $1[0];
|
||||
})(result23)
|
||||
: null;
|
||||
if (result22 !== null) {
|
||||
var result21 = result22;
|
||||
|
@ -357,7 +382,7 @@ PEG.grammarParser = (function(){
|
|||
this._pos = savedPos6;
|
||||
}
|
||||
var result36 = result37 !== null
|
||||
? (function($1, $2) { return new PEG.Grammar.AndPredicate($2); }).apply(null, result37)
|
||||
? (function($1, $2) { return { type: "and_predicate", expression: $2 }; }).apply(null, result37)
|
||||
: null;
|
||||
if (result36 !== null) {
|
||||
var result30 = result36;
|
||||
|
@ -377,7 +402,7 @@ PEG.grammarParser = (function(){
|
|||
this._pos = savedPos5;
|
||||
}
|
||||
var result32 = result33 !== null
|
||||
? (function($1, $2) { return new PEG.Grammar.NotPredicate($2); }).apply(null, result33)
|
||||
? (function($1, $2) { return { type: "not_predicate", expression: $2 }; }).apply(null, result33)
|
||||
: null;
|
||||
if (result32 !== null) {
|
||||
var result30 = result32;
|
||||
|
@ -426,7 +451,7 @@ PEG.grammarParser = (function(){
|
|||
this._pos = savedPos9;
|
||||
}
|
||||
var result50 = result51 !== null
|
||||
? (function($1, $2) { return new PEG.Grammar.Optional($1); }).apply(null, result51)
|
||||
? (function($1, $2) { return { type: "optional", expression: $1}; }).apply(null, result51)
|
||||
: null;
|
||||
if (result50 !== null) {
|
||||
var result40 = result50;
|
||||
|
@ -446,7 +471,7 @@ PEG.grammarParser = (function(){
|
|||
this._pos = savedPos8;
|
||||
}
|
||||
var result46 = result47 !== null
|
||||
? (function($1, $2) { return new PEG.Grammar.ZeroOrMore($1); }).apply(null, result47)
|
||||
? (function($1, $2) { return { type: "zero_or_more", expression: $1}; }).apply(null, result47)
|
||||
: null;
|
||||
if (result46 !== null) {
|
||||
var result40 = result46;
|
||||
|
@ -466,7 +491,7 @@ PEG.grammarParser = (function(){
|
|||
this._pos = savedPos7;
|
||||
}
|
||||
var result42 = result43 !== null
|
||||
? (function($1, $2) { return new PEG.Grammar.OneOrMore($1); }).apply(null, result43)
|
||||
? (function($1, $2) { return { type: "one_or_more", expression: $1}; }).apply(null, result43)
|
||||
: null;
|
||||
if (result42 !== null) {
|
||||
var result40 = result42;
|
||||
|
@ -557,28 +582,28 @@ PEG.grammarParser = (function(){
|
|||
this._pos = savedPos11;
|
||||
}
|
||||
var result66 = result67 !== null
|
||||
? (function($1, $2) { return new PEG.Grammar.RuleRef($1); }).apply(null, result67)
|
||||
? (function($1, $2) { return { type: "rule_ref", name: $1 }; }).apply(null, result67)
|
||||
: null;
|
||||
if (result66 !== null) {
|
||||
var result54 = result66;
|
||||
} else {
|
||||
var result65 = this._parse_literal(context);
|
||||
var result64 = result65 !== null
|
||||
? (function($1) { return new PEG.Grammar.Literal($1); })(result65)
|
||||
? (function($1) { return { type: "literal", value: $1 }; })(result65)
|
||||
: null;
|
||||
if (result64 !== null) {
|
||||
var result54 = result64;
|
||||
} else {
|
||||
var result63 = this._parse_dot(context);
|
||||
var result62 = result63 !== null
|
||||
? (function($1) { return new PEG.Grammar.Any(); })(result63)
|
||||
? (function($1) { return { type: "any" }; })(result63)
|
||||
: null;
|
||||
if (result62 !== null) {
|
||||
var result54 = result62;
|
||||
} else {
|
||||
var result61 = this._parse_class(context);
|
||||
var result60 = result61 !== null
|
||||
? (function($1) { return new PEG.Grammar.Class($1); })(result61)
|
||||
? (function($1) { return { type: "class", characters: $1 }; })(result61)
|
||||
: null;
|
||||
if (result60 !== null) {
|
||||
var result54 = result60;
|
||||
|
|
|
@ -5,45 +5,70 @@ grammar: __ rule+ {
|
|||
}
|
||||
|
||||
rule: identifier (literal / "") colon expression {
|
||||
return new PEG.Grammar.Rule($1, $2 !== "" ? $2 : null, $4);
|
||||
return {
|
||||
type: "rule",
|
||||
name: $1,
|
||||
displayName: $2 !== "" ? $2 : null,
|
||||
expression: $4
|
||||
};
|
||||
}
|
||||
|
||||
expression: choice
|
||||
|
||||
choice: sequence (slash sequence)* {
|
||||
return $2.length > 0
|
||||
? new PEG.Grammar.Choice([$1].concat(PEG.ArrayUtils.map(
|
||||
if ($2.length > 0) {
|
||||
var alternatives = [$1].concat(PEG.ArrayUtils.map(
|
||||
$2,
|
||||
function(element) { return element[1]; }
|
||||
)))
|
||||
: $1;
|
||||
));
|
||||
return {
|
||||
type: "choice",
|
||||
alternatives: alternatives
|
||||
}
|
||||
} else {
|
||||
return $1;
|
||||
}
|
||||
}
|
||||
|
||||
sequence
|
||||
: prefixed* action {
|
||||
return new PEG.Grammar.Action(
|
||||
$1.length != 1 ? new PEG.Grammar.Sequence($1) : $1[0],
|
||||
$2
|
||||
);
|
||||
var expression = $1.length != 1
|
||||
? {
|
||||
type: "sequence",
|
||||
elements: $1
|
||||
}
|
||||
: $1[0];
|
||||
return {
|
||||
type: "action",
|
||||
expression: expression,
|
||||
action: $2
|
||||
};
|
||||
}
|
||||
/ prefixed* {
|
||||
return $1.length != 1
|
||||
? {
|
||||
type: "sequence",
|
||||
elements: $1
|
||||
}
|
||||
: $1[0];
|
||||
}
|
||||
/ prefixed* { return $1.length != 1 ? new PEG.Grammar.Sequence($1) : $1[0]; }
|
||||
|
||||
prefixed
|
||||
: and suffixed { return new PEG.Grammar.AndPredicate($2); }
|
||||
/ not suffixed { return new PEG.Grammar.NotPredicate($2); }
|
||||
: and suffixed { return { type: "and_predicate", expression: $2 }; }
|
||||
/ not suffixed { return { type: "not_predicate", expression: $2 }; }
|
||||
/ suffixed
|
||||
|
||||
suffixed
|
||||
: primary question { return new PEG.Grammar.Optional($1); }
|
||||
/ primary star { return new PEG.Grammar.ZeroOrMore($1); }
|
||||
/ primary plus { return new PEG.Grammar.OneOrMore($1); }
|
||||
: primary question { return { type: "optional", expression: $1}; }
|
||||
/ primary star { return { type: "zero_or_more", expression: $1}; }
|
||||
/ primary plus { return { type: "one_or_more", expression: $1}; }
|
||||
/ 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.Class($1); }
|
||||
: identifier !(( literal / "") colon) { return { type: "rule_ref", name: $1 }; }
|
||||
/ literal { return { type: "literal", value: $1 }; }
|
||||
/ dot { return { type: "any" }; }
|
||||
/ class { return { type: "class", characters: $1 }; }
|
||||
/ lparen expression rparen { return $2; }
|
||||
|
||||
/* "Lexical" elements */
|
||||
|
|
|
@ -17,53 +17,129 @@ global.grammarParserDoesNotParse = function(input) {
|
|||
module("Grammar Parser");
|
||||
|
||||
with (PEG.Grammar) {
|
||||
var literalAbcd = new Literal("abcd");
|
||||
var literalEfgh = new Literal("efgh");
|
||||
var literalIjkl = new Literal("ijkl");
|
||||
function rule(name, displayName, expression) {
|
||||
return {
|
||||
type: "rule",
|
||||
name: name,
|
||||
displayName: displayName,
|
||||
expression: expression
|
||||
};
|
||||
}
|
||||
|
||||
var optional = new Optional(literalAbcd);
|
||||
function choice(alternatives) {
|
||||
return {
|
||||
type: "choice",
|
||||
alternatives: alternatives
|
||||
};
|
||||
}
|
||||
|
||||
var notAbcd = new NotPredicate(literalAbcd);
|
||||
var notEfgh = new NotPredicate(literalEfgh);
|
||||
var notIjkl = new NotPredicate(literalIjkl);
|
||||
function sequence(elements) {
|
||||
return {
|
||||
type: "sequence",
|
||||
elements: elements
|
||||
};
|
||||
}
|
||||
|
||||
var sequenceEmpty = new Sequence([]);
|
||||
var sequenceNots = new Sequence([notAbcd, notEfgh, notIjkl]);
|
||||
var sequenceLiterals = new Sequence([literalAbcd, literalEfgh, literalIjkl]);
|
||||
function nodeWithExpressionConstructor(type) {
|
||||
return function(expression) {
|
||||
return {
|
||||
type: type,
|
||||
expression: expression
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var andPredicate = nodeWithExpressionConstructor("and_predicate");
|
||||
var notPredicate = nodeWithExpressionConstructor("not_predicate");
|
||||
|
||||
var optional = nodeWithExpressionConstructor("optional");
|
||||
var zeroOrMore = nodeWithExpressionConstructor("zero_or_more");
|
||||
var oneOrMore = nodeWithExpressionConstructor("one_or_more");
|
||||
|
||||
function action(expression, action) {
|
||||
return {
|
||||
type: "action",
|
||||
expression: expression,
|
||||
action: action
|
||||
};
|
||||
};
|
||||
|
||||
function ruleRef(name) {
|
||||
return {
|
||||
type: "rule_ref",
|
||||
name: name
|
||||
};
|
||||
}
|
||||
|
||||
function literal(value) {
|
||||
return {
|
||||
type: "literal",
|
||||
value: value
|
||||
};
|
||||
}
|
||||
|
||||
function any() {
|
||||
return { type: "any" };
|
||||
}
|
||||
|
||||
function klass(characters) {
|
||||
return {
|
||||
type: "class",
|
||||
characters: characters
|
||||
};
|
||||
}
|
||||
|
||||
var literalAbcd = literal("abcd");
|
||||
var literalEfgh = literal("efgh");
|
||||
var literalIjkl = literal("ijkl");
|
||||
|
||||
var optionalLiteral = optional(literalAbcd);
|
||||
|
||||
var notAbcd = notPredicate(literalAbcd);
|
||||
var notEfgh = notPredicate(literalEfgh);
|
||||
var notIjkl = notPredicate(literalIjkl);
|
||||
|
||||
var sequenceEmpty = sequence([]);
|
||||
var sequenceNots = sequence([notAbcd, notEfgh, notIjkl]);
|
||||
var sequenceLiterals = sequence([literalAbcd, literalEfgh, literalIjkl]);
|
||||
|
||||
var choiceLiterals = choice([literalAbcd, literalEfgh, literalIjkl]);
|
||||
|
||||
function oneRuleGrammar(expression) {
|
||||
return { start: new PEG.Grammar.Rule("start", null, expression) };
|
||||
return { start: rule("start", null, expression) };
|
||||
}
|
||||
|
||||
var simpleGrammar = oneRuleGrammar(new Literal("abcd"));
|
||||
var simpleGrammar = oneRuleGrammar(literal("abcd"));
|
||||
|
||||
function identifierGrammar(identifier) {
|
||||
return oneRuleGrammar(new PEG.Grammar.RuleRef(identifier));
|
||||
return oneRuleGrammar(ruleRef(identifier));
|
||||
}
|
||||
|
||||
var literal_ = literal
|
||||
function literalGrammar(literal) {
|
||||
return oneRuleGrammar(new PEG.Grammar.Literal(literal));
|
||||
return oneRuleGrammar(literal_(literal));
|
||||
}
|
||||
|
||||
function classGrammar(chars) {
|
||||
return oneRuleGrammar(new PEG.Grammar.Class(chars));
|
||||
return oneRuleGrammar(klass(chars));
|
||||
}
|
||||
|
||||
var anyGrammar = oneRuleGrammar(new Any());
|
||||
var anyGrammar = oneRuleGrammar(any());
|
||||
|
||||
var action_ = action;
|
||||
function actionGrammar(action) {
|
||||
return oneRuleGrammar(new PEG.Grammar.Action(new PEG.Grammar.Literal("a"), action));
|
||||
return oneRuleGrammar(action_(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"', { a: 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)
|
||||
a: rule("a", null, literalAbcd),
|
||||
b: rule("b", null, literalEfgh),
|
||||
c: rule("c", null, literalIjkl)
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -72,17 +148,12 @@ with (PEG.Grammar) {
|
|||
test("parses rule", function() {
|
||||
grammarParserParses(
|
||||
'start: "abcd" / "efgh" / "ijkl"',
|
||||
oneRuleGrammar(new Choice([literalAbcd, literalEfgh, literalIjkl]))
|
||||
oneRuleGrammar(choiceLiterals)
|
||||
);
|
||||
grammarParserParses(
|
||||
'start "start rule": "abcd" / "efgh" / "ijkl"',
|
||||
{
|
||||
start:
|
||||
new Rule(
|
||||
"start",
|
||||
"start rule",
|
||||
new Choice([literalAbcd, literalEfgh, literalIjkl])
|
||||
)
|
||||
start: rule("start", "start rule", choiceLiterals)
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -91,7 +162,7 @@ with (PEG.Grammar) {
|
|||
test("parses expression", function() {
|
||||
grammarParserParses(
|
||||
'start: "abcd" / "efgh" / "ijkl"',
|
||||
oneRuleGrammar(new Choice([literalAbcd, literalEfgh, literalIjkl]))
|
||||
oneRuleGrammar(choiceLiterals)
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -103,7 +174,7 @@ with (PEG.Grammar) {
|
|||
);
|
||||
grammarParserParses(
|
||||
'start: "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl"',
|
||||
oneRuleGrammar(new Choice([
|
||||
oneRuleGrammar(choice([
|
||||
sequenceLiterals,
|
||||
sequenceLiterals,
|
||||
sequenceLiterals
|
||||
|
@ -115,15 +186,15 @@ with (PEG.Grammar) {
|
|||
test("parses sequence", function() {
|
||||
grammarParserParses(
|
||||
'start: { code }',
|
||||
oneRuleGrammar(new Action(sequenceEmpty, " code "))
|
||||
oneRuleGrammar(action(sequenceEmpty, " code "))
|
||||
);
|
||||
grammarParserParses(
|
||||
'start: !"abcd" { code }',
|
||||
oneRuleGrammar(new Action(notAbcd, " code "))
|
||||
oneRuleGrammar(action(notAbcd, " code "))
|
||||
);
|
||||
grammarParserParses(
|
||||
'start: !"abcd" !"efgh" !"ijkl" { code }',
|
||||
oneRuleGrammar(new Action(sequenceNots, " code "))
|
||||
oneRuleGrammar(action(sequenceNots, " code "))
|
||||
);
|
||||
|
||||
grammarParserParses('start: ', oneRuleGrammar(sequenceEmpty));
|
||||
|
@ -136,16 +207,16 @@ with (PEG.Grammar) {
|
|||
|
||||
/* Canonical prefixed is "!\"abcd\"". */
|
||||
test("parses prefixed", function() {
|
||||
grammarParserParses('start: &"abcd"?', oneRuleGrammar(new AndPredicate(optional)));
|
||||
grammarParserParses('start: !"abcd"?', oneRuleGrammar(new NotPredicate(optional)));
|
||||
grammarParserParses('start: "abcd"?', oneRuleGrammar(optional));
|
||||
grammarParserParses('start: &"abcd"?', oneRuleGrammar(andPredicate(optionalLiteral)));
|
||||
grammarParserParses('start: !"abcd"?', oneRuleGrammar(notPredicate(optionalLiteral)));
|
||||
grammarParserParses('start: "abcd"?', oneRuleGrammar(optionalLiteral));
|
||||
});
|
||||
|
||||
/* Canonical suffixed is "\"abcd\"?". */
|
||||
test("parses suffixed", function() {
|
||||
grammarParserParses('start: "abcd"?', oneRuleGrammar(optional));
|
||||
grammarParserParses('start: "abcd"*', oneRuleGrammar(new ZeroOrMore(literalAbcd)));
|
||||
grammarParserParses('start: "abcd"+', oneRuleGrammar(new OneOrMore(literalAbcd)));
|
||||
grammarParserParses('start: "abcd"?', oneRuleGrammar(optionalLiteral));
|
||||
grammarParserParses('start: "abcd"*', oneRuleGrammar(zeroOrMore(literalAbcd)));
|
||||
grammarParserParses('start: "abcd"+', oneRuleGrammar(oneOrMore(literalAbcd)));
|
||||
grammarParserParses('start: "abcd"', literalGrammar("abcd"));
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue