Fix regeneration of multi-file dependencies
[hcoop/domtool2.git] / src / reduce.sml
index 17a8507..9e538d6 100644 (file)
@@ -14,7 +14,7 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-*)
+ *)
 
 (* Evaluation of expressions until only externs are around *)
 
@@ -22,6 +22,8 @@ structure Reduce :> REDUCE = struct
 
 open Ast Print Env
 
+structure SM = StringMap
+
 fun freeIn x (b, _) =
     case b of
        EInt _ => false
@@ -34,10 +36,13 @@ fun freeIn x (b, _) =
 
       | ESkip => false
       | ESet (_, e) => freeIn x e
-      | EGet (x', _, b') => x <> x' andalso freeIn x b'
+      | EGet (x', _, _, b') => x <> x' andalso freeIn x b'
       | ESeq es => List.exists (freeIn x) es
       | ELocal (e1, e2) => freeIn x e1 orelse freeIn x e2
       | EWith (e1, e2) => freeIn x e1 orelse freeIn x e2
+      | EALam (x', _, b') => x <> x' andalso freeIn x b'
+
+      | EIf (e1, e2, e3) => freeIn x e1 orelse freeIn x e2 orelse freeIn x e3
 
 local
     val freshCount = ref 0
@@ -77,20 +82,42 @@ fun subst x e (bAll as (b, loc)) =
 
       | ESkip => bAll
       | ESet (v, b) => (ESet (v, subst x e b), loc)
-      | EGet (x', v, b') =>
+      | EGet (x', topt, v, b') =>
        if x = x' then
            bAll
        else if freeIn x' e then
            let
                val x'' = freshVar ()
            in
-               (EGet (x'', v, subst x e (subst x' (EVar x'', loc) b')), loc)
+               (EGet (x'', topt, v, subst x e (subst x' (EVar x'', loc) b')), loc)
            end
        else
-           (EGet (x', v, subst x e b'), loc)
+           (EGet (x', topt, v, subst x e b'), loc)
       | ESeq es => (ESeq (map (subst x e) es), loc)
       | ELocal (b1, b2) => (ELocal (subst x e b1, subst x e b2), loc)
       | EWith (b1, b2) => (EWith (subst x e b1, subst x e b2), loc)
+      | EALam (x', p, b') =>
+       if x = x' then
+           bAll
+       else if freeIn x' e then
+           let
+               val x'' = freshVar ()
+           in
+               (EALam (x'', p, subst x e (subst x' (EVar x'', loc) b')), loc)
+           end
+       else
+           (EALam (x', p, subst x e b'), loc)
+
+      | EIf (b1, b2, b3) => (EIf (subst x e b1, subst x e b2, subst x e b3), loc)
+
+fun findPrim (e, _) =
+    case e of
+       EApp (f, x) =>
+       (case findPrim f of
+            NONE => NONE
+          | SOME (f, xs) => SOME (f, xs @ [x]))
+      | EVar x => SOME (x, [])
+      | _ => NONE
 
 fun reduceExp G (eAll as (e, loc)) =
     case e of
@@ -110,7 +137,12 @@ fun reduceExp G (eAll as (e, loc)) =
        end
       | EVar x =>
        (case lookupEquation G x of
-            NONE => eAll
+            NONE =>
+            (case function x of
+                 NONE => eAll
+               | SOME f => case f [] of
+                               NONE => eAll
+                             | SOME e' => reduceExp G e')
           | SOME e => reduceExp G e)
       | EApp (e1, e2) =>
        let
@@ -119,14 +151,48 @@ fun reduceExp G (eAll as (e, loc)) =
        in
            case e1' of
                (ELam (x, _, b), _) => reduceExp G (subst x e2' b)
-             | _ => (EApp (e1', e2'), loc)
+             | _ =>
+               case findPrim eAll of
+                   NONE => (EApp (e1', e2'), loc)
+                 | SOME (f, args) =>
+                   case function f of
+                       NONE => (EApp (e1', e2'), loc)
+                     | SOME f => case f (map (reduceExp G) args) of
+                                     NONE => (EApp (e1', e2'), loc)
+                                   | SOME e' => reduceExp G e'
        end
 
       | ESkip => eAll
       | ESet (v, b) => (ESet (v, reduceExp G b), loc)
-      | EGet (x, v, b) => (EGet (x, v, reduceExp G b), loc)
+      | EGet (x, topt, v, b) => (EGet (x, topt, v, reduceExp G b), loc)
       | ESeq es => (ESeq (map (reduceExp G) es), loc)
       | ELocal (e1, e2) => (ELocal (reduceExp G e1, reduceExp G e2), loc)
-      | EWith (e1, e2) => (EWith (reduceExp G e1, reduceExp G e2), loc)
+      | EWith (e1, e2) =>
+       let
+           val e1' = reduceExp G e1
+           val e2' = reduceExp G e2
+       in
+           case e1' of
+               (EALam (x, _, b), _) => reduceExp G (subst x e2' b)
+             | _ => (EWith (e1', e2'), loc)
+       end
+      | EALam (x, p, e) =>
+       let
+           val G' = bindVal G (x, (TAction (p, SM.empty, SM.empty), loc), NONE)
+       in
+           (EALam (x, p, reduceExp G' e), loc)
+       end
+
+      | EIf (e1, e2, e3) =>
+       let
+           val e1' = reduceExp G e1
+           fun e2' () = reduceExp G e2
+           fun e3' () = reduceExp G e3
+       in
+           case e1' of
+               (EVar "true", _) => e2' ()
+             | (EVar "false", _) => e3' ()
+             | _ => (EIf (e1', e2' (), e3' ()), loc)
+       end
 
 end