@ -3,60 +3,103 @@
const util = require ( "../util" ) ;
const _ _slice = Array . prototype . slice ;
// Simple AST node visitor builder.
const visitor = {
build ( functions ) {
// Abstract syntax tree visitor for PEG.js
class ASTVisitor {
function visit ( node ) {
// Will traverse the node, strictly assuming the visitor can handle the node type.
visit ( node ) {
return functions [ node . type ] . apply ( null , arguments ) ;
const args = _ _slice . call ( arguments , 0 ) ;
return this [ node . type ] . apply ( this , args ) ;
}
const visitNop = util . noop ;
// Simple AST node visitor builder for PEG.js
static build ( functions ) {
const visitor = new ASTVisitor ( ) ;
util . extend ( visitor , functions ) ;
return visitor . visit . bind ( visitor ) ;
}
}
module . exports = ASTVisitor ;
// Helper's to create visitor's for use with the ASTVisitor class
const on = ASTVisitor . for = {
// Visit a node that is defined as a property on another node
property ( name ) {
function visitExpression ( node ) {
return function visitProperty ( node ) {
const extraArgs = _ _slice . call ( arguments , 1 ) ;
const value = node [ name ] ;
visit . apply ( null , [ node . expression ] . concat ( extraArgs ) ) ;
if ( extraArgs . length )
}
this . visit . apply ( this , [ value ] . concat ( extraArgs ) ) ;
function visitChildren ( children , extraArgs ) {
else
const args = [ void 0 ] . concat ( extraArgs ) ;
const cb = extraArgs . length
? function withArgs ( child ) {
this . visit ( value ) ;
args [ 0 ] = child ;
visit . apply ( null , args ) ;
} ;
} ,
// Visit an array of nodes that are defined as a property on another node
children ( name ) {
return function visitProperty ( node ) {
const args = _ _slice . call ( arguments , 0 ) ;
const children = node [ name ] ;
const visitor = this ;
const cb = args . length < 2
? function withoutArgs ( child ) {
visitor . visit ( child ) ;
}
: function withoutArgs ( child ) {
: function with Args( child ) {
visit ( child ) ;
args [ 0 ] = child ;
visitor . visit . apply ( visitor , args ) ;
} ;
children . forEach ( cb ) ;
}
} ;
} ,
} ;
// Build the default ast visitor functions
const visitNop = util . noop ;
const visitExpression = on . property ( "expression" ) ;
const DEFAULT _FUNCTIONS = {
grammar ( node ) {
const extraArgs = _ _slice . call ( arguments , 1 ) ;
if ( node . initializer ) {
visit . apply ( null , [ node . initializer ] . concat ( extraArgs ) ) ;
this . visit . apply ( this , [ node . initializer ] . concat ( extraArgs ) ) ;
}
node . rules . forEach ( rule => {
visit . apply ( null , [ rule ] . concat ( extraArgs ) ) ;
this . visit . apply ( this , [ rule ] . concat ( extraArgs ) ) ;
} ) ;
@ -65,9 +108,9 @@ const visitor = {
initializer : visitNop ,
rule : visitExpression ,
named : visitExpression ,
choice : util . createVisitor ( "alternatives" , visitChildren ) ,
choice : on . children ( "alternatives" ) ,
action : visitExpression ,
sequence : util . createVisitor ( "elements" , visitChildren ) ,
sequence : on . children ( "elements" ) ,
labeled : visitExpression ,
text : visitExpression ,
simple _and : visitExpression ,
@ -81,14 +124,12 @@ const visitor = {
rule _ref : visitNop ,
literal : visitNop ,
class : visitNop ,
any : visitNop
} ;
any : visitNop ,
util . extend ( functions , DEFAULT _FUNCTIONS ) ;
} ;
return visit ;
util . each ( DEFAULT _FUNCTIONS , ( fn , name ) => {
}
} ;
ASTVisitor . prototype [ name ] = fn ;
module . exports = visitor ;
} ) ;