Put files called lib.dtl first in dependency orderings
[hcoop/domtool2.git] / src / eval.sml
1 (* HCoop Domtool (http://hcoop.sourceforge.net/)
2 * Copyright (c) 2006, Adam Chlipala
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *)
18
19 (* Execution of Domtool programs reduced to primitive actions *)
20
21 structure Eval :> EVAL = struct
22
23 open Ast
24
25 structure SM = StringMap
26
27 fun lookup (evs, ev) =
28 case SM.find (evs, ev) of
29 NONE => raise Fail ("Couldn't find an environment variable "
30 ^ ev ^ " that type-checking has guaranteed")
31 | SOME v => v
32
33 fun printEvs (name, evs) =
34 (print ("Environment " ^ name ^ "\n");
35 SM.appi (fn (name, i) => Print.preface (name, Print.p_exp i)) evs;
36 print "\n")
37
38 val conjoin : Env.env_vars * Env.env_vars -> Env.env_vars =
39 SM.unionWith #2
40
41 fun findPrimitive e =
42 let
43 fun findPrim (e, _) =
44 case e of
45 EVar name => (name, [])
46 | EApp (e1, e2) =>
47 let
48 val (name, args) = findPrim e1
49 in
50 (name, e2 :: args)
51 end
52 | _ => raise Fail "Non-primitive action left after reduction"
53
54 val (name, args) = findPrim e
55 in
56 (name, rev args)
57 end
58
59 fun exec' evs (eAll as (e, _)) =
60 case e of
61 ESkip => SM.empty
62 | ESet (ev, e) => SM.insert (SM.empty, ev, e)
63 | EGet (x, _, ev, e) =>
64 let
65 val e' = Reduce.subst x (lookup (evs, ev)) e
66 in
67 exec' evs (Reduce.reduceExp Env.empty e')
68 end
69 | ESeq es =>
70 let
71 val (new, _) =
72 foldl (fn (e, (new, keep)) =>
73 let
74 val new' = exec' keep e
75 in
76 (conjoin (new, new'),
77 conjoin (keep, new'))
78 end) (SM.empty, evs) es
79 in
80 new
81 end
82 | ELocal (e1, e2) =>
83 let
84 val evs' = exec' evs e1
85 in
86 exec' (conjoin (evs, evs')) e2
87 end
88 | EWith (e1, e2) =>
89 let
90 val (prim, args) = findPrimitive e1
91 in
92 case Env.container prim of
93 NONE => raise Fail "Unbound primitive container"
94 | SOME (action, cleanup) =>
95 let
96 val evs' = action (evs, args)
97 val evs'' = exec' evs e2
98 in
99 cleanup ();
100 evs'
101 end
102 end
103
104 | _ =>
105 let
106 val (prim, args) = findPrimitive eAll
107 in
108 case Env.action prim of
109 NONE => raise Fail "Unbound primitive action"
110 | SOME action => action (evs, List.map (Reduce.reduceExp Env.empty) args)
111 end
112
113 fun exec evs e =
114 let
115 val _ = Env.pre ()
116 val evs' = exec' evs e
117 in
118 Env.post ()
119 end
120
121 end