1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
(* Scope analysis *)
open Ast.Value
open Utils
let rec analyse_expr expr env =
match expr with
| loc, Evalue v -> ((loc, Evalue v), env)
| loc, Eunop (op, e) ->
let e, env = analyse_expr e env in
((loc, Eunop (op, e)), env)
| loc, Ebinop (e1, op, e2) ->
let e1, env = analyse_expr e1 env in
let e2, env = analyse_expr e2 env in
((loc, Ebinop (e1, op, e2)), env)
| loc, Evariadic -> ((loc, Evariadic), env)
| loc, Efunctiondef (pl, b) ->
let (pl, b), env = analyse_funcbody (pl, b) env in
((loc, Efunctiondef (pl, b)), env)
| loc, Eprefix pexp ->
let pexp, env = analyse_prefixexp pexp env in
((loc, Eprefix pexp), env)
| loc, Etableconstructor fl ->
let fl, env = analyse_fieldlist fl env in
((loc, Etableconstructor fl), env)
and analyse_var var env =
match var with
| VarName n ->
let fresh_n, env = Env.get_name n (Vnil ()) env in
(VarName fresh_n, env)
| VarTableField (pexp, exp) ->
let pexp, env = analyse_prefixexp pexp env in
let exp, env = analyse_expr exp env in
(VarTableField (pexp, exp), env)
and analyse_fieldlist fl env =
match fl with
| [] -> ([], env)
| f :: fl -> (
match f with
| Fexp e ->
let e, env = analyse_expr e env in
let fl, env = analyse_fieldlist fl env in
(Fexp e :: fl, env)
| Fname (n, e) ->
(* n should not be freshed: tbl.x > tbl["x"] *)
let e, env = analyse_expr e env in
let fl, env = analyse_fieldlist fl env in
(Fname (n, e) :: fl, env)
| Fcol (e1, e2) ->
let e1, env = analyse_expr e1 env in
let e2, env = analyse_expr e2 env in
let fl, env = analyse_fieldlist fl env in
(Fcol (e1, e2) :: fl, env) )
and analyse_parlist pl env =
match pl with
| PLlist (nl, b) ->
let nl, env =
analyse_list nl (fun n ev -> Env.add_local n (Vnil ()) ev) env
in
(PLlist (nl, b), env)
| PLvariadic -> (PLvariadic, env)
and analyse_funcbody ((pl, b) as _fb) env =
let pl, env_loc = analyse_parlist pl env in
let b, env_loc = analyse_block b env_loc in
let locals = Env.get_locals env in
let env = Env.with_locals env_loc locals in
((pl, b), env)
and analyse_args (Aexpl el) env =
let el, env = analyse_list el analyse_expr env in
(Aexpl el, env)
and analyse_prefixexp pexp env =
match pexp with
| PEvar v ->
let v, env = analyse_var v env in
(PEvar v, env)
| PEfunctioncall fc ->
let fc, env = analyse_functioncall fc env in
(PEfunctioncall fc, env)
| PEexp e ->
let e, env = analyse_expr e env in
(PEexp e, env)
and analyse_functioncall fc env =
match fc with
| FCpreargs (pexp, args) ->
let pexp, env = analyse_prefixexp pexp env in
let args, env = analyse_args args env in
(FCpreargs (pexp, args), env)
| FCprename (pexp, n, args) ->
let pexp, env = analyse_prefixexp pexp env in
let args, env = analyse_args args env in
(FCprename (pexp, n, args), env)
and analyse_stmt stmt env =
match stmt with
| Sempty -> (Sempty, env)
| Sassign (vl, el) ->
let el, env = analyse_list el analyse_expr env in
let vl, env = analyse_list vl analyse_var env in
(Sassign (vl, el), env)
| SassignLocal (nal, el) ->
let el, env = analyse_list el analyse_expr env in
let nal, env =
(* todo : local name attrib (const/close) support *)
analyse_list nal
(fun (n, oa) ev ->
let fresh_n, ev = Env.add_local n (Vnil ()) ev in
((fresh_n, oa), ev) )
env
in
(SassignLocal (nal, el), env)
| Sbreak -> (Sbreak, env)
| Sreturn el ->
let el, env = analyse_list el analyse_expr env in
(Sreturn el, env)
| Slabel n -> (Slabel n, env)
| Sgoto n -> (Sgoto n, env)
| Sblock b ->
let b, env = analyse_block b env in
(Sblock b, env)
| Swhile (e, b) ->
let e, env = analyse_expr e env in
let b, env = analyse_block b env in
(Swhile (e, b), env)
| Srepeat (b, e) ->
let b, env = analyse_block b env in
let e, env = analyse_expr e env in
(Srepeat (b, e), env)
| Sif (e, b, ebl, ob) ->
let e, env = analyse_expr e env in
let b, env = analyse_block b env in
let ebl, env =
analyse_list ebl
(fun (e, b) ev ->
let e, ev = analyse_expr e ev in
let b, ev = analyse_block b ev in
((e, b), ev) )
env
in
let ob, env =
match ob with
| None -> (None, env)
| Some b ->
let b, env = analyse_block b env in
(Some b, env)
in
(Sif (e, b, ebl, ob), env)
| Sfor (n, e1, e2, oe, b) ->
let fresh_n, env_loc = Env.add_local n (Vnil ()) env in
let e1, env_loc = analyse_expr e1 env_loc in
let e2, env_loc = analyse_expr e2 env_loc in
let oe, env_loc =
match oe with
| None -> (None, env_loc)
| Some e ->
let e, env_loc = analyse_expr e env_loc in
(Some e, env_loc)
in
let b, env_loc = analyse_block b env_loc in
let locals = Env.get_locals env in
let env = Env.with_locals env_loc locals in
(Sfor (fresh_n, e1, e2, oe, b), env)
| Siterator (nl, el, b) ->
let fresh_nl, env_loc =
analyse_list nl (fun n ev -> Env.add_local n (Vnil ()) ev) env
in
let analysed_el, env_loc = analyse_list el analyse_expr env_loc in
let b, env_loc = analyse_block b env_loc in
let locals = Env.get_locals env in
let env = Env.with_locals env_loc locals in
(Siterator (fresh_nl, analysed_el, b), env)
(* | Sfunction (n, fb) ->
let fresh_n, env = Env.get_funcname n env in
let fb, env = analyse_funcbody fb env in
(Sfunction (fresh_n, fb), env) *)
| SfunctionLocal (n, fb) ->
let fresh_n, env = Env.add_local n (Vnil ()) env in
let fb, env = analyse_funcbody fb env in
(SfunctionLocal (fresh_n, fb), env)
| SfunctionCall fc ->
let fc, env = analyse_functioncall fc env in
(SfunctionCall fc, env)
and analyse_block b env =
match b with
| [] -> ([], env)
| stmt :: tl ->
let stmt, env_s = analyse_stmt stmt env in
let tl, env_b = analyse_block tl env_s in
let locals = Env.get_locals env in
let env = Env.with_locals env_b locals in
(stmt :: tl, env)
let analysis chunk env = analyse_block chunk env