| |
%{ // Traits meta model
class MetaTrait
{
private String fName;
public String getName() { return fName; }
private Form fProvides;
public Form getProvides() { return fProvides; }
private Form fRequires;
public Form getRequires() { return fRequires; }
private Form fOrigins;
public Form getOrigins() { return fOrigins; }
public MetaTrait( String aName, Form aProvides, Form aRequires, Form aOrigins )
{
fName = aName;
fProvides = aProvides;
fRequires = aRequires;
fOrigins = aOrigins;
}
}
private static int fVersions = 0;
public static String newVersion( String aTraitName )
{
return aTraitName + ":" + (new Integer( fVersions++ )).toString();
}
private Hashtable fTraits = new Hashtable();
private Label traitLabel = new Label( new Identifier( "traitName" ), -1 );
private FormValue registerTrait( String aTraitName, Form aProvides,
Form aRequires, Form aOrigins )
{
MetaTrait lNewTrait = new MetaTrait( aTraitName, aProvides, aRequires, aOrigins );
// register trait
fTraits.put( aTraitName, lNewTrait );
// build external representation of trait (NF)
Map lElements;
if ( aProvides instanceof NormalizedForm )
{
lElements = new Hashtable( ((NormalizedForm)aProvides).getBindings() );
}
else
{
// aProvides must be empty
lElements = new Hashtable();
}
lElements.put( "traitName",
new NormalizedBinding( -1, new StringValue( aTraitName ) ) );
// return external representation of trait
return new FormValue( new NormalizedForm( lElements ) );
}
}%
let
newTraitVersion =
%{
return new StringValue( newVersion( ((StringValue)aArg).getValue() ) );
}%
registerTrait =
%{
/*
aArg contains: traitName, provides, requires, origins
traitName : String
provides : form containing methods
requires : form containing bindings the map method names to a String rep of method name
origins : origin of methods in provides
*/
Form lArg = ((FormValue)aArg).getForm();
String lTraitName = null;
Form lProvides = null;
Form lRequires = null;
Form lOrigins = null;
try
{
lTraitName = ((StringValue)lArg.project( "traitName" )).getValue();
lProvides = lArg.dereference( "provides" );
lRequires = lArg.dereference( "requires" );
lOrigins = lArg.dereference( "origins" );
}
catch (FormException e)
{
System.out.println( "Error: " + e.getMessage() );
System.exit( 0 );
}
return registerTrait( lTraitName, lProvides, lRequires, lOrigins );
}% : FormValue
buildOrigin =
%{
Form lArg = ((FormValue)aArg).getForm();
String lTraitName = null;
Form lProvides = null;
Set lLabels = null;
try
{
lTraitName = ((StringValue)lArg.project( "traitName" )).getValue();
lProvides = lArg.dereference( "provides" );
lLabels = lProvides.getLabels();
}
catch (FormException e)
{
System.out.println( "Error: " + e.getMessage() );
System.exit( 0 );
}
// build a map from method name to trait name
Map lMappings = new Hashtable();
for( Iterator lEnum = lLabels.iterator(); lEnum.hasNext(); )
{
String lLabel = lEnum.next();
lMappings.put( lLabel,
new NormalizedBinding( -1, new StringValue( lTraitName ) ) );
}
return new FormValue( new NormalizedForm( lMappings ) );
}% : FormValue
getTraitInfo =
%{
MetaTrait lMTrait = null;
try
{
Form lTrait = ((FormValue)aArg).getForm();
lMTrait = (MetaTrait)fTraits.get( ((StringValue)lTrait.project( "traitName" )).getValue() );
}
catch (FormException e)
{
System.out.println( "Error: " + e.getMessage() );
System.exit( 0 );
}
Map lMappings = new Hashtable();
lMappings.put( "traitName",
new NormalizedBinding( -1,
new StringValue( lMTrait.getName() ) ) );
lMappings.put( "provides",
new NormalizedBinding( -1,
new FormValue( lMTrait.getProvides() ) ) );
lMappings.put( "requires",
new NormalizedBinding( -1,
new FormValue( lMTrait.getRequires() ) ) );
lMappings.put( "origins",
new NormalizedBinding( -1,
new FormValue( lMTrait.getOrigins() ) ) );
return new FormValue( new NormalizedForm( lMappings ) );
}% : FormValue
is_trait_composition_sound =
%{
Form lForm = ((FormValue)aArg).getForm();
IntegerValue Result = new IntegerValue( 1 );
Form lCommon = null;
Form lLOrigins = null;
Form lROrigins = null;
Set lLabels = null;
try
{
lCommon = lForm.dereference( "common" );
lLOrigins = lForm.dereference( "left_origins" );
lROrigins = lForm.dereference( "right_origins" );
lLabels = lCommon.getLabels();
if ( !(lCommon instanceof EmptyForm) )
{
for( Iterator lEnum = lLabels.iterator(); lEnum.hasNext(); )
{
String lLabel = lEnum.next();
Value lLeft = lLOrigins.project( lLabel );
Value lRight = lROrigins.project( lLabel );
if ( !(lLeft instanceof EpsilonValue) && !(lRight instanceof EpsilonValue) )
// check whether origins are different
if ( !((StringValue)lLeft).getValue().equals( ((StringValue)lRight).getValue() ) )
{
Result = new IntegerValue( 0 );
break;
}
}
}
}
catch (FormException e)
{
System.out.println( "Error: " + e.getMessage() );
System.exit( 0 );
}
return Result;
}% : IntegerValue
build_aliases =
%{
Form lForm = ((FormValue)aArg).getForm();
Map lMappings = new Hashtable();
try
{
Form lSource = lForm.dereference( "source" );
Form lAliases = lForm.dereference( "aliases" );
Value lDoAppend = lForm.project( "do_append_original" );
Set lLabels = lAliases.getLabels();
for( Iterator lEnum = lLabels.iterator(); lEnum.hasNext(); )
{
String lLabel = lEnum.next();
String lAlias = ((StringValue)lAliases.project( lLabel )).getValue();
Value lValue = lSource.select( lLabel );
if ( !(lDoAppend instanceof EpsilonValue) )
{
// Protocol: lValue is a String
String lNewValue = ((StringValue)lValue).getValue();
// Only if string does not already contain ':' marker
if ( lNewValue.indexOf( ':' ) == -1 )
lNewValue = lLabel + ":" + lNewValue;
lValue = new StringValue( lNewValue );
}
lMappings.put( lAlias, new NormalizedBinding( -1, lValue ) );
}
}
catch (FormException e)
{
System.out.println( "Error: " + e.getMessage() );
System.exit( 0 );
}
return new FormValue( new NormalizedForm( lMappings ) );
}% : FormValue
buildAllRequired =
%{
Form lForm = ((FormValue)aArg).getForm();
Form Result = EmptyForm.EMPTY;
try
{
Set lLabels = lForm.getLabels();
for( Iterator lEnum = lLabels.iterator(); lEnum.hasNext(); )
{
String lLabel = lEnum.next();
Result = new FormExtension( Result, lForm.dereference( lLabel ) );
}
}
catch (FormException e)
{
System.out.println( "Error: " + e.getMessage() );
System.exit( 0 );
}
return new FormValue( Result );
}% : FormValue
filter_required =
%{
Form lForm = ((FormValue)aArg).getForm();
Map lMappings = new Hashtable();
try
{
Form lRequired = lForm.dereference( "required" );
Form lProvided = lForm.dereference( "provided" );
Set lLabels = lRequired.getLabels();
// iterate over all provided methods that depend on some other methods (i.e., required)
for( Iterator lEnum = lLabels.iterator(); lEnum.hasNext(); )
{
String lLabel = lEnum.next();
Form lRefs = lRequired.dereference( lLabel ); // aquire required features for method lLabel
// remove provided features
lRefs = new FormRestriction( lRefs, lProvided );
// flatten resulting form
lRefs = FormNormalizer.normalize( lRefs );
// add new dependencies to result
if ( !(lRefs instanceof EmptyForm) )
lMappings.put( lLabel, new NormalizedBinding( -1,
new FormValue( lRefs ) ) );
}
}
catch (FormException e)
{
System.out.println( "Error: " + e.getMessage() );
System.exit( 0 );
}
return new FormValue( new NormalizedForm( lMappings ) );
}% : FormValue
build_base_requires =
%{
Form lForm = ((FormValue)aArg).getForm();
Map lMappings = new Hashtable();
try
{
Form lOrigins = lForm.dereference( "origins" );
Set lRemainingMethodLabels = lOrigins.getLabels();
for( Iterator lEnum = lRemainingMethodLabels.iterator(); lEnum.hasNext(); )
{
String lLabel = lEnum.next();
String lOrigin = ((StringValue)lOrigins.project( lLabel )).getValue();
// find originating trait name
int lColon = lOrigin.indexOf( ':' );
String lTraitName = lColon != -1 ? lOrigin.substring( lColon + 1 ) : lOrigin;
String lMethodName = lColon != -1 ? lOrigin.substring( 0, lColon ) : lLabel;
MetaTrait lMTrait = (MetaTrait)fTraits.get( lTraitName );
// aquire all requires
Form lMTrequires = lMTrait.getRequires();
// aquire method-specific requires
Form lMethodRequires = lMTrequires.dereference( lMethodName );
// build method-specific requires
lMappings.put( lLabel,
new NormalizedBinding( -1,
new FormValue( lMethodRequires ) ) );
}
}
catch (FormException e)
{
System.out.println( "Error: " + e.getMessage() );
System.exit( 0 );
}
return new FormValue( new NormalizedForm( lMappings ) );
}% : FormValue
// profiling
print_normalization_count =
%{
System.out.println( "Normalization count: " + FormNormalizer.normalizer_called );
return EpsilonValue.EPS;
}%
in
(|
newTrait = (\Arg:: registerTrait (| Arg, origins = buildOrigin Arg |) ),
composeTraits =
(\Arg:: let
left = getTraitInfo Arg->left
right = getTraitInfo Arg->right
in
Services.if_2
// check the methods in intersection, when not empty, originate
// from same trait
(is_trait_composition_sound
(| common = Services.intersection (| left = left->provides,
right = right->provides |),
left_origins = left->origins,
right_origins = right->origins |))
($ let
provides = (| (| left->provides |) # (| right->provides |) |)
requires = filter_required
(| required = (| (| left->requires |) # (| right->requires |) |),
provided = provides |)
origins = (| (| left->origins |) # (| right->origins |) |)
in
registerTrait (| traitName = Arg.traitName,
provides = provides,
requires = requires,
origins = origins |)
end)
($ (Services.error "Conflicting trait methods encountered!"))
end),
aliasMethods = (\Arg::
let
trait = getTraitInfo Arg->trait
aliases = Arg->aliases
new_provides = build_aliases (| source = trait->provides, aliases = aliases |)
new_requires = build_aliases (| source = trait->requires, aliases = aliases |)
new_origins = build_aliases (| source = trait->origins,
do_append_original = 1,
aliases = aliases |)
in
registerTrait (| traitName = newTraitVersion trait.traitName,
provides = (| (| (| trait->provides |) \ (| aliases |) |)
# (| new_provides |) |),
requires = (| (| (| trait->requires |) \ (| aliases |) |)
# (| new_requires |) |),
origins = (| (| (| trait->origins |) \ (| aliases |) |)
# (| new_origins |) |) |)
end),
excludeMethods = (\Arg::
let
trait = getTraitInfo Arg->trait
excludes = Arg->excludes
new_provides = (| (| trait->provides |) \ (| excludes |) |)
new_origins = (| (| trait->origins |) \ (| excludes |) |)
base_requires = build_base_requires
(| requires = (| (| trait->requires |) \ (| excludes |) |),
origins = new_origins,
excludes = excludes |)
in
registerTrait (| traitName = newTraitVersion trait.traitName,
provides = new_provides,
requires = filter_required (| required = base_requires,
provided = new_provides |),
origins = new_origins |)
end),
getTraitInfo = getTraitInfo,
pureTrait = (\Trait:: (| (| Trait |) \ (| traitName = Trait.traitName |) |)),
buildAllRequired = buildAllRequired
|)
end
|