AST refactoring 5/6: Make AST classless

redux
David Majda 14 years ago
parent 41abb7ad92
commit b4bf49443a

@ -153,75 +153,6 @@ PEG.Grammar.GrammarError = function(message) {
PEG.Grammar.GrammarError.prototype = Error.prototype; 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 ===== */
PEG.Compiler = { PEG.Compiler = {
@ -715,7 +646,7 @@ PEG.Compiler = {
var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result"); var expressionResultVar = PEG.Compiler.generateUniqueIdentifier("result");
if (node.expression instanceof PEG.Grammar.Sequence) { if (node.expression.type === "sequence") {
var params = PEG.ArrayUtils.map( var params = PEG.ArrayUtils.map(
PEG.ArrayUtils.range(1, node.expression.elements.length + 1), PEG.ArrayUtils.range(1, node.expression.elements.length + 1),
function(n) { return "$" + n; } function(n) { return "$" + n; }

@ -154,7 +154,12 @@ PEG.grammarParser = (function(){
} }
var result5 = result6 !== null var result5 = result6 !== null
? (function($1, $2, $3, $4) { ? (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) }).apply(null, result6)
: null; : null;
@ -247,12 +252,18 @@ PEG.grammarParser = (function(){
} }
var result14 = result15 !== null var result14 = result15 !== null
? (function($1, $2) { ? (function($1, $2) {
return $2.length > 0 if ($2.length > 0) {
? new PEG.Grammar.Choice([$1].concat(PEG.ArrayUtils.map( var alternatives = [$1].concat(PEG.ArrayUtils.map(
$2, $2,
function(element) { return element[1]; } function(element) { return element[1]; }
))) ));
: $1; return {
type: "choice",
alternatives: alternatives
}
} else {
return $1;
}
}).apply(null, result15) }).apply(null, result15)
: null; : null;
@ -297,10 +308,17 @@ PEG.grammarParser = (function(){
} }
var result25 = result26 !== null var result25 = result26 !== null
? (function($1, $2) { ? (function($1, $2) {
return new PEG.Grammar.Action( var expression = $1.length != 1
$1.length != 1 ? new PEG.Grammar.Sequence($1) : $1[0], ? {
$2 type: "sequence",
); elements: $1
}
: $1[0];
return {
type: "action",
expression: expression,
action: $2
};
}).apply(null, result26) }).apply(null, result26)
: null; : null;
if (result25 !== null) { if (result25 !== null) {
@ -313,7 +331,14 @@ PEG.grammarParser = (function(){
var result24 = this._parse_prefixed(context); var result24 = this._parse_prefixed(context);
} }
var result22 = result23 !== null 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; : null;
if (result22 !== null) { if (result22 !== null) {
var result21 = result22; var result21 = result22;
@ -357,7 +382,7 @@ PEG.grammarParser = (function(){
this._pos = savedPos6; this._pos = savedPos6;
} }
var result36 = result37 !== null 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; : null;
if (result36 !== null) { if (result36 !== null) {
var result30 = result36; var result30 = result36;
@ -377,7 +402,7 @@ PEG.grammarParser = (function(){
this._pos = savedPos5; this._pos = savedPos5;
} }
var result32 = result33 !== null 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; : null;
if (result32 !== null) { if (result32 !== null) {
var result30 = result32; var result30 = result32;
@ -426,7 +451,7 @@ PEG.grammarParser = (function(){
this._pos = savedPos9; this._pos = savedPos9;
} }
var result50 = result51 !== null 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; : null;
if (result50 !== null) { if (result50 !== null) {
var result40 = result50; var result40 = result50;
@ -446,7 +471,7 @@ PEG.grammarParser = (function(){
this._pos = savedPos8; this._pos = savedPos8;
} }
var result46 = result47 !== null 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; : null;
if (result46 !== null) { if (result46 !== null) {
var result40 = result46; var result40 = result46;
@ -466,7 +491,7 @@ PEG.grammarParser = (function(){
this._pos = savedPos7; this._pos = savedPos7;
} }
var result42 = result43 !== null 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; : null;
if (result42 !== null) { if (result42 !== null) {
var result40 = result42; var result40 = result42;
@ -557,28 +582,28 @@ PEG.grammarParser = (function(){
this._pos = savedPos11; this._pos = savedPos11;
} }
var result66 = result67 !== null 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; : null;
if (result66 !== null) { if (result66 !== null) {
var result54 = result66; var result54 = result66;
} else { } else {
var result65 = this._parse_literal(context); var result65 = this._parse_literal(context);
var result64 = result65 !== null var result64 = result65 !== null
? (function($1) { return new PEG.Grammar.Literal($1); })(result65) ? (function($1) { return { type: "literal", value: $1 }; })(result65)
: null; : null;
if (result64 !== null) { if (result64 !== null) {
var result54 = result64; var result54 = result64;
} else { } else {
var result63 = this._parse_dot(context); var result63 = this._parse_dot(context);
var result62 = result63 !== null var result62 = result63 !== null
? (function($1) { return new PEG.Grammar.Any(); })(result63) ? (function($1) { return { type: "any" }; })(result63)
: null; : null;
if (result62 !== null) { if (result62 !== null) {
var result54 = result62; var result54 = result62;
} else { } else {
var result61 = this._parse_class(context); var result61 = this._parse_class(context);
var result60 = result61 !== null var result60 = result61 !== null
? (function($1) { return new PEG.Grammar.Class($1); })(result61) ? (function($1) { return { type: "class", characters: $1 }; })(result61)
: null; : null;
if (result60 !== null) { if (result60 !== null) {
var result54 = result60; var result54 = result60;

@ -5,45 +5,70 @@ grammar: __ rule+ {
} }
rule: identifier (literal / "") colon expression { 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 expression: choice
choice: sequence (slash sequence)* { choice: sequence (slash sequence)* {
return $2.length > 0 if ($2.length > 0) {
? new PEG.Grammar.Choice([$1].concat(PEG.ArrayUtils.map( var alternatives = [$1].concat(PEG.ArrayUtils.map(
$2, $2,
function(element) { return element[1]; } function(element) { return element[1]; }
))) ));
: $1; return {
type: "choice",
alternatives: alternatives
}
} else {
return $1;
}
} }
sequence sequence
: prefixed* action { : prefixed* action {
return new PEG.Grammar.Action( var expression = $1.length != 1
$1.length != 1 ? new PEG.Grammar.Sequence($1) : $1[0], ? {
$2 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 prefixed
: and suffixed { return new PEG.Grammar.AndPredicate($2); } : and suffixed { return { type: "and_predicate", expression: $2 }; }
/ not suffixed { return new PEG.Grammar.NotPredicate($2); } / not suffixed { return { type: "not_predicate", expression: $2 }; }
/ suffixed / suffixed
suffixed suffixed
: primary question { return new PEG.Grammar.Optional($1); } : primary question { return { type: "optional", expression: $1}; }
/ primary star { return new PEG.Grammar.ZeroOrMore($1); } / primary star { return { type: "zero_or_more", expression: $1}; }
/ primary plus { return new PEG.Grammar.OneOrMore($1); } / primary plus { return { type: "one_or_more", expression: $1}; }
/ primary / primary
primary primary
: identifier !(( literal / "") colon) { return new PEG.Grammar.RuleRef($1); } : identifier !(( literal / "") colon) { return { type: "rule_ref", name: $1 }; }
/ literal { return new PEG.Grammar.Literal($1); } / literal { return { type: "literal", value: $1 }; }
/ dot { return new PEG.Grammar.Any(); } / dot { return { type: "any" }; }
/ class { return new PEG.Grammar.Class($1); } / class { return { type: "class", characters: $1 }; }
/ lparen expression rparen { return $2; } / lparen expression rparen { return $2; }
/* "Lexical" elements */ /* "Lexical" elements */

@ -17,53 +17,129 @@ global.grammarParserDoesNotParse = function(input) {
module("Grammar Parser"); module("Grammar Parser");
with (PEG.Grammar) { with (PEG.Grammar) {
var literalAbcd = new Literal("abcd"); function rule(name, displayName, expression) {
var literalEfgh = new Literal("efgh"); return {
var literalIjkl = new Literal("ijkl"); 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 literalAbcd = literal("abcd");
var notEfgh = new NotPredicate(literalEfgh); var literalEfgh = literal("efgh");
var notIjkl = new NotPredicate(literalIjkl); var literalIjkl = literal("ijkl");
var sequenceEmpty = new Sequence([]); var optionalLiteral = optional(literalAbcd);
var sequenceNots = new Sequence([notAbcd, notEfgh, notIjkl]);
var sequenceLiterals = new Sequence([literalAbcd, literalEfgh, literalIjkl]); 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) { 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) { function identifierGrammar(identifier) {
return oneRuleGrammar(new PEG.Grammar.RuleRef(identifier)); return oneRuleGrammar(ruleRef(identifier));
} }
var literal_ = literal
function literalGrammar(literal) { function literalGrammar(literal) {
return oneRuleGrammar(new PEG.Grammar.Literal(literal)); return oneRuleGrammar(literal_(literal));
} }
function classGrammar(chars) { 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) { 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\";". */ /* Canonical grammar is "a: \"abcd\";\nb: \"efgh\";\nc: \"ijkl\";". */
test("parses grammar", function() { test("parses grammar", function() {
grammarParserParses('a: "abcd"', { a: new Rule("a", null, literalAbcd) }); grammarParserParses('a: "abcd"', { a: rule("a", null, literalAbcd) });
grammarParserParses( grammarParserParses(
'a: "abcd"\nb: "efgh"\nc: "ijkl"', 'a: "abcd"\nb: "efgh"\nc: "ijkl"',
{ {
a: new Rule("a", null, literalAbcd), a: rule("a", null, literalAbcd),
b: new Rule("b", null, literalEfgh), b: rule("b", null, literalEfgh),
c: new Rule("c", null, literalIjkl) c: rule("c", null, literalIjkl)
} }
); );
}); });
@ -72,17 +148,12 @@ with (PEG.Grammar) {
test("parses rule", function() { test("parses rule", function() {
grammarParserParses( grammarParserParses(
'start: "abcd" / "efgh" / "ijkl"', 'start: "abcd" / "efgh" / "ijkl"',
oneRuleGrammar(new Choice([literalAbcd, literalEfgh, literalIjkl])) oneRuleGrammar(choiceLiterals)
); );
grammarParserParses( grammarParserParses(
'start "start rule": "abcd" / "efgh" / "ijkl"', 'start "start rule": "abcd" / "efgh" / "ijkl"',
{ {
start: start: rule("start", "start rule", choiceLiterals)
new Rule(
"start",
"start rule",
new Choice([literalAbcd, literalEfgh, literalIjkl])
)
} }
); );
}); });
@ -91,7 +162,7 @@ with (PEG.Grammar) {
test("parses expression", function() { test("parses expression", function() {
grammarParserParses( grammarParserParses(
'start: "abcd" / "efgh" / "ijkl"', 'start: "abcd" / "efgh" / "ijkl"',
oneRuleGrammar(new Choice([literalAbcd, literalEfgh, literalIjkl])) oneRuleGrammar(choiceLiterals)
); );
}); });
@ -103,7 +174,7 @@ with (PEG.Grammar) {
); );
grammarParserParses( grammarParserParses(
'start: "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl"', 'start: "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl" / "abcd" "efgh" "ijkl"',
oneRuleGrammar(new Choice([ oneRuleGrammar(choice([
sequenceLiterals, sequenceLiterals,
sequenceLiterals, sequenceLiterals,
sequenceLiterals sequenceLiterals
@ -115,15 +186,15 @@ with (PEG.Grammar) {
test("parses sequence", function() { test("parses sequence", function() {
grammarParserParses( grammarParserParses(
'start: { code }', 'start: { code }',
oneRuleGrammar(new Action(sequenceEmpty, " code ")) oneRuleGrammar(action(sequenceEmpty, " code "))
); );
grammarParserParses( grammarParserParses(
'start: !"abcd" { code }', 'start: !"abcd" { code }',
oneRuleGrammar(new Action(notAbcd, " code ")) oneRuleGrammar(action(notAbcd, " code "))
); );
grammarParserParses( grammarParserParses(
'start: !"abcd" !"efgh" !"ijkl" { code }', 'start: !"abcd" !"efgh" !"ijkl" { code }',
oneRuleGrammar(new Action(sequenceNots, " code ")) oneRuleGrammar(action(sequenceNots, " code "))
); );
grammarParserParses('start: ', oneRuleGrammar(sequenceEmpty)); grammarParserParses('start: ', oneRuleGrammar(sequenceEmpty));
@ -136,17 +207,17 @@ with (PEG.Grammar) {
/* Canonical prefixed is "!\"abcd\"". */ /* Canonical prefixed is "!\"abcd\"". */
test("parses prefixed", function() { test("parses prefixed", function() {
grammarParserParses('start: &"abcd"?', oneRuleGrammar(new AndPredicate(optional))); grammarParserParses('start: &"abcd"?', oneRuleGrammar(andPredicate(optionalLiteral)));
grammarParserParses('start: !"abcd"?', oneRuleGrammar(new NotPredicate(optional))); grammarParserParses('start: !"abcd"?', oneRuleGrammar(notPredicate(optionalLiteral)));
grammarParserParses('start: "abcd"?', oneRuleGrammar(optional)); grammarParserParses('start: "abcd"?', oneRuleGrammar(optionalLiteral));
}); });
/* Canonical suffixed is "\"abcd\"?". */ /* Canonical suffixed is "\"abcd\"?". */
test("parses suffixed", function() { test("parses suffixed", function() {
grammarParserParses('start: "abcd"?', oneRuleGrammar(optional)); grammarParserParses('start: "abcd"?', oneRuleGrammar(optionalLiteral));
grammarParserParses('start: "abcd"*', oneRuleGrammar(new ZeroOrMore(literalAbcd))); grammarParserParses('start: "abcd"*', oneRuleGrammar(zeroOrMore(literalAbcd)));
grammarParserParses('start: "abcd"+', oneRuleGrammar(new OneOrMore(literalAbcd))); grammarParserParses('start: "abcd"+', oneRuleGrammar(oneOrMore(literalAbcd)));
grammarParserParses('start: "abcd"', literalGrammar("abcd")); grammarParserParses('start: "abcd"', literalGrammar("abcd"));
}); });
/* Canonical primary is "\"abcd\"". */ /* Canonical primary is "\"abcd\"". */

Loading…
Cancel
Save