Traits Meta Level

Traits.lf:
%{ // 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
    

Last modified: 2006-02-11 — Markus Lumpe