@ -372,6 +372,82 @@ PEG.Compiler = {
}
] ,
/ *
* Optimalization passes made on the grammar AST before compilation . Each pass
* is a function that is passed the AST and start rule and returns a new AST
* and start rule . The AST can be modified in - place by the pass . The passes
* are run in sequence in order of their definition .
* /
_passes : [
/ *
* Removes proxy rules -- that is , rules that only delegate to other rule .
* /
function ( ast , startRule ) {
function isProxyRule ( node ) {
return node . type === "rule" && node . expression . type === "rule_ref" ;
}
function replaceRuleRefs ( ast , from , to ) {
function nop ( ) { }
function replaceInExpression ( node , from , to ) {
replace ( node . expression , from , to ) ;
}
function replaceInSubnodes ( propertyName ) {
return function ( node , from , to ) {
PEG . ArrayUtils . each ( node [ propertyName ] , function ( node ) {
replace ( node , from , to ) ;
} ) ;
} ;
}
var replaceFunctions = {
rule : replaceInExpression ,
choice : replaceInSubnodes ( "alternatives" ) ,
sequence : replaceInSubnodes ( "elements" ) ,
and _predicate : replaceInExpression ,
not _predicate : replaceInExpression ,
optional : replaceInExpression ,
zero _or _more : replaceInExpression ,
one _or _more : replaceInExpression ,
action : replaceInExpression ,
rule _ref :
function ( node , from , to ) {
if ( node . name === from ) {
node . name = to ;
}
} ,
literal : nop ,
any : nop ,
"class" : nop
} ;
function replace ( node , from , to ) {
replaceFunctions [ node . type ] ( node , from , to ) ;
}
for ( var rule in ast ) {
replace ( ast [ rule ] , from , to ) ;
}
}
for ( var rule in ast ) {
if ( isProxyRule ( ast [ rule ] ) ) {
replaceRuleRefs ( ast , ast [ rule ] . name , ast [ rule ] . expression . name ) ;
if ( rule === startRule ) {
startRule = ast [ rule ] . expression . name ;
}
delete ast [ rule ] ;
}
}
return [ ast , startRule ] ;
}
] ,
_compileFunctions : {
rule : function ( node ) {
var resultVar = PEG . Compiler . generateUniqueIdentifier ( "result" ) ;
@ -787,6 +863,12 @@ PEG.Compiler = {
this . _checks [ i ] ( ast , startRule ) ;
}
for ( var i = 0 ; i < this . _passes . length ; i ++ ) {
var newAstNadStartRule = this . _passes [ i ] ( ast , startRule ) ;
ast = newAstNadStartRule [ 0 ] ;
startRule = newAstNadStartRule [ 1 ] ;
}
var parseFunctionDefinitions = [ ] ;
for ( var rule in ast ) {
parseFunctionDefinitions . push ( this . compileNode ( ast [ rule ] ) ) ;