Skip to content

Instantly share code, notes, and snippets.

@AndreSteenveld
Last active August 29, 2015 14:01
Show Gist options
  • Save AndreSteenveld/425e266cb10775c1f364 to your computer and use it in GitHub Desktop.
Save AndreSteenveld/425e266cb10775c1f364 to your computer and use it in GitHub Desktop.
An implementation of C3mro for squirrel
function C3( ... ){
function c3Merge( supers ){
function head( candidate, sequences ){
foreach( sequence in sequences )
if( sequence.slice( 1 ).find( candidate ) != null )
return false;
return true;
}
local
sequences = supers.map( @( s ) s.slice( 0 ) ),
result = [ ];
while( true ){
local candidate = null;
sequences = sequences.filter( @( i, v ) v.len( ) != 0 );
if( sequences.len( ) == 0 ) return result;
foreach( sequence in sequences ){
candidate = sequence[ 0 ];
if( head( candidate, sequences.slice( 1 ) ) )
break;
else
candidate = null;
}
if( candidate == null )
throw "Inconsistend hierarchy";
result.push( candidate );
foreach( sequence in sequences )
if( sequence[ 0 ] == candidate )
sequence.remove( 0 );
}
return result;
}
foreach( key, super in vargv )
if( vargv.slice( key + 1 ).find( super ) != null )
throw "Duplicate base class [ " + key + " ] == [ " + ( vargv.slice( key + 1 ).find( super ) + key + 1 ) + " ]";
local
bases = vargv.slice( 0 ),
supers = vargv.map( function( clazz ) {
local
current = clazz,
bases = [ ],
attributes = null;
do {
attributes = current.getattributes( null );
if( "C3" in attributes ){
bases.extend( attributes.C3.linerization );
break;
}
bases.push( current );
current = current.getbase( );
} while( current != null )
return bases;
});
supers.insert( 0, bases );
local
super = class { },
linerization = [ ];
if( supers.len( ) != 0 ){
linerization.extend( c3Merge( supers ) );
local index = linerization.len( );
while( 0 <= --index ){
local instance = linerization[ index ].instance( );
// We need to do something with weak refs as well...
foreach( key, value in linerization[ index ] ){
try {
// The proof of the pudding, are we dealing with a real member here...
instance.rawset( key, value );
super.rawnewmember(
key,
linerization[ index ].rawget( key ),
linerization[ index ].getattributes( key ),
false
);
} catch( excp ) {
// We couldn't set the property we are looking this seems to be the only
// thing really seperating statics from instance memebers.
super.rawnewmember(
key,
linerization[ index ].rawget( key ),
linerization[ index ].getattributes( key ),
true
);
}
}
super = class extends super { };
}
}
super.setattributes( null, {
C3 = {
bases = bases,
linerization = linerization
}
});
return super;
}
//
// https://www.python.org/download/releases/2.3/mro/
// https://github.com/dojo/dojo/blob/master/_base/declare.js
// https://github.com/maksimr/c3mro/blob/master/js/c3mro.js
//
class O { constructor( ){ ::print( "O " ); } function method( a ){ return a + "O "; } }
class F extends O { constructor( ){ base.constructor( ); ::print( "F " ); } function method( a ){ return "F " + base.method( a ); } }
class E extends O { constructor( ){ base.constructor( ); ::print( "E " ); } function method( a ){ return "E " + base.method( a ); } }
class D extends O { constructor( ){ base.constructor( ); ::print( "D " ); } function method( a ){ return "D " + base.method( a ); } }
class C extends C3( D, F ){ constructor( ){ base.constructor( ); ::print( "C " ); } function method( a ){ return "C " + base.method( a ); } }
class B extends C3( D, E ){ constructor( ){ base.constructor( ); ::print( "B " ); } function method( a ){ return "B " + base.method( a ); } }
class A extends C3( B, C ){ constructor( ){ base.constructor( ); ::print( "A " ); } function method( a ){ return "A " + base.method( a ); } }
try{
// This is obviously a mistake
class T extends C3( O, O ){ }
}catch( excp ){
::print( excp + "\n" );
}
::print( "constructor order - method order\n" );
::print( "- " + ( O( ) ).method( "" ) + "\n" );
::print( "- " + ( D( ) ).method( "" ) + "\n" );
::print( "- " + ( E( ) ).method( "" ) + "\n" );
::print( "- " + ( F( ) ).method( "" ) + "\n" );
::print( "- " + ( C( ) ).method( "" ) + "\n" );
::print( "- " + ( B( ) ).method( "" ) + "\n" );
::print( "- " + ( A( ) ).method( "" ) + "\n" );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment