Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] Annotation of /branches/vis15/src/compiler/typechecker/check-var-uses.sml
ViewVC logotype

Annotation of /branches/vis15/src/compiler/typechecker/check-var-uses.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3467 - (view) (download)

1 : jhr 3413 (* check-var-uses.sml
2 :     *
3 :     * This code is part of the Diderot Project (http://diderot-language.cs.uchicago.edu)
4 :     *
5 :     * COPYRIGHT (c) 2015 The University of Chicago
6 :     * All rights reserved.
7 :     *
8 :     * This pass checks two properties of variables:
9 :     *
10 :     * 1) variables that might be used before being assigned a value (ERROR)
11 :     * 2) variables that defined, but not used (WARNING)
12 :     *)
13 :    
14 :     structure CheckVarUses : sig
15 :    
16 : jhr 3414 (* check for uses of undefined variables and unused variables in the program *)
17 : jhr 3413 val check : Env.context * AST.program -> unit
18 :    
19 :     end = struct
20 :    
21 :     structure VSet = Var.Set
22 :    
23 :     datatype token = datatype TypeError.token
24 :    
25 : jhr 3414 fun error ((errStrm, _), msg) = Error.error (errStrm, TypeError.format msg)
26 :    
27 : jhr 3413 fun unusedWarning ((errStrm, _), x) =
28 :     Error.warning (errStrm, TypeError.format [
29 : jhr 3418 S(Var.kindToString x), S " ", V x, S " declared at line ",
30 : jhr 3414 LN(Var.locationOf x), S " is unused"
31 : jhr 3413 ])
32 :    
33 :     (* Check the use of a variable and report an error if it has not been initialized.
34 :     * We also remove it from the unused set and return the new unused set.
35 :     *)
36 :     fun chkUse (cxt : Env.context, (x, span), undef, unused) = (case Var.kindOf x
37 : jhr 3463 of Var.BasisVar => (
38 :     if Basis.isStrandSet x
39 :     then TypeError.error ((#1 cxt, span), [
40 :     S "use of strand set ", V x, S " outside of comprehension"
41 :     ])
42 :     else ();
43 :     unused)
44 : jhr 3413 | Var.ConstVar => VSet.subtract(unused, x)
45 :     | Var.FunVar => VSet.subtract(unused, x)
46 :     | _ => (
47 : jhr 3421 (* check for use of an undefined variable; the test against unused is
48 :     * to reduce repeated error messages.
49 :     *)
50 :     if VSet.member(undef, x) andalso VSet.member(unused, x)
51 : jhr 3413 then TypeError.error ((#1 cxt, span), [
52 : jhr 3418 S "possible use of variable ", V x, S " before it has been initialized"
53 : jhr 3413 ])
54 :     else ();
55 :     VSet.subtract(unused, x))
56 :     (* end case *))
57 :    
58 : jhr 3414 (* check for unused variable and, if unused, remove it from the unused set *)
59 :     fun chkForUnused cxt (x, unused) = if VSet.member(unused, x)
60 :     then (
61 :     unusedWarning(cxt, x);
62 :     VSet.subtract(unused, x))
63 :     else unused
64 :    
65 : jhr 3413 (* check an expression for uses of undefined variables and remove used variables
66 :     * from the unused list
67 :     *)
68 :     fun chkExpr (cxt, e, undef, unused) = let
69 :     fun chk (e, unused) = (case e
70 :     of AST.E_Var x => chkUse(cxt, x, undef, unused)
71 :     | AST.E_Lit _ => unused
72 :     | AST.E_Select(e, x) => chkUse(cxt, x, chk (e, undef), unused)
73 : jhr 3467 | AST.E_Prim(f, _, [], _) => (
74 :     if Basis.isStrandSet f
75 :     then TypeError.error (cxt, [
76 :     S "use of strand set ", V f, S " outside of comprehension"
77 :     ])
78 :     else ();
79 :     unused)
80 : jhr 3413 | AST.E_Prim(_, _, args, _) => chk' (args, unused)
81 :     | AST.E_Apply(f, args, _) => chk' (args, chkUse (cxt, f, undef, unused))
82 :     | AST.E_Comprehension(e, (x, e'), _) => let
83 :     val unused = chk (e, chk (e', unused))
84 :     in
85 : jhr 3414 chkForUnused cxt (x, unused)
86 : jhr 3413 end
87 : jhr 3464 | AST.E_ParallelMap(e, x, xs, _) => chkForUnused cxt (x, chk (e, unused))
88 : jhr 3413 | AST.E_Tensor(args, _) => chk' (args, unused)
89 :     | AST.E_Seq(args, _) => chk' (args, unused)
90 :     | AST.E_Slice(e, indices, _) =>
91 :     List.foldl (fn (SOME e, unu) => chk(e, unu) | (NONE, unu) => unu)
92 :     (chk (e, unused)) indices
93 :     | AST.E_Cond(e1, e2, e3, _) => chk (e3, chk (e2, chk (e1, unused)))
94 :     | AST.E_LoadNrrd _ => unused
95 :     | AST.E_Coerce{e, ...} => chk (e, unused)
96 :     (* end case *))
97 :     and chk' (es, unused) = List.foldl chk unused es
98 :     in
99 :     chk (e, unused)
100 :     end
101 :    
102 :     fun chkStmt (cxt, s, undef, unused) = let
103 :     fun chkScope ([], undef, unused, bound) = let
104 :     (* check for unused variables bound in this scope *)
105 : jhr 3414 val unused = VSet.foldl (chkForUnused cxt) unused bound
106 : jhr 3413 in
107 :     (VSet.difference(undef, bound), unused)
108 :     end
109 :     | chkScope (stm::stms, undef, unused, bound) = let
110 :     val (undef, unused, bound) = chk (stm, undef, unused, bound)
111 :     in
112 :     chkScope (stms, undef, unused, bound)
113 :     end
114 :     and chkBlockOrStm (AST.S_Block stms, undef, unused, bound) =
115 :     chkScope (stms, undef, unused, bound)
116 :     | chkBlockOrStm (stm, undef, unused, bound) = chkScope ([stm], undef, unused, bound)
117 :     and chk (stm, undef, unused, bound) = (case stm
118 :     of AST.S_Block stms => let
119 :     val (undef, unused) = chkScope (stms, undef, unused, VSet.empty)
120 :     in
121 :     (undef, unused, bound)
122 :     end
123 :     | AST.S_Decl(x, NONE) =>
124 :     (VSet.add(undef, x), VSet.add(unused, x), VSet.add(bound, x))
125 :     | AST.S_Decl(x, SOME e) => let
126 :     val unused = chkExpr (cxt, e, undef, unused)
127 :     in
128 :     (undef, VSet.add(unused, x), VSet.add(bound, x))
129 :     end
130 :     | AST.S_IfThenElse(e, stm1, stm2) => let
131 :     val unused = chkExpr (cxt, e, undef, unused)
132 :     val (undef1, unused1) = chkBlockOrStm (stm1, undef, unused, VSet.empty)
133 :     val (undef2, unused2) = chkBlockOrStm (stm2, undef, unused, VSet.empty)
134 :     in
135 :     (* variables have to be defined on both paths to be removed from undef,
136 :     * but can be used on either path to be removed from unused.
137 :     *)
138 :     (VSet.union(undef1, undef2), VSet.intersection(unused1, unused2), bound)
139 :     end
140 :     | AST.S_Foreach((x, e), stm) => let
141 :     val unused = chkExpr (cxt, e, undef, unused)
142 :     (* note that we do not assume that the loop is guaranteed to execute,
143 :     * so we ignore any changes to the undef set.
144 :     *)
145 :     val (_, unused) = chkBlockOrStm (stm, undef, unused, VSet.singleton x)
146 :     in
147 :     (undef, unused, bound)
148 :     end
149 :     | AST.S_Assign(x, e) =>
150 :     (VSet.subtract(undef, #1 x), chkExpr (cxt, e, undef, unused), bound)
151 :     | AST.S_New(_, args) => (undef, chkExps (args, undef, unused), bound)
152 :     | AST.S_Continue => (undef, unused, bound)
153 :     | AST.S_Die => (undef, unused, bound)
154 :     | AST.S_Stabilize => (undef, unused, bound)
155 :     | AST.S_Return e => (undef, chkExpr (cxt, e, undef, unused), bound)
156 :     | AST.S_Print args => (undef, chkExps (args, undef, unused), bound)
157 :     (* end case *))
158 :     and chkExps (exps, undef, unused) = let
159 : jhr 3433 fun chk (exp, unused) = chkExpr (cxt, exp, undef, unused)
160 : jhr 3413 in
161 :     List.foldl chk unused exps
162 :     end
163 :     in
164 :     chkBlockOrStm (s, undef, unused, VSet.empty)
165 :     end
166 :    
167 : jhr 3414 fun chkOptBlock (_, NONE, undef, unused) = (undef, unused)
168 :     | chkOptBlock (cxt, SOME stm, undef, unused) = chkStmt (cxt,stm, undef, unused)
169 :    
170 : jhr 3452 fun chkStrand (cxt, AST.Strand{params, state, initM, updateM, stabilizeM, ...}, undef, unused) = let
171 : jhr 3414 (* check a state-variable declaration *)
172 :     fun chkVarDecl ((x, optE), (undef, unused, bound, outputs)) = let
173 : jhr 3422 val (undef, unused) = (case optE
174 :     of NONE => (VSet.add(undef, x), unused)
175 :     | SOME e => (undef, chkExpr (cxt, e, undef, unused))
176 :     (* end case *))
177 : jhr 3414 val (unused, outputs) = if Var.isOutput x
178 :     then (unused, x::outputs)
179 :     else (VSet.add(unused, x), outputs)
180 :     in
181 : jhr 3438 (undef, unused, x::bound, outputs)
182 : jhr 3414 end
183 :     (* first we add the parameters to the sets of bound and unused variables *)
184 : jhr 3438 val bound = params
185 :     val unused = VSet.addList (unused, params)
186 : jhr 3414 (* process the state variables *)
187 :     val (undef, unused, bound, outputs) =
188 :     List.foldl chkVarDecl (undef, unused, bound, []) state
189 :     (* check the initially method first (if it exists) *)
190 : jhr 3452 val (undef, unused) = chkOptBlock (cxt, initM, undef, unused)
191 : jhr 3414 (* then the update method *)
192 : jhr 3452 val (undef', unused) = chkStmt (cxt, updateM, undef, unused)
193 : jhr 3414 (* check the stabilize method; we ignore definitions from the update method, since
194 :     * we might get called from the initially method.
195 :     *)
196 :     (* FIXME: we should check if the initially method has a call to stabilize! *)
197 : jhr 3452 val (undef'', unused) = chkOptBlock (cxt, stabilizeM, undef, unused)
198 : jhr 3414 (* merge the undef sets from the update and stabilize methods *)
199 :     val undef = VSet.intersection (undef', undef'')
200 :     in
201 :     (* check for undefined output variables *)
202 :     List.app
203 :     (fn x => if VSet.member(undef, x)
204 : jhr 3418 then error (cxt, [S "strand output variable ", V x, S " is not initialized"])
205 : jhr 3414 else ()
206 :     ) outputs;
207 :     (* report unused state variables *)
208 : jhr 3438 List.foldl (chkForUnused cxt) unused bound
209 : jhr 3414 end
210 :    
211 : jhr 3422 fun chkCreate (cxt, AST.C_Grid(_, stm), undef, unused) = #2 (chkStmt (cxt, stm, undef, unused))
212 :     | chkCreate (cxt, AST.C_Collection stm, undef, unused) = #2 (chkStmt (cxt, stm, undef, unused))
213 :    
214 : jhr 3413 fun check (cxt, prog) = let
215 : jhr 3414 val AST.Program{const_dcls, input_dcls, globals, init, strand, create, update, ...} = prog
216 :     fun chkVarDecl ((x, NONE), (undef, unused, bound)) =
217 :     (VSet.add(undef, x), VSet.add(unused, x), VSet.add(bound, x))
218 :     | chkVarDecl ((x, SOME e), (undef, unused, bound)) =
219 : jhr 3422 (undef, VSet.add(chkExpr(cxt, e, undef, unused), x), VSet.add(bound, x))
220 : jhr 3432 (* check input-variable declarations; these get their values at runtime *)
221 :     fun chkInputDecl (((x, NONE), _), (undef, unused, bound)) =
222 :     (undef, VSet.add(unused, x), VSet.add(bound, x))
223 :     | chkInputDecl (((x, SOME e), _), (undef, unused, bound)) =
224 :     (undef, VSet.add(chkExpr(cxt, e, undef, unused), x), VSet.add(bound, x))
225 : jhr 3414 fun chkGlobalDecl (AST.D_Var vd, accum) = chkVarDecl (vd, accum)
226 :     | chkGlobalDecl (AST.D_Func(f, params, body), (undef, unused, bound)) = let
227 :     val (undef, unused) = chkStmt (cxt, body, undef, VSet.addList(unused, params))
228 :     val unused = List.foldl (chkForUnused cxt) unused params
229 :     in
230 :     (undef, VSet.add(unused, f), bound)
231 :     end
232 :     (* first process the global declarations *)
233 :     val (undef, unused, bound) =
234 :     List.foldl chkVarDecl (VSet.empty, VSet.empty, VSet.empty) const_dcls
235 :     val (undef, unused, bound) =
236 :     List.foldl chkInputDecl (undef, unused, bound) input_dcls
237 :     val (undef, unused, bound) =
238 :     List.foldl chkGlobalDecl (undef, unused, bound) globals
239 :     (* the optional global initially block *)
240 :     val (undef, unused) = chkOptBlock (cxt, init, undef, unused)
241 :     (* the strand (no global initialization allowed) *)
242 :     val unused = chkStrand (cxt, strand, undef, unused)
243 : jhr 3422 (* check the initial-strands creation code *)
244 :     val unused = chkCreate (cxt, create, undef, unused)
245 : jhr 3414 (* the optional global update block *)
246 :     val (undef, unused) = chkOptBlock (cxt, update, undef, unused)
247 : jhr 3413 in
248 : jhr 3414 (* report unused variables *)
249 :     VSet.app
250 :     (fn x => if VSet.member(unused, x) then unusedWarning(cxt, x) else ())
251 :     bound
252 : jhr 3413 end
253 :    
254 :     end

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0