@ -1,370 +1,3 @@
/* PEG.js compiler. */
( function ( undefined ) {
/* ===== PEG ===== */
/* no var */ PEG = { } ;
/ *
* Generates a parser from a specified grammar and returns it .
*
* The grammar must be a string in the format described by the metagramar in the
* metagrammar . pegjs file .
*
* Throws | PEG . parser . SyntaxError | if the grammar contains a syntax error or
* | PEG . GrammarError | if it contains a semantic error . Note that not all errors
* are detected during the generation and some may protrude to the generated
* parser and cause its malfunction .
* /
PEG . buildParser = function ( grammar ) {
return PEG . compiler . compile ( PEG . parser . parse ( grammar ) ) ;
} ;
/* ===== PEG.GrammarError ===== */
/* Thrown when the grammar contains an error. */
PEG . GrammarError = function ( message ) {
this . name = "PEG.GrammarError" ;
this . message = message ;
} ;
PEG . GrammarError . prototype = Error . prototype ;
/* ===== PEG.ArrayUtils ===== */
/* Array manipulation utility functions. */
PEG . ArrayUtils = {
/ *
* The code needs to be in sync with the code template in the compilation
* function for "action" nodes .
* /
contains : function ( array , value ) {
/ *
* Stupid IE does not have Array . prototype . indexOf , otherwise this function
* would be a one - liner .
* /
var length = array . length ;
for ( var i = 0 ; i < length ; i ++ ) {
if ( array [ i ] === value ) {
return true ;
}
}
return false ;
} ,
each : function ( array , callback ) {
var length = array . length ;
for ( var i = 0 ; i < length ; i ++ ) {
callback ( array [ i ] ) ;
}
} ,
map : function ( array , callback ) {
var result = [ ] ;
var length = array . length ;
for ( var i = 0 ; i < length ; i ++ ) {
result [ i ] = callback ( array [ i ] ) ;
}
return result ;
}
} ;
/* ===== PEG.StringUtils ===== */
/* String manipulation utility functions. */
PEG . StringUtils = {
/ *
* Surrounds the string with quotes and escapes characters inside so that the
* result is a valid JavaScript string .
*
* The code needs to be in sync with th code template in the compilation
* function for "action" nodes .
* /
quote : function ( s ) {
/ *
* ECMA - 262 , 5 th ed . , 7.8 . 4 : All characters may appear literally in a string
* literal except for the closing quote character , backslash , carriage
* return , line separator , paragraph separator , and line feed . Any character
* may appear in the form of an escape sequence .
* /
return '"' + s
. replace ( /\\/g , '\\\\' ) // backslash
. replace ( /"/g , '\\"' ) // closing quote character
. replace ( /\r/g , '\\r' ) // carriage return
. replace ( /\u2028/g , '\\u2028' ) // line separator
. replace ( /\u2029/g , '\\u2029' ) // paragraph separator
. replace ( /\n/g , '\\n' ) // line feed
+ '"' ;
}
} ;
/* ===== PEG.RegExpUtils ===== */
/* RegExp manipulation utility functions. */
PEG . RegExpUtils = {
/ *
* Escapes characters inside the string so that it can be used as a list of
* characters in a character class of a regular expression .
* /
quoteForClass : function ( s ) {
/* Based on ECMA-262, 5th ed., 7.8.5 & 15.10.1. */
return s
. replace ( /\\/g , '\\\\' ) // backslash
. replace ( /\0/g , '\\0' ) // null, IE needs this
. replace ( /\//g , '\\/' ) // closing slash
. replace ( /]/g , '\\]' ) // closing bracket
. replace ( /-/g , '\\-' ) // dash
. replace ( /\r/g , '\\r' ) // carriage return
. replace ( /\u2028/g , '\\u2028' ) // line separator
. replace ( /\u2029/g , '\\u2029' ) // paragraph separator
. replace ( /\n/g , '\\n' ) // line feed
}
} ;
/* ===== PEG.compiler ===== */
PEG . compiler = {
/ *
* Generates a parser from a specified grammar AST . Throws | PEG . GrammarError |
* if the AST contains a semantic error . Note that not all errors are detected
* during the generation and some may protrude to the generated parser and
* cause its malfunction .
* /
compile : function ( ast ) {
for ( var i = 0 ; i < this . checks . length ; i ++ ) {
this . checks [ i ] ( ast ) ;
}
for ( var i = 0 ; i < this . passes . length ; i ++ ) {
ast = this . passes [ i ] ( ast ) ;
}
var source = this . emitter ( ast ) ;
var result = eval ( source ) ;
result . _source = source ;
return result ;
}
} ;
/ *
* Checks made on the grammar AST before compilation . Each check is a function
* that is passed the AST and does not return anything . If the check passes , the
* function does not do anything special , otherwise it throws
* | PEG . GrammarError | . The checks are run in sequence in order of their
* definition .
* /
PEG . compiler . checks = [
/* Checks that all referenced rules exist. */
function ( ast ) {
function nop ( ) { }
function checkExpression ( node ) { check ( node . expression ) ; }
function checkSubnodes ( propertyName ) {
return function ( node ) {
PEG . ArrayUtils . each ( node [ propertyName ] , check ) ;
} ;
}
var checkFunctions = {
grammar :
function ( node ) {
for ( var name in node . rules ) {
check ( node . rules [ name ] ) ;
}
} ,
rule : checkExpression ,
choice : checkSubnodes ( "alternatives" ) ,
sequence : checkSubnodes ( "elements" ) ,
labeled : checkExpression ,
simple _and : checkExpression ,
simple _not : checkExpression ,
semantic _and : nop ,
semantic _not : nop ,
optional : checkExpression ,
zero _or _more : checkExpression ,
one _or _more : checkExpression ,
action : checkExpression ,
rule _ref :
function ( node ) {
if ( ast . rules [ node . name ] === undefined ) {
throw new PEG . GrammarError (
"Referenced rule \"" + node . name + "\" does not exist."
) ;
}
} ,
literal : nop ,
any : nop ,
"class" : nop
} ;
function check ( node ) { checkFunctions [ node . type ] ( node ) ; }
check ( ast ) ;
} ,
/* Checks that no left recursion is present. */
function ( ast ) {
function nop ( ) { }
function checkExpression ( node , appliedRules ) {
check ( node . expression , appliedRules ) ;
}
var checkFunctions = {
grammar :
function ( node , appliedRules ) {
for ( var name in node . rules ) {
check ( ast . rules [ name ] , appliedRules ) ;
}
} ,
rule :
function ( node , appliedRules ) {
check ( node . expression , appliedRules . concat ( node . name ) ) ;
} ,
choice :
function ( node , appliedRules ) {
PEG . ArrayUtils . each ( node . alternatives , function ( alternative ) {
check ( alternative , appliedRules ) ;
} ) ;
} ,
sequence :
function ( node , appliedRules ) {
if ( node . elements . length > 0 ) {
check ( node . elements [ 0 ] , appliedRules ) ;
}
} ,
labeled : checkExpression ,
simple _and : checkExpression ,
simple _not : checkExpression ,
semantic _and : nop ,
semantic _not : nop ,
optional : checkExpression ,
zero _or _more : checkExpression ,
one _or _more : checkExpression ,
action : checkExpression ,
rule _ref :
function ( node , appliedRules ) {
if ( PEG . ArrayUtils . contains ( appliedRules , node . name ) ) {
throw new PEG . GrammarError (
"Left recursion detected for rule \"" + node . name + "\"."
) ;
}
check ( ast . rules [ node . name ] , appliedRules ) ;
} ,
literal : nop ,
any : nop ,
"class" : nop
} ;
function check ( node , appliedRules ) {
checkFunctions [ node . type ] ( node , appliedRules ) ;
}
check ( ast , [ ] ) ;
}
] ;
/ *
* Optimalization passes made on the grammar AST before compilation . Each pass
* is a function that is passed the AST and returns a new AST . The AST can be
* modified in - place by the pass . The passes are run in sequence in order of
* their definition .
* /
PEG . compiler . passes = [
/ *
* Removes proxy rules -- that is , rules that only delegate to other rule .
* /
function ( ast ) {
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 = {
grammar :
function ( node , from , to ) {
for ( var name in node . rules ) {
replace ( ast . rules [ name ] , from , to ) ;
}
} ,
rule : replaceInExpression ,
choice : replaceInSubnodes ( "alternatives" ) ,
sequence : replaceInSubnodes ( "elements" ) ,
labeled : replaceInExpression ,
simple _and : replaceInExpression ,
simple _not : replaceInExpression ,
semantic _and : nop ,
semantic _not : nop ,
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 ) ;
}
replace ( ast , from , to ) ;
}
for ( var name in ast . rules ) {
if ( isProxyRule ( ast . rules [ name ] ) ) {
replaceRuleRefs ( ast , ast . rules [ name ] . name , ast . rules [ name ] . expression . name ) ;
if ( name === ast . startRule ) {
ast . startRule = ast . rules [ name ] . expression . name ;
}
delete ast . rules [ name ] ;
}
}
return ast ;
}
] ;
/* Emits the generated code for the AST. */
PEG . compiler . emitter = function ( ast ) {
/ *
@ -1085,5 +718,3 @@ PEG.compiler.emitter = function(ast) {
return emit ( ast ) ;
} ;
} ) ( ) ;