1
0
Fork 0

Refactored Traits to use propParse hooks

perfodd
Mike Gerwitz 2014-03-11 06:36:45 -04:00
parent 3d47443046
commit 316a7dd703
2 changed files with 80 additions and 22 deletions

View File

@ -487,14 +487,47 @@ exports.prototype.buildMembers = function buildMembers(
virtual_members: memberdest['virtual'], virtual_members: memberdest['virtual'],
}; };
util.propParse( props, { // default member handlers for parser
var handlers = {
each: _parseEach, each: _parseEach,
property: _parseProp, property: _parseProp,
getset: _parseGetSet, getset: _parseGetSet,
method: _parseMethod, method: _parseMethod,
}, context ); };
// process accumulated member state // a custom parser may be provided to hook the below property parser;
// this can be done to save time on post-processing, or alter the
// default behavior of the parser
if ( props.___$$parser$$ )
{
// this isn't something that we actually want to parse
var parser = props.___$$parser$$;
delete props.___$$parser$$;
function hjoin( name, orig )
{
handlers[ name ] = function()
{
var args = Array.prototype.slice.call( arguments );
// invoke the custom handler with the original handler as
// its last argument (which the custom handler may choose
// not to invoke at all)
args.push( orig );
parser[ name ].apply( context, args );
};
}
// this avoids a performance penalty unless the above property is
// set
parser.each && hjoin( 'each', handlers.each );
parser.property && hjoin( 'property', handlers.property );
parser.getset && hjoin( 'getset', handlers.getset );
parser.method && hjoin( 'method', handlers.method );
}
// parse members and process accumulated member state
util.propParse( props, handlers, context );
this._memberBuilder.end( context.state ); this._memberBuilder.end( context.state );
} }

View File

@ -86,6 +86,12 @@ Trait.extend = function( dfn )
// just in case DFN does not contain any abstract members itself // just in case DFN does not contain any abstract members itself
dfn[ 'abstract protected ___$$trait$$' ] = []; dfn[ 'abstract protected ___$$trait$$' ] = [];
// augment the parser to handle our own oddities
dfn.___$$parser$$ = {
each: _parseMember,
property: _parseProps,
};
// give the abstract trait class a distinctive name for debugging // give the abstract trait class a distinctive name for debugging
dfn.__name = '#AbstractTrait#'; dfn.__name = '#AbstractTrait#';
@ -112,16 +118,6 @@ Trait.extend = function( dfn )
return ''+name; return ''+name;
}; };
// traits are not permitted to define constructors
if ( tclass.___$$methods$$['public'].__construct !== undefined )
{
throw Error( "Traits may not define __construct" );
}
// traits have property restrictions
validateProps( tclass.___$$props$$['public'] );
validateProps( tclass.___$$props$$['protected'] );
// invoked to trigger mixin // invoked to trigger mixin
TraitType.__mixin = function( dfn, tc, base ) TraitType.__mixin = function( dfn, tc, base )
{ {
@ -138,30 +134,59 @@ Trait.extend = function( dfn )
}; };
/**
* Verifies trait member restrictions
*
* @param {string} name property name
* @param {*} value property value
* @param {Object} keywords property keywords
* @param {Function} h original handler that we replaced
*
* @return {undefined}
*/
function _parseMember( name, value, keywords, h )
{
// traits are not permitted to define constructors
if ( name === '__construct' )
{
throw Error( "Traits may not define __construct" );
}
// apply original handler
h.apply( this, arguments );
}
/** /**
* Throws error if non-internal property is found within PROPS * Throws error if non-internal property is found within PROPS
* *
* For details and rationale, see the Trait/PropertyTest case. * For details and rationale, see the Trait/PropertyTest case.
* *
* @param {Object} props properties to prohibit * @param {string} name property name
* @param {*} value property value
* @param {Object} keywords property keywords
* @param {Function} h original handler that we replaced
* *
* @return {undefined} * @return {undefined}
*/ */
function validateProps( props ) function _parseProps( name, value, keywords, h )
{ {
for ( var f in props ) // ignore internal properties
if ( name.substr( 0, 3 ) === '___' )
{ {
// ignore internal properties return;
if ( f.substr( 0, 3 ) === '___' ) }
{
continue;
}
if ( !( keywords['private'] ) )
{
throw Error( throw Error(
"Cannot define property `" + f + "'; only private " + "Cannot define property `" + name + "'; only private " +
"properties are permitted within Trait definitions" "properties are permitted within Trait definitions"
); );
} }
// apply original handler
h.apply( this, arguments );
} }