/**
 * Module containing the strategies to merge rulesets. 
 *
 * @author Eric Bouwers
 */
module php/strategy/const-prop/ruleset

strategies

  /**
   * Performs a union of the dynamic rulesets used for evaluation. 
   * This strategy also incorperates the saving and merging of the
   * include-state of file inclusion. So it is actually a combination of 
   * propogation and type-state.
   *
   * @param s1 The first strategy to execute
   * @param s2 The second strategy to execute
   */
   php-union-const-prop(s1,s2) =
   (  ((where( dr-get-rule-set(|"EvalInclusionStatus") => original-rule-set
            ; dr-start-change-set(|"EvalInclusionStatus") 
            )         
       ;  s1 
       ) 
         /EvalPHPVar,EvalPHPArray,EvalPHPValId, EvalPHPNextIndex\
       (where( dr-get-rule-set(|"EvalInclusionStatus") => changed-rule-set 
               ; <dr-set-rule-set(|"EvalInclusionStatus")> original-rule-set
               ; dr-start-change-set(|"EvalInclusionStatus")
         )                 
         ; s2
         )                                                    
      ) 
      ; where( <merge-rules-for-include-state>  changed-rule-set)
   ) 
   <+ where(!"Merging of two evaluations failed."; debug(!"Error 002: "))

   /**
    * Performs an intersect operations on the dynamic rule-sets used for
    * evaluation. Placed here for abstraction purposes. This strategy
    * also handles the dynamic rule-set for inclusion.
    *
    * @param s The strategy to execute.
    */
   php-intersect-const-prop(s) = 
   (  // Seems to be the only way to get a change-set without touching the
      // actual implementation of change-sets
       where( dr-get-rule-set(|"EvalInclusionStatus") => original-rule-set
            ; dr-start-change-set(|"EvalInclusionStatus") 
            ; dr-get-rule-set(|"EvalInclusionStatus") => changed-rule-set 
            ; <dr-set-rule-set(|"EvalInclusionStatus")> original-rule-set
            ; dr-start-change-set(|"EvalInclusionStatus")
         )                 
       ; /EvalPHPVar,EvalPHPArray, EvalPHPValId,EvalPHPNextIndex\* s
       ; where( <merge-rules-for-include-state>  changed-rule-set)
   ) 
   <+ where(!"Merging of two evaluations failed."; debug(!"Error 002: "))

   /**
    * Merges the rule-set which is the current term to the current changeset.
    * @type List(ChangeSet) -> List(ChangeSet)
    */
   merge-rules-for-include-state = ?rs1
   ; dr-symbolic-merge-rulesets( inclusion-combine-unit
                               , get-inclusion-status 
                               , aux-EvalInclusionStatus(|(),())
                               , redefine-inclusion-status
                               | rs1
                               , "EvalInclusionStatus")

/**
 * These strategies are part of the boiler-plate code needed for merging dynamic
 * rule-sets. 
 * The strategies where retrieved from the slides of the 2005 Programming
 * Transformation course.
 */
strategies
    /**
     * Merges dynamic rule-sets
     */
    dr-symbolic-merge-rulesets(merge, call, aux, redef | rs1, R) =
        where(
            !rs1 => [ChangeSet(_,_,<id>)|_]        
            ; hashtable-keys                       
            ; map(Snd          
                 ; !(<id>, <merge>(<dr-symbolic-lookup(aux|rs1)>, <call>)) 
                 ; redef )   
            ; dr-get-rule-set(|R) => rs2 => [ChangeSet(_,_,<id>)|_]
            ; hashtable-keys 
            ; map(Snd
                 ; !(<id>, <merge>(<dr-symbolic-lookup(aux|rs1)>, <call>))
                 ; redef) 
            ; dr-commit-change-set(|R) 
        )

    /**
     * Utility
     */
    dr-symbolic-lookup(aux|rs) =
      ?x; <dr-lookup-rule(|x)> rs; ?[<aux>|_]