package wax-lib
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Libraries for Wax, a Rust-like syntax for WebAssembly
Install
dune-project
Dependency
Authors
Maintainers
Sources
wax-0.1.0.tbz
sha256=41b580846af8d41bdf6c3f005f62e38feda3e60fe2e9e4aa440db34ce515a153
sha512=4b3a181fcc7d743194a8647260870fb5190770066a197bcc48104c2b77fd40c643228b795c2bcd6b29a120820e969eb42a37a9bcec98b3f608d13f152d9f6579
doc/src/wax-lib.wasm/desugar.ml.html
Source file desugar.ml
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(* Expand the Wax-specific [@string]/[@char] annotations of a WAT module into core WebAssembly ([array.new_fixed] / [i32.const]), so the text other tools accept. Conditional-compilation annotations ([(@if ...)]) have no core-wasm form; they are expected to have been resolved already (by [Cond_specialize] through [-D]), and any that remain make desugaring fail. *) 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. *) (* The array type a [@string] builds must be declared for [array.new_fixed] to name it. An untyped string uses the default [<string>] ([mut i8]); we synthesise that type once, under this name (freshened on the rare chance the module already declares it). *) let default_string_type = "<string>" let module_ ((name, fields) : Ast.location module_) : Ast.location module_ = (* Scan the type section: which array types are [i16] (their strings are UTF-16-encoded), tracked both by name and by index since a [@string] may name its type either way; plus every type name, to freshen the synthesised one. *) let wide_names = ref StringSet.empty in let wide_indices = ref IntSet.empty in let type_names = ref StringSet.empty in (* A type usable as the default [<string>] for an untyped string: as in [Text_to_binary], a singleton rec group that is a plain [(array (mut i8))] (final, no supertype). Referencing it avoids synthesising a redundant one; the last such type wins, matching [Text_to_binary]. *) 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 (* The type to build with, and whether it is UTF-16. An untyped string reuses an existing default [<string>] type when one exists, and otherwise pins a synthesised one. *) 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 (* An operand of the folded [array.new_fixed] must itself be folded (an [(i32.const N)] sub-expression), not a bare stack instruction. *) let const loc v = { Ast.desc = Folded ({ Ast.desc = Const (I32 (string_of_int v)); info = loc }, []); info = loc; } in (* A string [array.new_fixed] over its encoded elements: UTF-16 code units for an [i16] array, raw UTF-8 bytes for an [i8] one. *) 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; } (* [@string]/[@char] print as a folded head with no operands; expand them at the folded level so no redundant parenthesis is left behind. *) | 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 (* A [(@feature "…")] declaration is pure metadata with no core equivalent: drop it, so no annotation remains in the output. Feature resolution has already run by this point (desugaring follows validation); re-ingesting the desugared text needs [-X] again, exactly as desugared strings do not come back as literals. *) 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 (* Appended (not prepended) so it takes the highest type index, leaving any numeric type reference in the module unshifted. *) fields @ [ Ast.no_loc (Types [| Ast.no_loc (Some (Ast.no_loc string_type_name), st) |]); ] else fields in (name, fields)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>