Add the ASTVisitor class (#451)
For compatibility with pre-0.11 plugins, this class lives on the same namespace as the orignal visitor helper and also exports a static method called 'build'.
This commit is contained in:
parent
93cc6c5b26
commit
7a19d46e8a
|
@ -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 ) {
|
||||
|
||||
function visitExpression( node ) {
|
||||
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 ) {
|
||||
|
||||
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 ) );
|
||||
|
||||
else
|
||||
|
||||
this.visit( value );
|
||||
|
||||
};
|
||||
|
||||
},
|
||||
|
||||
// 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 visitChildren( children, extraArgs ) {
|
||||
|
||||
const args = [ void 0 ].concat( extraArgs );
|
||||
const cb = extraArgs.length
|
||||
? function withArgs( child ) {
|
||||
: function withArgs( child ) {
|
||||
|
||||
args[ 0 ] = child;
|
||||
visit.apply( null, args );
|
||||
|
||||
}
|
||||
: function withoutArgs( child ) {
|
||||
|
||||
visit( 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 = {
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = visitor;
|
||||
util.each( DEFAULT_FUNCTIONS, ( fn, name ) => {
|
||||
|
||||
ASTVisitor.prototype[ name ] = fn;
|
||||
|
||||
} );
|
||||
|
|
Loading…
Reference in a new issue