@ -265,7 +265,7 @@ PEG.compiler.emitter = function(ast) {
' throw new Error("Invalid rule name: " + quote(startRule) + ".");' ,
' throw new Error("Invalid rule name: " + quote(startRule) + ".");' ,
' }' ,
' }' ,
' } else {' ,
' } else {' ,
' startRule = #{string( startRule)};',
' startRule = #{string( node. startRule)};',
' }' ,
' }' ,
' ' ,
' ' ,
' var pos = 0;' ,
' var pos = 0;' ,
@ -390,8 +390,8 @@ PEG.compiler.emitter = function(ast) {
' return { line: line, column: column };' ,
' return { line: line, column: column };' ,
' }' ,
' }' ,
' ' ,
' ' ,
' #if initializerCode !== "" ',
' #if node. initializer',
' #block initializerCode ',
' #block emit(node.initializer) ',
' #end' ,
' #end' ,
' ' ,
' ' ,
' var result = parseFunctions[startRule]();' ,
' var result = parseFunctions[startRule]();' ,
@ -488,126 +488,126 @@ PEG.compiler.emitter = function(ast) {
' return cachedResult.result;' ,
' return cachedResult.result;' ,
' }' ,
' }' ,
' ' ,
' ' ,
' #if resultVars.length > 0',
' #if node. resultVars.length > 0',
' var #{ resultVars.join(", ")};',
' var #{ node. resultVars.join(", ")};',
' #end' ,
' #end' ,
' #if posVars.length > 0',
' #if node. posVars.length > 0',
' var #{ posVars.join(", ")};',
' var #{ node. posVars.join(", ")};',
' #end' ,
' #end' ,
' ' ,
' ' ,
' #if node.displayName !== null' ,
' #if node.displayName !== null' ,
' reportFailures++;' ,
' reportFailures++;' ,
' #end' ,
' #end' ,
' #block code ',
' #block emit(node.expression) ',
' #if node.displayName !== null' ,
' #if node.displayName !== null' ,
' reportFailures--;' ,
' reportFailures--;' ,
' if (reportFailures === 0 && #{ resultVar} === null) {',
' if (reportFailures === 0 && #{ node. resultVar} === null) {',
' matchFailed(#{string(node.displayName)});' ,
' matchFailed(#{string(node.displayName)});' ,
' }' ,
' }' ,
' #end' ,
' #end' ,
' ' ,
' ' ,
' cache[cacheKey] = {' ,
' cache[cacheKey] = {' ,
' nextPos: pos,' ,
' nextPos: pos,' ,
' result: #{ resultVar}',
' result: #{ node. resultVar}',
' };' ,
' };' ,
' return #{ resultVar};',
' return #{ node. resultVar};',
'}'
'}'
] ,
] ,
choice : [
choice : [
'#block currentAlternativeCode ',
'#block emit(alternative) ',
'#block nextAlternativesCode'
'#block nextAlternativesCode'
] ,
] ,
"choice.next" : [
"choice.next" : [
'if (#{ resultVar} === null) {',
'if (#{ node. resultVar} === null) {',
' #block code' ,
' #block code' ,
'}'
'}'
] ,
] ,
sequence : [
sequence : [
'#{ posVar} = pos;',
'#{ node. posVar} = pos;',
'#block code'
'#block code'
] ,
] ,
"sequence.iteration" : [
"sequence.iteration" : [
'#block e lementCode ',
'#block e mit(element) ',
'if (#{element R esultVar} !== null) {',
'if (#{element .r esultVar} !== null) {',
' #block code' ,
' #block code' ,
'} else {' ,
'} else {' ,
' #{ resultVar} = null;',
' #{ node. resultVar} = null;',
' pos = #{ posVar};',
' pos = #{ node. posVar};',
'}'
'}'
] ,
] ,
"sequence.inner" : [
"sequence.inner" : [
'#{ resultVar} = [#{elementResultVars .join(", ")}];'
'#{ node.resultVar} = [#{pluck(node.elements, "resultVar") .join(", ")}];'
] ,
] ,
simple _and : [
simple _and : [
'#{ posVar} = pos;',
'#{ node. posVar} = pos;',
'reportFailures++;' ,
'reportFailures++;' ,
'#block e xpressionCode ',
'#block e mit(node.expression) ',
'reportFailures--;' ,
'reportFailures--;' ,
'if (#{ resultVar} !== null) {',
'if (#{ node. resultVar} !== null) {',
' #{ resultVar} = "";',
' #{ node. resultVar} = "";',
' pos = #{ posVar};',
' pos = #{ node. posVar};',
'} else {' ,
'} else {' ,
' #{ resultVar} = null;',
' #{ node. resultVar} = null;',
'}'
'}'
] ,
] ,
simple _not : [
simple _not : [
'#{ posVar} = pos;',
'#{ node. posVar} = pos;',
'reportFailures++;' ,
'reportFailures++;' ,
'#block e xpressionCode ',
'#block e mit(node.expression) ',
'reportFailures--;' ,
'reportFailures--;' ,
'if (#{ resultVar} === null) {',
'if (#{ node. resultVar} === null) {',
' #{ resultVar} = "";',
' #{ node. resultVar} = "";',
'} else {' ,
'} else {' ,
' #{ resultVar} = null;',
' #{ node. resultVar} = null;',
' pos = #{ posVar};',
' pos = #{ node. posVar};',
'}'
'}'
] ,
] ,
semantic _and : [
semantic _and : [
'#{ resultVar} = (function() {#{node.code}})() ? "" : null;'
'#{ node. resultVar} = (function() {#{node.code}})() ? "" : null;'
] ,
] ,
semantic _not : [
semantic _not : [
'#{ resultVar} = (function() {#{node.code}})() ? null : "";'
'#{ node. resultVar} = (function() {#{node.code}})() ? null : "";'
] ,
] ,
optional : [
optional : [
'#block e xpressionCode ',
'#block e mit(node.expression) ',
'#{ resultVar} = #{resultVar} !== null ? #{resultVar} : "";'
'#{ node. resultVar} = #{node. resultVar} !== null ? #{node. resultVar} : "";'
] ,
] ,
zero _or _more : [
zero _or _more : [
'#{ resultVar} = [];',
'#{ node. resultVar} = [];',
'#block e xpressionCode ',
'#block e mit(node.expression) ',
'while (#{ expressionR esultVar} !== null) {',
'while (#{ node.expression.r esultVar} !== null) {',
' #{ resultVar}.push(#{expressionR esultVar});',
' #{ node.resultVar}.push(#{node.expression.r esultVar});',
' #block e xpressionCode ',
' #block e mit(node.expression) ',
'}'
'}'
] ,
] ,
one _or _more : [
one _or _more : [
'#block e xpressionCode ',
'#block e mit(node.expression) ',
'if (#{ expressionR esultVar} !== null) {',
'if (#{ node.expression.r esultVar} !== null) {',
' #{ resultVar} = [];',
' #{ node. resultVar} = [];',
' while (#{ expressionR esultVar} !== null) {',
' while (#{ node.expression.r esultVar} !== null) {',
' #{ resultVar}.push(#{expressionR esultVar});',
' #{ node.resultVar}.push(#{node.expression.r esultVar});',
' #block e xpressionCode ',
' #block e mit(node.expression) ',
' }' ,
' }' ,
'} else {' ,
'} else {' ,
' #{ resultVar} = null;',
' #{ node. resultVar} = null;',
'}'
'}'
] ,
] ,
action : [
action : [
'#{ posVar} = pos;',
'#{ node. posVar} = pos;',
'#block e xpressionCode ',
'#block e mit(node.expression) ',
'if (#{ resultVar} !== null) {',
'if (#{ node. resultVar} !== null) {',
' #{ resultVar} = (function(#{formalParams.join(", ")}) {#{node.code}})(#{actualParams.join(", ")});',
' #{ node. resultVar} = (function(#{formalParams.join(", ")}) {#{node.code}})(#{actualParams.join(", ")});',
'}' ,
'}' ,
'if (#{ resultVar} === null) {',
'if (#{ node. resultVar} === null) {',
' pos = #{ posVar};',
' pos = #{ node. posVar};',
'}'
'}'
] ,
] ,
rule _ref : [
rule _ref : [
'#{ resultVar} = parse_#{node.name}();'
'#{ node. resultVar} = parse_#{node.name}();'
] ,
] ,
literal : [
literal : [
'#if node.value.length === 0' ,
'#if node.value.length === 0' ,
' #{ resultVar} = "";',
' #{ node. resultVar} = "";',
'#else' ,
'#else' ,
' #if !node.ignoreCase' ,
' #if !node.ignoreCase' ,
' #if node.value.length === 1' ,
' #if node.value.length === 1' ,
@ -627,13 +627,13 @@ PEG.compiler.emitter = function(ast) {
' if (input.substr(pos, #{node.value.length}).toLowerCase() === #{string(node.value.toLowerCase())}) {' ,
' if (input.substr(pos, #{node.value.length}).toLowerCase() === #{string(node.value.toLowerCase())}) {' ,
' #end' ,
' #end' ,
' #if !node.ignoreCase' ,
' #if !node.ignoreCase' ,
' #{ resultVar} = #{string(node.value)};',
' #{ node. resultVar} = #{string(node.value)};',
' #else' ,
' #else' ,
' #{ resultVar} = input.substr(pos, #{node.value.length});',
' #{ node. resultVar} = input.substr(pos, #{node.value.length});',
' #end' ,
' #end' ,
' pos += #{node.value.length};' ,
' pos += #{node.value.length};' ,
' } else {' ,
' } else {' ,
' #{ resultVar} = null;',
' #{ node. resultVar} = null;',
' if (reportFailures === 0) {' ,
' if (reportFailures === 0) {' ,
' matchFailed(#{string(string(node.value))});' ,
' matchFailed(#{string(string(node.value))});' ,
' }' ,
' }' ,
@ -642,10 +642,10 @@ PEG.compiler.emitter = function(ast) {
] ,
] ,
any : [
any : [
'if (input.length > pos) {' ,
'if (input.length > pos) {' ,
' #{ resultVar} = input.charAt(pos);',
' #{ node. resultVar} = input.charAt(pos);',
' pos++;' ,
' pos++;' ,
'} else {' ,
'} else {' ,
' #{ resultVar} = null;',
' #{ node. resultVar} = null;',
' if (reportFailures === 0) {' ,
' if (reportFailures === 0) {' ,
' matchFailed("any character");' ,
' matchFailed("any character");' ,
' }' ,
' }' ,
@ -653,10 +653,10 @@ PEG.compiler.emitter = function(ast) {
] ,
] ,
"class" : [
"class" : [
'if (#{regexp}.test(input.charAt(pos))) {' ,
'if (#{regexp}.test(input.charAt(pos))) {' ,
' #{ resultVar} = input.charAt(pos);',
' #{ node. resultVar} = input.charAt(pos);',
' pos++;' ,
' pos++;' ,
'} else {' ,
'} else {' ,
' #{ resultVar} = null;',
' #{ node. resultVar} = null;',
' if (reportFailures === 0) {' ,
' if (reportFailures === 0) {' ,
' matchFailed(#{string(node.rawText)});' ,
' matchFailed(#{string(node.rawText)});' ,
' }' ,
' }' ,
@ -673,18 +673,18 @@ PEG.compiler.emitter = function(ast) {
function fill ( name , vars ) {
function fill ( name , vars ) {
vars . string = quote ;
vars . string = quote ;
vars . pluck = pluck ;
vars . emit = emit ;
return templates [ name ] ( vars ) ;
return templates [ name ] ( vars ) ;
}
}
function resultVar ( index ) { return "result" + index ; }
function emitSimple ( name ) {
function posVar ( index ) { return "pos" + index ; }
return function ( node ) { return fill ( name , { node : node } ) ; } ;
}
var emit = buildNodeVisitor ( {
var emit = buildNodeVisitor ( {
grammar : function ( node ) {
grammar : function ( node ) {
var initializerCode = node . initializer !== null
? emit ( node . initializer )
: "" ;
var name ;
var name ;
var parseFunctionTableItems = [ ] ;
var parseFunctionTableItems = [ ] ;
@ -699,38 +699,15 @@ PEG.compiler.emitter = function(ast) {
}
}
return fill ( "grammar" , {
return fill ( "grammar" , {
i nitializerC ode: i nitializerC ode,
node: node,
parseFunctionTableItems : parseFunctionTableItems ,
parseFunctionTableItems : parseFunctionTableItems ,
parseFunctionDefinitions : parseFunctionDefinitions ,
parseFunctionDefinitions : parseFunctionDefinitions
startRule : node . startRule
} ) ;
} ) ;
} ,
} ,
initializer : function ( node ) {
initializer : function ( node ) { return node . code ; } ,
return node . code ;
} ,
rule : function ( node ) {
rule : emitSimple ( "rule" ) ,
var context = {
resultIndex : 0 ,
posIndex : 0 ,
delta : function ( resultIndexDelta , posIndexDelta ) {
return {
resultIndex : this . resultIndex + resultIndexDelta ,
posIndex : this . posIndex + posIndexDelta ,
delta : this . delta
} ;
}
} ;
return fill ( "rule" , {
node : node ,
resultVars : map ( range ( node . resultStackDepth ) , resultVar ) ,
posVars : map ( range ( node . posStackDepth ) , posVar ) ,
code : emit ( node . expression , context ) ,
resultVar : resultVar ( context . resultIndex )
} ) ;
} ,
/ *
/ *
* The contract for all code fragments generated by the following functions
* The contract for all code fragments generated by the following functions
@ -742,126 +719,59 @@ PEG.compiler.emitter = function(ast) {
*
*
* * If the code fragment matches the input , it advances | pos | to point to
* * If the code fragment matches the input , it advances | pos | to point to
* the first chracter following the matched part of the input and sets
* the first chracter following the matched part of the input and sets
* variable with a name computed by calling
* variable with a name stored in | node . resultVar | to an appropriate
* | resultVar ( context . resultIndex ) | to an appropriate value . This value is
* value . This value is always non - | null | .
* always non - | null | .
*
*
* * If the code fragment does not match the input , it returns with | pos |
* * If the code fragment does not match the input , it returns with | pos |
* set to the original value and it sets a variable with a name computed
* set to the original value and it sets a variable with a name stored in
* by calling | resultVar ( context . resultIndex ) | to | null | .
* | node . resultVar | to | null | .
*
*
* The code can use variables with names computed by calling
* The code can use variables with names stored in | resultVar | and | posVar |
*
* properties of the current node 's subnodes. It can' t use any other
* | resultVar ( context . resultIndex + i ) |
* variables .
*
* and
*
* | posVar ( context . posIndex + i ) |
*
* where | i | >= 1 to store necessary data ( return values and positions ) . It
* won ' t use any other variables .
* /
* /
choice : function ( node , context ) {
choice : function ( node ) {
var code , nextAlternativesCode ;
var code , nextAlternativesCode ;
for ( var i = node . alternatives . length - 1 ; i >= 0 ; i -- ) {
for ( var i = node . alternatives . length - 1 ; i >= 0 ; i -- ) {
nextAlternativesCode = i !== node . alternatives . length - 1
nextAlternativesCode = i !== node . alternatives . length - 1
? fill ( "choice.next" , {
? fill ( "choice.next" , { node : node , code : code } )
code : code ,
resultVar : resultVar ( context . resultIndex )
} )
: '' ;
: '' ;
code = fill ( "choice" , {
code = fill ( "choice" , {
currentAlternativeCode: emit ( node . alternatives [ i ] , context ) ,
alternative : node . alternatives [ i ] ,
nextAlternativesCode : nextAlternativesCode
nextAlternativesCode : nextAlternativesCode
} ) ;
} ) ;
}
}
return code ;
return code ;
} ,
} ,
sequence : function ( node , context ) {
sequence : function ( node ) {
var elementResultVars = map ( node . elements , function ( element , i ) {
var code = fill ( "sequence.inner" , { node : node } ) ;
return resultVar ( context . resultIndex + i ) ;
} ) ;
var code = fill ( "sequence.inner" , {
resultVar : resultVar ( context . resultIndex ) ,
elementResultVars : elementResultVars
} ) ;
for ( var i = node . elements . length - 1 ; i >= 0 ; i -- ) {
for ( var i = node . elements . length - 1 ; i >= 0 ; i -- ) {
code = fill ( "sequence.iteration" , {
code = fill ( "sequence.iteration" , {
elementCode : emit ( node . elements [ i ] , context . delta ( i , 1 ) ) ,
node : node ,
elementResultVar : elementResultVars [ i ] ,
element : node . elements [ i ] ,
code : code ,
code : code
posVar : posVar ( context . posIndex ) ,
resultVar : resultVar ( context . resultIndex )
} ) ;
} ) ;
}
}
return fill ( "sequence" , { code : code , posVar : posVar ( context . posIndex ) } ) ;
return fill ( "sequence" , { node : node , code : code } ) ;
} ,
labeled : function ( node , context ) {
return emit ( node . expression , context ) ;
} ,
simple _and : function ( node , context ) {
return fill ( "simple_and" , {
expressionCode : emit ( node . expression , context . delta ( 0 , 1 ) ) ,
posVar : posVar ( context . posIndex ) ,
resultVar : resultVar ( context . resultIndex )
} ) ;
} ,
simple _not : function ( node , context ) {
return fill ( "simple_not" , {
expressionCode : emit ( node . expression , context . delta ( 0 , 1 ) ) ,
posVar : posVar ( context . posIndex ) ,
resultVar : resultVar ( context . resultIndex )
} ) ;
} ,
semantic _and : function ( node , context ) {
return fill ( "semantic_and" , {
node : node ,
resultVar : resultVar ( context . resultIndex )
} ) ;
} ,
} ,
semantic _not : function ( node , context ) {
labeled : function ( node ) { return emit ( node . expression ) ; } ,
return fill ( "semantic_not" , {
node : node ,
resultVar : resultVar ( context . resultIndex )
} ) ;
} ,
optional : function ( node , context ) {
simple _and : emitSimple ( "simple_and" ) ,
return fill ( "optional" , {
simple _not : emitSimple ( "simple_not" ) ,
expressionCode : emit ( node . expression , context ) ,
semantic _and : emitSimple ( "semantic_and" ) ,
resultVar : resultVar ( context . resultIndex )
semantic _not : emitSimple ( "semantic_not" ) ,
} ) ;
optional : emitSimple ( "optional" ) ,
} ,
zero _or _more : emitSimple ( "zero_or_more" ) ,
one _or _more : emitSimple ( "one_or_more" ) ,
zero _or _more : function ( node , context ) {
action : function ( node ) {
return fill ( "zero_or_more" , {
expressionCode : emit ( node . expression , context . delta ( 1 , 0 ) ) ,
expressionResultVar : resultVar ( context . resultIndex + 1 ) ,
resultVar : resultVar ( context . resultIndex )
} ) ;
} ,
one _or _more : function ( node , context ) {
return fill ( "one_or_more" , {
expressionCode : emit ( node . expression , context . delta ( 1 , 0 ) ) ,
expressionResultVar : resultVar ( context . resultIndex + 1 ) ,
resultVar : resultVar ( context . resultIndex )
} ) ;
} ,
action : function ( node , context ) {
/ *
/ *
* In case of sequences , we splat their elements into function arguments
* In case of sequences , we splat their elements into function arguments
* one by one . Example :
* one by one . Example :
@ -881,12 +791,12 @@ PEG.compiler.emitter = function(ast) {
each ( node . expression . elements , function ( element , i ) {
each ( node . expression . elements , function ( element , i ) {
if ( element . type === "labeled" ) {
if ( element . type === "labeled" ) {
formalParams . push ( element . label ) ;
formalParams . push ( element . label ) ;
actualParams . push ( resultVar( context . resultIndex ) + '[' + i + ']' ) ;
actualParams . push ( node. resultVar + '[' + i + ']' ) ;
}
}
} ) ;
} ) ;
} else if ( node . expression . type === "labeled" ) {
} else if ( node . expression . type === "labeled" ) {
formalParams = [ node . expression . label ] ;
formalParams = [ node . expression . label ] ;
actualParams = [ resultVar( context . resultIndex ) ] ;
actualParams = [ node. resultVar ] ;
} else {
} else {
formalParams = [ ] ;
formalParams = [ ] ;
actualParams = [ ] ;
actualParams = [ ] ;
@ -894,33 +804,16 @@ PEG.compiler.emitter = function(ast) {
return fill ( "action" , {
return fill ( "action" , {
node : node ,
node : node ,
expressionCode : emit ( node . expression , context . delta ( 0 , 1 ) ) ,
formalParams : formalParams ,
formalParams : formalParams ,
actualParams : actualParams ,
actualParams : actualParams
posVar : posVar ( context . posIndex ) ,
resultVar : resultVar ( context . resultIndex )
} ) ;
} ,
rule _ref : function ( node , context ) {
return fill ( "rule_ref" , {
node : node ,
resultVar : resultVar ( context . resultIndex )
} ) ;
} ) ;
} ,
} ,
literal : function ( node , context ) {
rule _ref : emitSimple ( "rule_ref" ) ,
return fill ( "literal" , {
literal : emitSimple ( "literal" ) ,
node : node ,
any : emitSimple ( "any" ) ,
resultVar : resultVar ( context . resultIndex )
} ) ;
} ,
any : function ( node , context ) {
"class" : function ( node ) {
return fill ( "any" , { resultVar : resultVar ( context . resultIndex ) } ) ;
} ,
"class" : function ( node , context ) {
var regexp ;
var regexp ;
if ( node . parts . length > 0 ) {
if ( node . parts . length > 0 ) {
@ -942,11 +835,7 @@ PEG.compiler.emitter = function(ast) {
regexp = node . inverted ? '/^[\\S\\s]/' : '/^(?!)/' ;
regexp = node . inverted ? '/^[\\S\\s]/' : '/^(?!)/' ;
}
}
return fill ( "class" , {
return fill ( "class" , { node : node , regexp : regexp } ) ;
node : node ,
regexp : regexp ,
resultVar : resultVar ( context . resultIndex )
} ) ;
}
}
} ) ;
} ) ;