add rules to install systemd units
[hcoop/domtool2.git] / src / unused.sml
1 (* HCoop Domtool (http://hcoop.sourceforge.net/)
2 * Copyright (c) 2007, 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 (* Domtool configuration language unused environment variable setting analysis *)
20
21 structure Unused :> UNUSED = struct
22
23 open Ast
24 structure SM = StringMap
25 structure SS = StringSet
26
27 fun check G e =
28 let
29 fun used vars x =
30 (#1 (SM.remove (vars, x)))
31 handle NotFound => vars
32
33 fun unused loc x =
34 ErrorMsg.warning (SOME loc) ("Unused setting of environment variable " ^ x)
35
36 fun writing vars x loc =
37 (Option.app (fn loc' => unused loc' x) (SM.find (vars, x));
38 SM.insert (vars, x, loc))
39
40 fun findHead (e, _) =
41 case e of
42 EVar x => SOME x
43 | EApp (e, _) => findHead e
44 | _ => NONE
45
46 fun processTy f default loc t =
47 case #1 (Describe.ununify t) of
48 TArrow (_, t) => processTy f default loc t
49 | TNested (_, t) => processTy f default loc t
50
51 | TAction (_, reads, writes) => f (reads, writes)
52
53 | _ => default
54
55 fun writes (e, _) =
56 case e of
57 ESet (x, _) => SS.singleton x
58 | EGet (_, _, _, e) => writes e
59 | ESeq es => foldl (fn (e, s) => SS.union (writes e, s)) SS.empty es
60 | ELocal (_, e) => writes e
61 | EWith (e, _) => writes e
62 | _ => SS.empty
63
64 fun chk (eAll as (e, loc), vars) =
65 case e of
66 EInt _ => vars
67 | EString _ => vars
68 | EList es => vars
69 | ELam _ => vars
70 | ESkip => vars
71
72 | ESet (x, _) => writing vars x loc
73 | EGet (_, _, x, e) => chk (e, used vars x)
74 | ESeq es => foldl chk vars es
75 | ELocal (e1, e2) =>
76 let
77 val vars = chk (e2, chk (e1, vars))
78 val writes1 = writes e1
79 val writes2 = writes e2
80 in
81 SM.foldli (fn (x, _, vars') =>
82 if SS.member (writes1, x)
83 andalso not (SS.member (writes2, x)) then
84 SM.insert (vars', x, valOf (SM.find (vars, x)))
85 else
86 vars') vars vars
87 end
88 | EWith (e1, e2) => chk (e2, chk (e1, vars))
89 | EALam _ => vars
90 | EIf _ => vars
91
92 | _ =>
93 let
94 val processTy = processTy (fn (reads, writes) =>
95 let
96 val vars = SM.foldli (fn (x, _, vars) => used vars x) vars reads
97 in
98 SM.foldli (fn (x, _, vars) => writing vars x loc) vars writes
99 end)
100 vars
101 in
102 case findHead eAll of
103 NONE => raise Fail "Couldn't find the head"
104 | SOME head =>
105 case Env.lookupVal G head of
106 NONE => vars
107 | SOME t => processTy loc t
108 end
109 in
110 SM.appi (fn (x, loc) => unused loc x) (chk (e, SM.empty))
111 end
112 end