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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
open Ast.Text
module StringSet = Set.Make (String)
module IntSet = Set.Make (Int)
exception Conditional_remains of Ast.location
(** Raised when an [(@if ...)] annotation is still present: it could not be
resolved (no matching [-D]), and there is nothing to desugar it to. *)
let default_string_type = "<string>"
let module_ ((name, fields) : Ast.location module_) : Ast.location module_ =
let wide_names = ref StringSet.empty in
let wide_indices = ref IntSet.empty in
let type_names = ref StringSet.empty in
let default_type = ref None in
let next = ref 0 in
List.iter
(fun f ->
match f.Ast.desc with
| Types r ->
let singleton = Array.length r = 1 in
Array.iter
(fun e ->
let nameo, (st : subtype) = e.Ast.desc in
let here = !next in
Option.iter
(fun n -> type_names := StringSet.add n.Ast.desc !type_names)
nameo;
(match st.typ with
| Array { typ = Packed I16; _ } ->
wide_indices := IntSet.add here !wide_indices;
Option.iter
(fun n ->
wide_names := StringSet.add n.Ast.desc !wide_names)
nameo
| _ -> ());
(if singleton then
match st with
| {
final = true;
supertype = None;
typ = Array { mut = true; typ = Packed I8 };
_;
} ->
let idx =
match nameo with
| Some n ->
{ Ast.desc = Id n.Ast.desc; info = n.Ast.info }
| None ->
{
Ast.desc = Num (Wax_utils.Uint32.of_int here);
info = f.Ast.info;
}
in
default_type := Some idx
| _ -> ());
incr next)
r
| _ -> ())
fields;
let string_type_name =
let rec fresh cand n =
if StringSet.mem cand !type_names then
fresh (Printf.sprintf "<string>%d" n) (n + 1)
else cand
in
fresh default_string_type 1
in
let needs_string_type = ref false in
let is_wide (i : idx) =
match i.desc with
| Id n -> StringSet.mem n !wide_names
| Num k -> IntSet.mem (Wax_utils.Uint32.to_int k) !wide_indices
in
let resolve_type loc (idxo : idx option) =
match idxo with
| Some i -> (i, is_wide i)
| None -> (
match !default_type with
| Some idx -> (idx, false)
| None ->
needs_string_type := true;
({ Ast.desc = Id string_type_name; info = loc }, false))
in
let const loc v =
{
Ast.desc =
Folded ({ Ast.desc = Const (I32 (string_of_int v)); info = loc }, []);
info = loc;
}
in
let string_expr loc (idxo : idx option) (s : datastring) =
let content = Wax_utils.Ast.concat_desc s in
let type_idx, wide = resolve_type loc idxo in
let values =
if wide then Wax_utils.Unicode.utf16_code_units content
else List.init (String.length content) (fun j -> Char.code content.[j])
in
Folded
( {
Ast.desc =
ArrayNewFixed
(type_idx, Wax_utils.Uint32.of_int (List.length values));
info = loc;
},
List.map (const loc) values )
in
let char_expr c = Const (I32 (string_of_int (Uchar.to_int c))) in
let rec map_instr (i : Ast.location instr) : Ast.location instr =
match i.desc with
| String (idxo, s) -> { i with desc = string_expr i.info idxo s }
| Char c -> { i with desc = char_expr c }
| If_annotation _ -> raise (Conditional_remains i.info)
| desc -> { i with desc = map_structured desc }
and map_structured (desc : Ast.location instr_desc) : Ast.location instr_desc
=
match desc with
| Block b ->
Block
{
b with
block = { b.block with desc = List.map map_instr b.block.desc };
}
| Loop b ->
Loop
{
b with
block = { b.block with desc = List.map map_instr b.block.desc };
}
| If b ->
If
{
b with
if_block =
{ b.if_block with desc = List.map map_instr b.if_block.desc };
else_block =
{ b.else_block with desc = List.map map_instr b.else_block.desc };
}
| TryTable b ->
TryTable
{
b with
block = { b.block with desc = List.map map_instr b.block.desc };
}
| Try b ->
Try
{
b with
block = { b.block with desc = List.map map_instr b.block.desc };
catches =
List.map
(fun (t, l) ->
(t, { l with Ast.desc = List.map map_instr l.Ast.desc }))
b.catches;
catch_all =
Option.map
(fun b -> { b with Ast.desc = List.map map_instr b.Ast.desc })
b.catch_all;
}
| Folded ({ desc = String (idxo, s); info }, []) -> string_expr info idxo s
| Folded ({ desc = Char c; _ }, []) -> char_expr c
| Folded (h, l) -> Folded (map_instr h, List.map map_instr l)
| Hinted (b, inner) -> Hinted (b, map_instr inner)
| desc -> desc
in
let map_field (f : (Ast.location modulefield, Ast.location) Ast.annotated) =
let desc =
match f.Ast.desc with
| Func r -> Func { r with instrs = List.map map_instr r.instrs }
| Global r -> Global { r with init = List.map map_instr r.init }
| Table r ->
let init =
match r.init with
| Init_default -> Init_default
| Init_expr e -> Init_expr (List.map map_instr e)
| Init_segment segs ->
Init_segment (List.map (List.map map_instr) segs)
in
Table { r with init }
| Elem r -> Elem { r with init = List.map (List.map map_instr) r.init }
| String_global { id; typ; init } ->
let type_idx, _ = resolve_type f.info typ in
let gtyp : globaltype =
{ mut = false; typ = Ref { nullable = false; typ = Type type_idx } }
in
let e = { Ast.desc = string_expr f.info typ init; info = f.info } in
Global { id = Some id; typ = gtyp; init = [ e ]; exports = [] }
| Module_if_annotation _ -> raise (Conditional_remains f.info)
| desc -> desc
in
{ f with desc }
in
let fields =
List.filter
(fun (f : (Ast.location modulefield, _) Ast.annotated) ->
match f.desc with Feature_annotation _ -> false | _ -> true)
fields
in
let fields = List.map map_field fields in
let fields =
if !needs_string_type then
let st : subtype =
{
typ = Array { mut = true; typ = Packed I8 };
supertype = None;
final = true;
descriptor = None;
describes = None;
}
in
fields
@ [
Ast.no_loc
(Types [| Ast.no_loc (Some (Ast.no_loc string_type_name), st) |]);
]
else fields
in
(name, fields)