1
0
Fork 0

Protected trait methods are now mixed in

perfodd
Mike Gerwitz 2014-01-23 01:15:53 -05:00
parent 3724b1bc0d
commit e44ac3190b
2 changed files with 34 additions and 20 deletions

View File

@ -38,7 +38,7 @@ Trait.extend = function( dfn )
// we need at least one abstract member in order to declare a class as
// abstract (in this case, our trait class), so let's create a dummy one
// just in case DFN does not contain any abstract members itself
dfn[ 'abstract protected __$$trait$$' ] = [];
dfn[ 'abstract protected ___$$trait$$' ] = [];
function TraitType()
{
@ -88,7 +88,7 @@ function createConcrete( acls )
{
// start by providing a concrete implementation for our dummy method
var dfn = {
'protected __$$trait$$': function() {},
'protected ___$$trait$$': function() {},
};
// TODO: everything else
@ -111,44 +111,59 @@ function mixin( trait, dfn )
{
// the abstract class hidden within the trait
var acls = trait.__acls,
methods = acls.___$$methods$$,
pub = methods['public'];
methods = acls.___$$methods$$;
// retrieve the private member name that will contain this trait object
var iname = addTraitInst( trait.__ccls, dfn );
// TODO: protected; ignore abstract
for ( var f in pub )
mixMethods( methods['public'], dfn, 'public', iname );
mixMethods( methods['protected'], dfn, 'protected', iname );
return dfn;
}
/**
* Mix methods from SRC into DEST using proxies
*
* @param {Object} src visibility object to scavenge from
* @param {Object} dest destination definition object
* @param {string} vis visibility modifier
* @param {string} ianem proxy destination (trait instance)
*
* @return {undefined}
*/
function mixMethods( src, dest, vis, iname )
{
// TODO: ignore abstract
for ( var f in src )
{
if ( !( Object.hasOwnProperty.call( pub, f ) ) )
if ( !( Object.hasOwnProperty.call( src, f ) ) )
{
continue;
}
// TODO: this is a kluge; we'll use proper reflection eventually,
// but for now, this is how we determine if this is an actual public
// method vs. something that just happens to be on the public
// visibility object
if ( !( pub[ f ].___$$keywords$$ ) )
// but for now, this is how we determine if this is an actual method
// vs. something that just happens to be on the visibility object
if ( !( src[ f ].___$$keywords$$ ) || f === '___$$trait$$' )
{
continue;
}
var pname = 'public proxy ' + f;
var pname = vis + ' proxy ' + f;
// if we have already set up a proxy for a field of this name, then
// multiple traits have defined the same concrete member
if ( dfn[ pname ] !== undefined )
if ( dest[ pname ] !== undefined )
{
// TODO: between what traits?
throw Error( "Trait member conflict: `" + f + "'" );
}
// proxy this method to what will be the encapsulated trait object
dfn[ pname ] = iname;
dest[ pname ] = iname;
}
return dfn;
}

View File

@ -45,18 +45,17 @@ require( 'common' ).testCase(
],
// should (at least for the time being) be picked up by existing
// class error checks
// class error checks; TODO: but let's provide trait-specific
// error messages to avoid frustration and infuriation
[ 'foo', "varying keywords; same visibility",
{ 'virtual public foo': function() {} },
{ 'public virtual foo': function() {} },
],
/* TODO
[ 'foo', "different visibility",
{ 'public foo': function() {} },
{ 'protected foo': function() {} },
],
*/
];
},
@ -234,7 +233,7 @@ require( 'common' ).testCase(
// caused the error
this.assertOk(
e.message.match( '\\b' + fname + '\\b' ),
"Missing field name"
"Error message missing field name: " + e.message
);
// TODO: we can also make less people hate us if we include the