AST refactoring 5/6: Make AST classless

redux
David Majda 15 years ago
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
};
}
function choice(alternatives) {
return {
type: "choice",
alternatives: alternatives
};
}
function sequence(elements) {
return {
type: "sequence",
elements: elements
};
}
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
};
}
var optional = new Optional(literalAbcd);
function literal(value) {
return {
type: "literal",
value: value
};
}
function any() {
return { type: "any" };
}
function klass(characters) {
return {
type: "class",
characters: characters
};
}
var notAbcd = new NotPredicate(literalAbcd);
var notEfgh = new NotPredicate(literalEfgh);
var notIjkl = new NotPredicate(literalIjkl);
var literalAbcd = literal("abcd");
var literalEfgh = literal("efgh");
var literalIjkl = literal("ijkl");
var sequenceEmpty = new Sequence([]);
var sequenceNots = new Sequence([notAbcd, notEfgh, notIjkl]);
var sequenceLiterals = new Sequence([literalAbcd, literalEfgh, literalIjkl]);
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,17 +207,17 @@ 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"', literalGrammar("abcd"));
grammarParserParses('start: "abcd"?', oneRuleGrammar(optionalLiteral));
grammarParserParses('start: "abcd"*', oneRuleGrammar(zeroOrMore(literalAbcd)));
grammarParserParses('start: "abcd"+', oneRuleGrammar(oneOrMore(literalAbcd)));
grammarParserParses('start: "abcd"', literalGrammar("abcd"));
});
/* Canonical primary is "\"abcd\"". */

Loading…
Cancel
Save