123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466type('desc,'info)annotated=('desc,'info)Wax_utils.Ast.annotated={desc:'desc;info:'info;}typelocation=Wax_utils.Ast.location={loc_start:Lexing.position;loc_end:Lexing.position;}letno_loc=Wax_utils.Ast.no_loc(* [instr] shares the [desc]/[info] field names with [annotated] and, being
declared later, wins field disambiguation wherever the receiver's type is not
already known. Read a *generic* node's fields through this alias to say which
record is meant: [x.desc]. *)moduleAnnot=Wax_utils.Asttypeident=(string,location)annotatedincludeWax_wasm.Ast.Make_types(structtypeidx=ident(* Each element carries a source location spanning the whole entry (e.g. a
struct field [name: type]), so a trailing comment can attach to it even
when the name is absent or synthesized. *)type'aannotated_array=(ident*'a,location)annotatedarraytype'aopt_annotated_array=(identoption*'a,location)annotatedarrayend)(* A [..] splice at the head of a struct definition inherits the supertype's
fields. It is carried through the AST as a sentinel field whose name is
[splice_field_name] — not a valid identifier, so it never collides with a real
field. Typing replaces it with the supertype's fields; the printer renders it
back as [..]. Its field type is a placeholder and is never inspected. *)letsplice_field_name=".."letis_splice_field(f:(ident*fieldtype,location)annotated)=String.equal(fstf.desc).descsplice_field_nameletsplice_fieldloc:(ident*fieldtype,location)annotated={desc=({desc=splice_field_name;info=loc},{mut=false;typ=ValueI32});info=loc;}(* The located [(name, thing)] pairs the type family carries: a function
parameter (its name optional), a struct field, a rec-group member. Named
accessors rather than [fst]/[snd] over [.desc], because [desc] on a node whose
type is not already known resolvesto the instruction record's field of that
name (see {!Annot}). Their declared return types also let a chained read —
[(field_name f).desc] — resolve on its own. *)letparam_name(p:(identoption*valtype,location)annotated)=fstp.descletparam_type(p:(identoption*valtype,location)annotated)=sndp.descletfield_name(f:(ident*fieldtype,location)annotated)=fstf.descletfield_type(f:(ident*fieldtype,location)annotated)=sndf.descletmember_name(m:(ident*subtype,location)annotated)=fstm.descletmember_type(m:(ident*subtype,location)annotated)=sndm.desctypesignage=Wax_wasm.Ast.signage=Signed|Unsignedtypeunop=Neg|Pos|Nottypebinop=|Add|Sub|Mul|Divofsignageoption|Remofsignage|And|Or|Xor|Shl|Shrofsignage|Eq|Ne|Ltofsignageoption|Gtofsignageoption|Leofsignageoption|Geofsignageoptiontypelabel=identtypecasttype=|Valtypeofvaltype|Functypeof{nullable:bool;sign:functype}|Signedtypeof{typ:[`I32|`I64|`F32|`F64];signage:signage;strict:bool;}|Ascribedofvaltype(** The parenthesized type ascription [(e : t)]: a static assertion that
[e]'s type is a subtype of [t], with result type [t]. Never lowers to
an instruction, and — unlike a cast — an ascribed bare hole claims no
pending value: it GROUNDS a value of type [t] off the polymorphic
floor. *)letformat_signed_typetypsignagestrict=Printf.sprintf"%s_%s%s"(matchtypwith|`I32->"i32"|`I64->"i64"|`F32->"f32"|`F64->"f64")(matchsignagewithSigned->"s"|Unsigned->"u")(ifstrictthen"_strict"else"")typecatch=|Catchofident*label|CatchRefofident*label|CatchAlloflabel|CatchAllRefoflabeltypeon_clause=OnLabelofident*label|OnSwitchofident(* A [match] arm pattern: a (optionally bound) reference-type test, or a null
test. See the [Match] node and {!Ast_utils.lower_match}. *)typematch_pattern=MatchCastofidentoption*reftype|MatchNulltype'infoinstr_desc=|Blockof{label:labeloption;typ:functype;block:('infoinstrlist,location)annotated;}|Loopof{label:labeloption;typ:functype;block:('infoinstrlist,location)annotated;}|Whileof{label:labeloption;cond:'infoinstr;(* Zig-style continue-expression: a statement run at the end of every
iteration, including when the body branches to the loop label
([continue]). Lowered so a [continue] runs it before re-testing. *)step:'infoinstroption;block:('infoinstrlist,location)annotated;}|Ifof{label:labeloption;typ:functype;cond:'infoinstr;if_block:('infoinstrlist,location)annotated;else_block:('infoinstrlist,location)annotatedoption;}|TryTableof{label:labeloption;typ:functype;catches:catchlist;block:('infoinstrlist,location)annotated;}|Tryof{label:labeloption;typ:functype;block:('infoinstrlist,location)annotated;catches:(ident*('infoinstrlist,location)annotated)list;catch_all:('infoinstrlist,location)annotatedoption;}|TryCatchof{label:labeloption;typ:functype;block:('infoinstrlist,location)annotated;arms:'infotrycatch_armlist;}|Unreachable|Nop|Hole|Null|Getofident(* A qualified name [namespace::member], used as the callee of a built-in
intrinsic call such as [i64::add128(...)]. *)|Pathofident*ident(* Assignment to a named local or global. The middle field is the
compound-assignment operator: [None] for a plain [x = e]; [Some op] for
[x op= e], which is equivalent to [x = x op e]. The operator is preserved
through typing and lowering so it round-trips in both directions ([x op= e]
on the Wax side, a [get]/op/[set] on the Wasm side); the middle field
carries the RHS type. A discarded value ([_ = e]) is not a [Set] but an
anonymous [Let] ([Let ([ (None, _) ], Some e)]); see {!Let}. *)|Setofident*(binop,location)annotatedoption*'infoinstr|Teeofident*'infoinstr|Callof'infoinstr*'infoinstrlist|TailCallof'infoinstr*'infoinstrlist(* A labelled call argument [name: expr], used for the static [offset]/
[align]/[lane] immediates of a memory access. Produced by the parser only
as a direct element of a [Call]/[TailCall] argument list; typing rejects
it anywhere else. *)|Labelledofident*'infoinstr|CharofUchar.t|Stringofidentoption*string|Intofstring|Floatofstring|Castof'infoinstr*casttype|CastDescof'infoinstr*(* nullable result *)bool*'infoinstr|Testof'infoinstr*reftype|NonNullof'infoinstr(* A field's value is [None] when written in the punning shorthand [{x}],
which abbreviates [{x: x}] (the value is taken from the like-named
local/global). Typing resolves the pun to the explicit [Get] before
lowering; the printer renders [None] back as the shorthand. *)|Structofidentoption*(ident*'infoinstroption)list|StructDefaultofidentoption|StructDescof'infoinstr*(ident*'infoinstroption)list|StructDefaultDescof'infoinstr|StructGetof'infoinstr*ident|GetDescriptorof'infoinstr|StructSetof'infoinstr*ident*'infoinstr|Arrayofidentoption*'infoinstr*'infoinstr|ArrayDefaultofidentoption*'infoinstr|ArrayFixedofidentoption*'infoinstrlist|ArraySegmentofidentoption*ident*'infoinstr*'infoinstr|ArrayGetof'infoinstr*'infoinstr|ArraySetof'infoinstr*'infoinstr*'infoinstr|BinOpof(binop,location)annotated*'infoinstr*'infoinstr|UnOpof(unop,location)annotated*'infoinstr|Letof(identoption*valtypeoption)list*'infoinstroption|Broflabel*'infoinstroption|Br_ifoflabel*'infoinstr|Br_tableoflabellist*'infoinstr|Dispatchof{index:'infoinstr;cases:labellist;default:label;arms:(label*('infoinstrlist,location)annotated)list;}|Matchof{scrutinee:'infoinstr;arms:(match_pattern*('infoinstrlist,location)annotated)list;default:('infoinstrlist,location)annotated;}|Br_on_nulloflabel*'infoinstr|Br_on_non_nulloflabel*'infoinstr|Br_on_castoflabel*reftype*'infoinstr|Br_on_cast_failoflabel*reftype*'infoinstr|Br_on_cast_desc_eqoflabel*(* nullable *)bool*'infoinstr*'infoinstr|Br_on_cast_desc_eq_failoflabel*(* nullable *)bool*'infoinstr*'infoinstr|Throwofident*'infoinstrlist|ThrowRefof'infoinstr|ContNewofident*'infoinstr|ContBindofident*ident*'infoinstrlist|Suspendofident*'infoinstrlist|Resumeofident*on_clauselist*'infoinstrlist|ResumeThrowofident*ident*on_clauselist*'infoinstrlist|ResumeThrowRefofident*on_clauselist*'infoinstrlist|Switchofident*ident*'infoinstrlist|Onof'infoinstr*on_clauselist|Returnof'infoinstroption|Sequenceof'infoinstrlist|Selectof'infoinstr*'infoinstr*'infoinstr|If_annotationof{cond:Wax_wasm.Ast.cond;then_body:('infoinstrlist,location)annotated;else_body:('infoinstrlist,location)annotatedoption;}(* [hints] carries the advisory [metadata.code.*] metadata (branch-hinting and
compilation-hints proposals) of this instruction, written in Wax as an
attribute prefixing it ([#[likely]], [#[freq = 16]], ...). It is a field rather
than a wrapper node so that the matches on [desc] — which is nearly every match
on an instruction — neither see it nor have to see through it.
[expected] is the type the value this node produces MUST have, when a producer
knows it independently of Wax inference: {!Wax_conversion.From_wasm} records
the type the Wasm opcode it decompiled this node from states ([Recorded]).
Nothing in the source language sets it (a parsed module leaves every node
[Unset]) and nothing user-visible reads it — unlike [hints] it is never
printed. The typer's width-check mode ({!Typing.f}'s [~width_check]) compares
its own inferred type for the node against a [Recorded] claim and reports a
mismatch as an internal-invariant failure: a decompiled expression whose
printed form Wax would re-infer at another width silently changes the opcode
on recompile.
The two claim-less states are distinct on purpose. [Contextual] means a
producer CONSIDERED the node and deliberately declined to claim: the value's
width comes from its context rather than its own printed form
([From_wasm]'s [forget_expected]), or its type is a reference — the one class
outside the width channel. [Unset] means no producer ever considered it: the
default for parsed source and for nodes synthesized after the conversion —
but on a [From_wasm]-emitted node that produces a NUMERIC value it is a
recording gap, the one silent failure class of the width machinery (a gap is
invisible to the reconciliation by construction). [--debug width-record]
reports every such node so the gap class is auditable instead of waiting for
a fuzzer to hit a drift. Every reader that asks "does this node state its
type?" must treat [Unset] and [Contextual] identically (only [Recorded]
informs); only the audit distinguishes them.
A field rather than a side table keyed by location, because a synthesized
dead-code node carries no real span; and rather than a wrapper node, so no
match on [desc] has to see through it (as for [hints]). *)andexpectation=Unset|Contextual|Recordedofvaltypeand'infoinstr={desc:'infoinstr_desc;info:'info;hints:identWax_wasm.Hints.t;expected:expectation;}and'infotrycatch_arm={arm_tag:identoption;arm_ref:bool;arm_types:valtypearray;arm_body:('infoinstrlist,location)annotated;}(* A synthesized instruction: no source location, no hints. The instruction
counterpart of [no_loc], which builds an [annotated] and so cannot serve a
record that carries hints as well. *)letno_loc_instrdesc:locationinstr={desc;info=Wax_utils.Ast.dummy_loc;hints=Wax_wasm.Hints.none;expected=Unset;}(* An attribute is a name with an optional value expression and an optional
conditional-compilation guard: [#[export = "f"]] carries a value, [#[start]]
does not, and [#[export = "f", if not(portable)]] carries a guard that makes
just this export conditional (independent of the field's own reachability).
Only [export] may be guarded. The guard is located at its [if] keyword, to
anchor a diagnostic.
Each carries the span of the whole [#[...]], so a diagnostic about the
attribute names it rather than falling back to its value (which a valueless one
like [#[start]] does not have) or to the whole field it sits on. A synthesized
attribute — one the Wasm-to-Wax conversion invents rather than reads — has no
real span and takes the entity's. *)typeattribute={attr_name:string;attr_value:locationinstroption;attr_guard:(Wax_wasm.Ast.cond,location)annotatedoption;attr_span:location;}typeattributes=attributelist(* What an [import "module" { ... }] entry brings in. Imports have no body, so
these carry only type-level information (no ['info]-annotated instructions):
[exact] marks an exact function import ([fn f: !t]). *)typeimport_kind=|Import_funcof{typ:identoption;sign:functypeoption;exact:bool}|Import_globalof{mut:bool;typ:valtype}|Import_tagof{typ:identoption;sign:functypeoption}|Import_memoryof{address_type:[`I32|`I64];limits:(Wax_utils.Uint64.t*Wax_utils.Uint64.toption)option;page_size_log2:intoption;shared:bool;}|Import_tableof{address_type:[`I32|`I64];reftype:reftype;limits:(Wax_utils.Uint64.t*Wax_utils.Uint64.toption)option;}(* A single imported entity. [id] is its Wax name; it is imported under that
name unless a name-only [#[import = "name"]] attribute overrides it.
[attributes] also carries e.g. [#[export]] to re-export it. *)typeimport_decl={id:ident;kind:import_kind;attributes:attributes}(* One element of a data segment's contents (WAT "numeric values" proposal): a
string literal (its raw bytes), a scalar numeric run [[f32: 1.5, nan, …]], or a
[v128] run [[v128: i32x4(1,2,3,4), …]]. In a run the element type is stated
once and the values are raw literal strings, packed little-endian. Holds no
instructions — every value is a literal. *)typedata_elem=|Data_stringofstring|Data_runofstoragetype*(string,location)annotatedlist|Data_v128of(Wax_utils.V128.t,location)annotatedlist(* A data segment's contents: elements concatenated in order; an empty list is an
empty segment. *)type'infomemdata={data_name:identoption;offset:'infoinstr;init:data_elemlist;}type'infodatamode=Passive|Activeofident*'infoinstrtype'infoelemmode=EPassive|EActiveofident*'infoinstrtype'infomodulefield=|Typeofrectype|Funcof{name:ident;typ:identoption;sign:functypeoption;body:labeloption*'infoinstrlist;attributes:attributes;}|Globalof{name:ident;mut:bool;typ:valtypeoption;def:'infoinstr;attributes:attributes;}|Tagof{name:ident;typ:identoption;sign:functypeoption;attributes:attributes;}|Memoryof{name:ident;address_type:[`I32|`I64];limits:(Wax_utils.Uint64.t*Wax_utils.Uint64.toption)option;(* Custom page size as its base-2 logarithm ([None] is the default
65536-byte page). *)page_size_log2:intoption;shared:bool;data:'infomemdatalist;attributes:attributes;}|Dataof{name:identoption;mode:'infodatamode;init:data_elemlist;attributes:attributes;}|Tableof{name:ident;address_type:[`I32|`I64];reftype:reftype;limits:(Wax_utils.Uint64.t*Wax_utils.Uint64.toption)option;init:'infoinstroption;attributes:attributes;}|Elemof{name:ident;reftype:reftype;mode:'infoelemmode;init:'infoinstrlist;attributes:attributes;}(* A single import, [import "module" fn f();]. *)|Importof{module_:(string,location)annotated;decl:(import_decl,location)annotated;}(* A grouped import block, [import "module" { fn f(); const c: i32; }]: several
imports sharing one module. *)|Import_groupof{module_:(string,location)annotated;decls:(import_decl,location)annotatedlist;}(* A module-level inner attribute, [#![module = "name"]]. Unlike the outer
attributes above it is attached to the whole module rather than a field;
the only one recognized is [module], which names the module. *)|Module_annotationofattributes|Conditionalof{cond:Wax_wasm.Ast.cond;then_fields:(('infomodulefield,location)annotatedlist,location)annotated;else_fields:(('infomodulefield,location)annotatedlist,location)annotatedoption;}type'infomodule_=('infomodulefield,location)annotatedlist