| %{ |
| open Source |
| open Types |
| open Ast |
| open Mnemonics |
| open Script |
| |
| |
| (* Error handling *) |
| |
| let error at msg = raise (Parse_error.Syntax (at, msg)) |
| |
| let thd (_, _, x) = x |
| |
| |
| (* Position handling *) |
| |
| let loc_of_pos position = |
| { file = position.Lexing.pos_fname; |
| line = position.Lexing.pos_lnum; |
| column = position.Lexing.pos_cnum - position.Lexing.pos_bol |
| } |
| |
| let region_of_pos position1 position2 = |
| { left = loc_of_pos position1; |
| right = loc_of_pos position2 |
| } |
| |
| let at (l, r) = region_of_pos l r |
| |
| let (@@@) = Source.(@@) |
| let (@@) x loc = x @@@ at loc |
| |
| |
| (* Literals *) |
| |
| let nat8 s loc = |
| try I8.of_string_u s with Failure _ -> error (at loc) "i8 constant out of range" |
| |
| let nat32 s loc = |
| try I32.of_string_u s with Failure _ -> error (at loc) "i32 constant out of range" |
| |
| let nat64 s loc = |
| try I64.of_string_u s with Failure _ -> error (at loc) "i64 constant out of range" |
| |
| let name s loc = |
| try Utf8.decode s with Utf8.Utf8 -> error (at loc) "malformed UTF-8 encoding" |
| |
| let var s loc = |
| let r = at loc in |
| try ignore (Utf8.decode s); Source.(s @@ r) |
| with Utf8.Utf8 -> error r "malformed UTF-8 encoding" |
| |
| let num f s = |
| try f s with Failure _ -> error s.at "constant out of range" |
| |
| let vec f shape ss loc = |
| try f shape ss (at loc) with |
| | Failure _ -> error (at loc) "constant out of range" |
| | Invalid_argument _ -> error (at loc) "wrong number of lane literals" |
| |
| let vec_lane_nan shape l at = |
| let open Value in |
| match shape with |
| | V128.F32x4 () -> NanPat (F32 l @@@ at) |
| | V128.F64x2 () -> NanPat (F64 l @@@ at) |
| | _ -> error at "invalid vector constant" |
| |
| let vec_lane_lit shape l at = |
| let open Value in |
| match shape with |
| | V128.I8x16 () -> NumPat (I32 (Convert.I32_.extend_i8_s (I8.of_string l)) @@@ at) |
| | V128.I16x8 () -> NumPat (I32 (Convert.I32_.extend_i16_s (I16.of_string l)) @@@ at) |
| | V128.I32x4 () -> NumPat (I32 (I32.of_string l) @@@ at) |
| | V128.I64x2 () -> NumPat (I64 (I64.of_string l) @@@ at) |
| | V128.F32x4 () -> NumPat (F32 (F32.of_string l) @@@ at) |
| | V128.F64x2 () -> NumPat (F64 (F64.of_string l) @@@ at) |
| |
| let shuffle_lit ss loc = |
| if not (List.length ss = 16) then |
| error (at loc) "invalid lane length"; |
| List.map (fun s -> nat8 s.it loc) ss |
| |
| let nanop f nan = |
| let open Source in |
| let open Value in |
| match snd (f ("0" @@ no_region)) with |
| | F32 _ -> F32 nan.it @@ nan.at |
| | F64 _ -> F64 nan.it @@ nan.at |
| | I32 _ | I64 _ -> error nan.at "NaN pattern with non-float type" |
| |
| |
| (* Symbolic indices *) |
| |
| module VarMap = Map.Make(String) |
| |
| type space = {mutable map : int32 VarMap.t; mutable count : int32} |
| let empty () = {map = VarMap.empty; count = 0l} |
| |
| let shift category at n i = |
| let i' = Int32.add i n in |
| if I32.lt_u i' n then |
| error at ("too many " ^ category ^ " bindings"); |
| i' |
| |
| let bind category space n at = |
| let i = space.count in |
| space.count <- shift category at n i; |
| i |
| |
| let scoped category n space at = |
| {map = VarMap.map (shift category at n) space.map; count = space.count} |
| |
| |
| type types = |
| { space : space; |
| mutable fields : space list; |
| mutable list : type_ list; |
| mutable ctx : deftype list; |
| } |
| |
| type context = |
| { types : types; tags : space; globals : space; |
| memories : space; tables : space; funcs : space; |
| datas : space; elems : space; locals : space; labels : space; |
| deferred_locals : (unit -> unit) list ref |
| } |
| |
| let empty_types () = {space = empty (); fields = []; list = []; ctx = []} |
| let empty_context () = |
| { types = empty_types (); tags = empty (); globals = empty (); |
| memories = empty (); tables = empty (); funcs = empty (); |
| datas = empty (); elems = empty (); locals = empty (); labels = empty (); |
| deferred_locals = ref [] |
| } |
| |
| let enter_block (c : context) loc = {c with labels = scoped "label" 1l c.labels (at loc)} |
| let enter_let (c : context) loc = {c with locals = empty (); deferred_locals = ref []} |
| let enter_func (c : context) loc = {(enter_let c loc) with labels = empty ()} |
| |
| let defer_locals (c : context) f = |
| c.deferred_locals := (fun () -> ignore (f ())) :: !(c.deferred_locals) |
| |
| let force_locals (c : context) = |
| List.fold_right Stdlib.(@@) !(c.deferred_locals) (); |
| c.deferred_locals := [] |
| |
| |
| let print x = |
| let s = Types.string_of_name (Utf8.decode x.it) in |
| "$" ^ if s = x.it then s else "\"" ^ s ^ "\"" |
| |
| let lookup category space x = |
| try VarMap.find x.it space.map |
| with Not_found -> error x.at ("unknown " ^ category ^ " " ^ print x) |
| |
| let type_ (c : context) x = lookup "type" c.types.space x |
| let tag (c : context) x = lookup "tag" c.tags x |
| let global (c : context) x = lookup "global" c.globals x |
| let memory (c : context) x = lookup "memory" c.memories x |
| let table (c : context) x = lookup "table" c.tables x |
| let func (c : context) x = lookup "function" c.funcs x |
| let data (c : context) x = lookup "data segment" c.datas x |
| let elem (c : context) x = lookup "elem segment" c.elems x |
| let local (c : context) x = lookup "local" c.locals x |
| let label (c : context) x = lookup "label " c.labels x |
| let field x (c : context) y = |
| lookup "field " (Lib.List32.nth c.types.fields x) y |
| |
| let func_type (c : context) x = |
| match expand_deftype (Lib.List32.nth c.types.ctx x.it) with |
| | FuncT (ts1, ts2) -> ts1, ts2 |
| | _ -> error x.at ("non-function type " ^ Int32.to_string x.it) |
| | exception Failure _ -> error x.at ("unknown type " ^ Int32.to_string x.it) |
| |
| |
| let bind_abs category space x = |
| if VarMap.mem x.it space.map then |
| error x.at ("duplicate " ^ category ^ " " ^ print x); |
| let i = bind category space 1l x.at in |
| space.map <- VarMap.add x.it i space.map; |
| i |
| |
| let bind_rel category space x = |
| ignore (bind category space 1l x.at); |
| space.map <- VarMap.add x.it 0l space.map; |
| 0l |
| |
| let new_fields (c : context) = |
| c.types.fields <- c.types.fields @ [empty ()] |
| |
| let bind_type (c : context) x = new_fields c; bind_abs "type" c.types.space x |
| let bind_tag (c : context) x = bind_abs "tag" c.tags x |
| let bind_global (c : context) x = bind_abs "global" c.globals x |
| let bind_memory (c : context) x = bind_abs "memory" c.memories x |
| let bind_table (c : context) x = bind_abs "table" c.tables x |
| let bind_func (c : context) x = bind_abs "function" c.funcs x |
| let bind_data (c : context) x = bind_abs "data segment" c.datas x |
| let bind_elem (c : context) x = bind_abs "elem segment" c.elems x |
| let bind_local (c : context) x = force_locals c; bind_abs "local" c.locals x |
| let bind_label (c : context) x = bind_rel "label" c.labels x |
| let bind_field (c : context) x y = |
| bind_abs "field" (Lib.List32.nth c.types.fields x) y |
| |
| let define_type (c : context) (ty : type_) = |
| c.types.list <- c.types.list @ [ty] |
| |
| let define_deftype (c : context) (dt : deftype) = |
| assert (c.types.space.count > Lib.List32.length c.types.ctx); |
| c.types.ctx <- c.types.ctx @ [dt] |
| |
| let anon_type (c : context) loc = new_fields c; bind "type" c.types.space 1l (at loc) |
| let anon_tag (c : context) loc = bind "tag" c.tags 1l (at loc) |
| let anon_global (c : context) loc = bind "global" c.globals 1l (at loc) |
| let anon_memory (c : context) loc = bind "memory" c.memories 1l (at loc) |
| let anon_table (c : context) loc = bind "table" c.tables 1l (at loc) |
| let anon_func (c : context) loc = bind "function" c.funcs 1l (at loc) |
| let anon_data (c : context) loc = bind "data segment" c.datas 1l (at loc) |
| let anon_elem (c : context) loc = bind "elem segment" c.elems 1l (at loc) |
| let anon_locals (c : context) n loc = |
| defer_locals c (fun () -> bind "local" c.locals n (at loc)) |
| let anon_label (c : context) loc = bind "label" c.labels 1l (at loc) |
| let anon_fields (c : context) x n loc = |
| bind "field" (Lib.List32.nth c.types.fields x) n (at loc) |
| |
| |
| let inline_functype (c : context) (ts1, ts2) loc = |
| let st = SubT (Final, [], FuncT (ts1, ts2)) in |
| match |
| Lib.List.index_where (function |
| | DefT (RecT [st'], 0l) -> st = st' |
| | _ -> false |
| ) c.types.ctx |
| with |
| | Some i -> Int32.of_int i @@ loc |
| | None -> |
| let i = anon_type c loc in |
| define_type c (RecT [st] @@ loc); |
| define_deftype c (DefT (RecT [st], 0l)); |
| i @@ loc |
| |
| let inline_functype_explicit (c : context) x ft = |
| if ft = ([], []) then |
| (* Deferring ensures that type lookup is only triggered when |
| symbolic identifiers are used, and not for desugared functions *) |
| defer_locals c (fun () -> |
| let (ts1, _ts2) = func_type c x in |
| bind "local" c.locals (Lib.List32.length ts1) x.at |
| ) |
| else if ft <> func_type c x then |
| error x.at "inline function type does not match explicit type"; |
| x |
| |
| |
| (* Custom annotations *) |
| |
| let parse_annots (m : module_) : Custom.section list = |
| let bs = Annot.get_source () in |
| let annots = Annot.get m.at in |
| let secs = |
| Annot.NameMap.fold (fun name anns secs -> |
| match Custom.handler name with |
| | Some (module Handler) -> |
| let secs' = Handler.parse m bs anns in |
| List.map (fun fmt -> |
| let module S = struct module Handler = Handler let it = fmt end in |
| (module S : Custom.Section) |
| ) secs' @ secs |
| | None -> |
| if !Flags.custom_reject then |
| raise (Custom.Syntax ((List.hd anns).at, |
| "unknown annotation @" ^ Utf8.encode name)) |
| else [] |
| ) annots [] |
| in |
| List.stable_sort Custom.compare_section secs |
| |
| %} |
| |
| %token LPAR RPAR |
| %token<string> NAT INT FLOAT STRING VAR |
| %token<Types.numtype> NUMTYPE |
| %token<Types.vectype> VECTYPE |
| %token<Types.packtype> PACKTYPE |
| %token<V128.shape> VECSHAPE |
| %token ANYREF NULLREF EQREF I31REF STRUCTREF ARRAYREF |
| %token FUNCREF NULLFUNCREF EXNREF NULLEXNREF EXTERNREF NULLEXTERNREF |
| %token ANY NONE EQ I31 REF NOFUNC EXN NOEXN EXTERN NOEXTERN NULL |
| %token MUT FIELD STRUCT ARRAY SUB FINAL REC |
| %token UNREACHABLE NOP DROP SELECT |
| %token BLOCK END IF THEN ELSE LOOP |
| %token BR BR_IF BR_TABLE |
| %token<Ast.idx -> Ast.instr'> BR_ON_NULL |
| %token<Ast.idx -> Types.reftype -> Types.reftype -> Ast.instr'> BR_ON_CAST |
| %token CALL CALL_REF CALL_INDIRECT |
| %token RETURN RETURN_CALL RETURN_CALL_REF RETURN_CALL_INDIRECT |
| %token THROW THROW_REF TRY_TABLE CATCH CATCH_REF CATCH_ALL CATCH_ALL_REF |
| %token LOCAL_GET LOCAL_SET LOCAL_TEE GLOBAL_GET GLOBAL_SET |
| %token TABLE_GET TABLE_SET |
| %token TABLE_SIZE TABLE_GROW TABLE_FILL TABLE_COPY TABLE_INIT ELEM_DROP |
| %token MEMORY_SIZE MEMORY_GROW MEMORY_FILL MEMORY_COPY MEMORY_INIT DATA_DROP |
| %token<Ast.idx -> int option -> Memory.offset -> Ast.instr'> LOAD STORE |
| %token<string> OFFSET_EQ_NAT ALIGN_EQ_NAT |
| %token<string Source.phrase -> Ast.instr' * Value.num> CONST |
| %token<Ast.instr'> UNARY BINARY TEST COMPARE CONVERT |
| %token REF_NULL REF_FUNC REF_I31 REF_STRUCT REF_ARRAY REF_EXN REF_EXTERN REF_HOST |
| %token REF_EQ REF_IS_NULL REF_AS_NON_NULL REF_TEST REF_CAST |
| %token<Ast.instr'> I31_GET |
| %token<Ast.idx -> Ast.instr'> STRUCT_NEW ARRAY_NEW ARRAY_GET |
| %token STRUCT_SET |
| %token<Ast.idx -> int32 -> Ast.instr'> STRUCT_GET |
| %token ARRAY_NEW_FIXED ARRAY_NEW_ELEM ARRAY_NEW_DATA |
| %token ARRAY_SET ARRAY_LEN |
| %token ARRAY_COPY ARRAY_FILL ARRAY_INIT_DATA ARRAY_INIT_ELEM |
| %token<Ast.instr'> EXTERN_CONVERT |
| %token<Ast.idx -> int option -> Memory.offset -> Ast.instr'> VEC_LOAD VEC_STORE |
| %token<Ast.idx -> int option -> Memory.offset -> Ast.laneidx -> Ast.instr'> VEC_LOAD_LANE VEC_STORE_LANE |
| %token<V128.shape -> string Source.phrase list -> Source.region -> Ast.instr' * Value.vec> VEC_CONST |
| %token<Ast.instr'> VEC_UNARY VEC_BINARY VEC_TERNARY VEC_TEST |
| %token<Ast.instr'> VEC_SHIFT VEC_BITMASK VEC_SPLAT |
| %token VEC_SHUFFLE |
| %token<Ast.laneidx -> Ast.instr'> VEC_EXTRACT VEC_REPLACE |
| %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL |
| %token TABLE ELEM MEMORY TAG DATA DECLARE OFFSET ITEM IMPORT EXPORT |
| %token MODULE BIN QUOTE DEFINITION INSTANCE |
| %token SCRIPT REGISTER INVOKE GET |
| %token ASSERT_MALFORMED ASSERT_INVALID ASSERT_UNLINKABLE |
| %token ASSERT_RETURN ASSERT_TRAP ASSERT_EXCEPTION ASSERT_EXHAUSTION |
| %token ASSERT_MALFORMED_CUSTOM ASSERT_INVALID_CUSTOM |
| %token<Script.nan> NAN |
| %token EITHER |
| %token INPUT OUTPUT |
| %token EOF |
| |
| %start script script1 module1 |
| %type<Script.script> script |
| %type<Script.script> script1 |
| %type<Script.var option * Script.definition> module1 |
| |
| %% |
| |
| /* Auxiliaries */ |
| |
| name : |
| | STRING { name $1 $sloc } |
| |
| string_list : |
| | /* empty */ { "" } |
| | string_list STRING { $1 ^ $2 } |
| |
| |
| /* Types */ |
| |
| %inline addrtype : |
| | NUMTYPE |
| { match $1 with |
| | I32T -> I32AT |
| | I64T -> I64AT |
| | _ -> error (at $sloc) "malformed address type" } |
| | /* empty */ { I32AT } /* Sugar */ |
| |
| null_opt : |
| | /* empty */ { NoNull } |
| | NULL { Null } |
| |
| heaptype : |
| | ANY { fun c -> AnyHT } |
| | NONE { fun c -> NoneHT } |
| | EQ { fun c -> EqHT } |
| | I31 { fun c -> I31HT } |
| | STRUCT { fun c -> StructHT } |
| | ARRAY { fun c -> ArrayHT } |
| | FUNC { fun c -> FuncHT } |
| | NOFUNC { fun c -> NoFuncHT } |
| | EXN { fun c -> ExnHT } |
| | NOEXN { fun c -> NoExnHT } |
| | EXTERN { fun c -> ExternHT } |
| | NOEXTERN { fun c -> NoExternHT } |
| | idx { fun c -> UseHT (Idx ($1 c type_).it) } |
| |
| reftype : |
| | LPAR REF null_opt heaptype RPAR { fun c -> ($3, $4 c) } |
| | ANYREF { fun c -> (Null, AnyHT) } /* Sugar */ |
| | NULLREF { fun c -> (Null, NoneHT) } /* Sugar */ |
| | EQREF { fun c -> (Null, EqHT) } /* Sugar */ |
| | I31REF { fun c -> (Null, I31HT) } /* Sugar */ |
| | STRUCTREF { fun c -> (Null, StructHT) } /* Sugar */ |
| | ARRAYREF { fun c -> (Null, ArrayHT) } /* Sugar */ |
| | FUNCREF { fun c -> (Null, FuncHT) } /* Sugar */ |
| | NULLFUNCREF { fun c -> (Null, NoFuncHT) } /* Sugar */ |
| | EXNREF { fun c -> (Null, ExnHT) } /* Sugar */ |
| | NULLEXNREF { fun c -> (Null, NoExnHT) } /* Sugar */ |
| | EXTERNREF { fun c -> (Null, ExternHT) } /* Sugar */ |
| | NULLEXTERNREF { fun c -> (Null, NoExternHT) } /* Sugar */ |
| |
| valtype : |
| | NUMTYPE { fun c -> NumT $1 } |
| | VECTYPE { fun c -> VecT $1 } |
| | reftype { fun c -> RefT ($1 c) } |
| |
| valtype_list : |
| | list(valtype) |
| { Lib.List32.length $1, fun c -> List.map (fun f -> f c) $1 } |
| |
| globaltype : |
| | valtype { fun c -> GlobalT (Cons, $1 c) } |
| | LPAR MUT valtype RPAR { fun c -> GlobalT (Var, $3 c) } |
| |
| storagetype : |
| | valtype { fun c -> ValStorageT ($1 c) } |
| | PACKTYPE { fun c -> PackStorageT $1 } |
| |
| fieldtype : |
| | storagetype { fun c -> FieldT (Cons, $1 c) } |
| | LPAR MUT storagetype RPAR { fun c -> FieldT (Var, $3 c) } |
| |
| fieldtype_list : |
| | /* empty */ { fun c -> [] } |
| | fieldtype fieldtype_list { fun c -> $1 c :: $2 c } |
| |
| struct_field_list : |
| | /* empty */ { fun c x -> [] } |
| | LPAR FIELD fieldtype_list RPAR struct_field_list |
| { fun c x -> let fts = $3 c in |
| ignore (anon_fields c x (Lib.List32.length fts) $loc($3)); fts @ $5 c x } |
| | LPAR FIELD bindidx fieldtype RPAR struct_field_list |
| { fun c x -> ignore (bind_field c x $3); $4 c :: $6 c x } |
| |
| structtype : |
| | struct_field_list { $1 } |
| |
| arraytype : |
| | fieldtype { $1 } |
| |
| functype : |
| | functype_result |
| { fun c -> ([], $1 c) } |
| | LPAR PARAM valtype_list RPAR functype |
| { fun c -> let (ts1, ts2) = $5 c in |
| (snd $3 c @ ts1, ts2) } |
| | LPAR PARAM bindidx valtype RPAR functype /* Sugar */ |
| { fun c -> let (ts1, ts2) = $6 c in |
| ($4 c :: ts1, ts2) } |
| |
| functype_result : |
| | /* empty */ |
| { fun c -> [] } |
| | LPAR RESULT valtype_list RPAR functype_result |
| { fun c -> snd $3 c @ $5 c } |
| |
| comptype : |
| | LPAR STRUCT structtype RPAR { fun c x -> StructT ($3 c x) } |
| | LPAR ARRAY arraytype RPAR { fun c x -> ArrayT ($3 c) } |
| | LPAR FUNC functype RPAR { fun c x -> FuncT ($3 c) } |
| |
| subtype : |
| | comptype { fun c x -> SubT (Final, [], $1 c x) } |
| | LPAR SUB idx_list comptype RPAR |
| { fun c x -> SubT (NoFinal, |
| List.map (fun y -> Idx y.it) ($3 c type_), $4 c x) } |
| | LPAR SUB FINAL idx_list comptype RPAR |
| { fun c x -> SubT (Final, |
| List.map (fun y -> Idx y.it) ($4 c type_), $5 c x) } |
| |
| tabletype : |
| | addrtype limits reftype { fun c -> TableT ($1, $2, $3 c) } |
| |
| memorytype : |
| | addrtype limits { fun c -> MemoryT ($1, $2) } |
| |
| limits : |
| | NAT { {min = nat64 $1 $loc($1); max = None} } |
| | NAT NAT { {min = nat64 $1 $loc($1); max = Some (nat64 $2 $loc($2))} } |
| |
| typeuse : |
| | LPAR TYPE idx RPAR { fun c -> $3 c type_ } |
| |
| |
| /* Immediates */ |
| |
| nat8 : |
| | NAT { nat8 $1 $sloc } |
| |
| nat32 : |
| | NAT { nat32 $1 $sloc } |
| |
| num : |
| | NAT { $1 @@ $sloc } |
| | INT { $1 @@ $sloc } |
| | FLOAT { $1 @@ $sloc } |
| |
| idx : |
| | NAT { fun c lookup -> nat32 $1 $sloc @@ $sloc } |
| | VAR { fun c lookup -> lookup c (var $1 $sloc) @@ $sloc } |
| |
| idx_opt : |
| | /* empty */ { fun c lookup at -> 0l @@ at } |
| | idx { fun c lookup at -> $1 c lookup } |
| |
| idx_idx_opt : |
| | /* empty */ { fun c lookup at -> 0l @@ at, 0l @@ at } |
| | idx idx { fun c lookup at -> $1 c lookup, $2 c lookup } |
| |
| idx_list : |
| | /* empty */ { fun c lookup -> [] } |
| | idx idx_list { fun c lookup -> $1 c lookup :: $2 c lookup } |
| |
| bindidx_opt : |
| | /* empty */ { fun c anon bind -> anon c $sloc } |
| | bindidx { fun c anon bind -> bind c $1 } /* Sugar */ |
| |
| bindidx : |
| | VAR { var $1 $sloc } |
| |
| labeling_opt : |
| | /* empty */ |
| { fun c xs -> |
| List.iter (fun x -> error x.at "mismatching label") xs; |
| let c' = enter_block c $sloc in ignore (anon_label c' $sloc); c' } |
| | bindidx |
| { fun c xs -> |
| List.iter |
| (fun x -> if x.it <> $1.it then error x.at "mismatching label") xs; |
| let c' = enter_block c $sloc in ignore (bind_label c' $1); c' } |
| |
| labeling_end_opt : |
| | /* empty */ { [] } |
| | bindidx { [$1] } |
| |
| offset_ : |
| | OFFSET_EQ_NAT { nat64 $1 $sloc } |
| |
| offset_opt : |
| | /* empty */ { 0L } |
| | offset_ { $1 } |
| |
| align : |
| | ALIGN_EQ_NAT |
| { let n = nat64 $1 $sloc in |
| if not (Lib.Int64.is_power_of_two_unsigned n) then |
| error (at $sloc) "alignment must be a power of two"; |
| Some (Int64.to_int (Lib.Int64.log2_unsigned n)) } |
| |
| align_opt : |
| | /* empty */ { None } |
| | align { $1 } |
| |
| |
| /* Instructions & Expressions */ |
| |
| instr_list : |
| | /* empty */ { fun c -> [] } |
| | instr1 instr_list { fun c -> $1 c @ $2 c } |
| | selectinstr_instr_list { $1 } |
| | callinstr_instr_list { $1 } |
| |
| instr1 : |
| | plaininstr { fun c -> [$1 c @@ $sloc] } |
| | blockinstr { fun c -> [$1 c @@ $sloc] } |
| | expr { $1 } /* Sugar */ |
| |
| plaininstr : |
| | UNREACHABLE { fun c -> unreachable } |
| | NOP { fun c -> nop } |
| | DROP { fun c -> drop } |
| | BR idx { fun c -> br ($2 c label) } |
| | BR_IF idx { fun c -> br_if ($2 c label) } |
| | BR_TABLE idx idx_list |
| { fun c -> let xs, x = Lib.List.split_last ($2 c label :: $3 c label) in |
| br_table xs x } |
| | BR_ON_NULL idx { fun c -> $1 ($2 c label) } |
| | BR_ON_CAST idx reftype reftype { fun c -> $1 ($2 c label) ($3 c) ($4 c) } |
| | RETURN { fun c -> return } |
| | CALL idx { fun c -> call ($2 c func) } |
| | CALL_REF idx { fun c -> call_ref ($2 c type_) } |
| | RETURN_CALL idx { fun c -> return_call ($2 c func) } |
| | RETURN_CALL_REF idx { fun c -> return_call_ref ($2 c type_) } |
| | THROW idx { fun c -> throw ($2 c tag) } |
| | THROW_REF { fun c -> throw_ref } |
| | LOCAL_GET idx { fun c -> local_get ($2 c local) } |
| | LOCAL_SET idx { fun c -> local_set ($2 c local) } |
| | LOCAL_TEE idx { fun c -> local_tee ($2 c local) } |
| | GLOBAL_GET idx { fun c -> global_get ($2 c global) } |
| | GLOBAL_SET idx { fun c -> global_set ($2 c global) } |
| | TABLE_GET idx_opt { fun c -> table_get ($2 c table $loc($1)) } |
| | TABLE_SET idx_opt { fun c -> table_set ($2 c table $loc($1)) } |
| | TABLE_SIZE idx_opt { fun c -> table_size ($2 c table $loc($1)) } |
| | TABLE_GROW idx_opt { fun c -> table_grow ($2 c table $loc($1)) } |
| | TABLE_FILL idx_opt { fun c -> table_fill ($2 c table $loc($1)) } |
| | TABLE_COPY idx_idx_opt |
| { fun c -> let x, y = $2 c table $loc($1) in table_copy x y } |
| | TABLE_INIT idx idx |
| { fun c -> table_init ($2 c table) ($3 c elem) } |
| | TABLE_INIT idx /* Sugar */ |
| { fun c -> table_init (0l @@ $loc($1)) ($2 c elem) } |
| | ELEM_DROP idx { fun c -> elem_drop ($2 c elem) } |
| | LOAD idx_opt offset_opt align_opt |
| { fun c -> $1 ($2 c memory $loc($1)) $4 $3 } |
| | STORE idx_opt offset_opt align_opt |
| { fun c -> $1 ($2 c memory $loc($1)) $4 $3 } |
| | VEC_LOAD idx_opt offset_opt align_opt |
| { fun c -> $1 ($2 c memory $loc($1)) $4 $3 } |
| | VEC_STORE idx_opt offset_opt align_opt |
| { fun c -> $1 ($2 c memory $loc($1)) $4 $3 } |
| | VEC_LOAD_LANE lane_imms { fun c -> $2 $1 $loc($1) c } |
| | VEC_STORE_LANE lane_imms { fun c -> $2 $1 $loc($1) c } |
| | MEMORY_SIZE idx_opt { fun c -> memory_size ($2 c memory $loc($1)) } |
| | MEMORY_GROW idx_opt { fun c -> memory_grow ($2 c memory $loc($1)) } |
| | MEMORY_FILL idx_opt { fun c -> memory_fill ($2 c memory $loc($1)) } |
| | MEMORY_COPY idx_idx_opt |
| { fun c -> let x, y = $2 c memory $loc($1) in memory_copy x y } |
| | MEMORY_INIT idx idx |
| { fun c -> memory_init ($2 c memory) ($3 c data) } |
| | MEMORY_INIT idx /* Sugar */ |
| { fun c -> memory_init (0l @@ $loc($1)) ($2 c data) } |
| | DATA_DROP idx { fun c -> data_drop ($2 c data) } |
| | REF_NULL heaptype { fun c -> ref_null ($2 c) } |
| | REF_FUNC idx { fun c -> ref_func ($2 c func) } |
| | REF_IS_NULL { fun c -> ref_is_null } |
| | REF_AS_NON_NULL { fun c -> ref_as_non_null } |
| | REF_TEST reftype { fun c -> ref_test ($2 c) } |
| | REF_CAST reftype { fun c -> ref_cast ($2 c) } |
| | REF_EQ { fun c -> ref_eq } |
| | REF_I31 { fun c -> ref_i31 } |
| | I31_GET { fun c -> $1 } |
| | STRUCT_NEW idx { fun c -> $1 ($2 c type_) } |
| | STRUCT_GET idx idx { fun c -> let x = $2 c type_ in $1 x ($3 c (field x.it)).it } |
| | STRUCT_SET idx idx { fun c -> let x = $2 c type_ in struct_set x ($3 c (field x.it)).it } |
| | ARRAY_NEW idx { fun c -> $1 ($2 c type_) } |
| | ARRAY_NEW_FIXED idx nat32 { fun c -> array_new_fixed ($2 c type_) $3 } |
| | ARRAY_NEW_ELEM idx idx { fun c -> array_new_elem ($2 c type_) ($3 c elem) } |
| | ARRAY_NEW_DATA idx idx { fun c -> array_new_data ($2 c type_) ($3 c data) } |
| | ARRAY_GET idx { fun c -> $1 ($2 c type_) } |
| | ARRAY_SET idx { fun c -> array_set ($2 c type_) } |
| | ARRAY_LEN { fun c -> array_len } |
| | ARRAY_COPY idx idx { fun c -> array_copy ($2 c type_) ($3 c type_) } |
| | ARRAY_FILL idx { fun c -> array_fill ($2 c type_) } |
| | ARRAY_INIT_DATA idx idx { fun c -> array_init_data ($2 c type_) ($3 c data) } |
| | ARRAY_INIT_ELEM idx idx { fun c -> array_init_elem ($2 c type_) ($3 c elem) } |
| | EXTERN_CONVERT { fun c -> $1 } |
| | CONST num { fun c -> fst (num $1 $2) } |
| | TEST { fun c -> $1 } |
| | COMPARE { fun c -> $1 } |
| | UNARY { fun c -> $1 } |
| | BINARY { fun c -> $1 } |
| | CONVERT { fun c -> $1 } |
| | VEC_CONST VECSHAPE list(num) { fun c -> fst (vec $1 $2 $3 $sloc) } |
| | VEC_UNARY { fun c -> $1 } |
| | VEC_BINARY { fun c -> $1 } |
| | VEC_TERNARY { fun c -> $1 } |
| | VEC_TEST { fun c -> $1 } |
| | VEC_SHIFT { fun c -> $1 } |
| | VEC_BITMASK { fun c -> $1 } |
| | VEC_SHUFFLE list(num) { fun c -> i8x16_shuffle (shuffle_lit $2 $sloc) } |
| | VEC_SPLAT { fun c -> $1 } |
| | VEC_EXTRACT laneidx { fun c -> $1 $2 } |
| | VEC_REPLACE laneidx { fun c -> $1 $2 } |
| |
| |
| laneidx : |
| | nat8 { $1 } |
| |
| lane_imms : |
| /* Need to multiply out options and indices to avoid spurious conflicts */ |
| | NAT offset_opt align_opt laneidx |
| { fun instr at0 c -> |
| instr (nat32 $1 $loc($1) @@ $loc($1)) $3 $2 $4 } |
| | VAR offset_opt align_opt laneidx /* Sugar */ |
| { fun instr at0 c -> |
| instr (memory c ($1 @@ $loc($1)) @@ $loc($1)) $3 $2 $4 } |
| | offset_ align_opt laneidx /* Sugar */ |
| { fun instr at0 c -> instr (0l @@ at0) $2 $1 $3 } |
| | align laneidx /* Sugar */ |
| { fun instr at0 c -> instr (0l @@ at0) $1 0L $2 } |
| | laneidx /* Sugar */ |
| { fun instr at0 c -> instr (0l @@ at0) None 0L $1 } |
| |
| |
| selectinstr_instr_list : |
| | SELECT selectinstr_results_instr_list |
| { fun c -> let b, ts, es = $2 c in |
| (select (if b then (Some ts) else None) @@ $loc($1)) :: es } |
| |
| selectinstr_results_instr_list : |
| | LPAR RESULT valtype_list RPAR selectinstr_results_instr_list |
| { fun c -> let _, ts, es = $5 c in true, snd $3 c @ ts, es } |
| | instr_list |
| { fun c -> false, [], $1 c } |
| |
| |
| callinstr_instr_list : |
| | CALL_INDIRECT idx callinstr_type_instr_list |
| { fun c -> let x, es = $3 c in |
| (call_indirect ($2 c table) x @@ $loc($1)) :: es } |
| | CALL_INDIRECT callinstr_type_instr_list /* Sugar */ |
| { fun c -> let x, es = $2 c in |
| (call_indirect (0l @@ $loc($1)) x @@ $loc($1)) :: es } |
| | RETURN_CALL_INDIRECT idx callinstr_type_instr_list |
| { fun c -> let x, es = $3 c in |
| (return_call_indirect ($2 c table) x @@ $loc($1)) :: es } |
| | RETURN_CALL_INDIRECT callinstr_type_instr_list /* Sugar */ |
| { fun c -> let x, es = $2 c in |
| (return_call_indirect (0l @@ $loc($1)) x @@ $loc($1)) :: es } |
| |
| callinstr_type_instr_list : |
| | typeuse callinstr_params_instr_list |
| { fun c -> |
| match $2 c with |
| | ([], []), es -> $1 c, es |
| | ft, es -> inline_functype_explicit c ($1 c) ft, es } |
| | callinstr_params_instr_list |
| { fun c -> let ft, es = $1 c in inline_functype c ft $sloc, es } |
| |
| callinstr_params_instr_list : |
| | LPAR PARAM valtype_list RPAR callinstr_params_instr_list |
| { fun c -> let (ts1, ts2), es = $5 c in |
| (snd $3 c @ ts1, ts2), es } |
| | callinstr_results_instr_list |
| { fun c -> let ts, es = $1 c in ([], ts), es } |
| |
| callinstr_results_instr_list : |
| | LPAR RESULT valtype_list RPAR callinstr_results_instr_list |
| { fun c -> let ts, es = $5 c in snd $3 c @ ts, es } |
| | instr_list |
| { fun c -> [], $1 c } |
| |
| |
| blockinstr : |
| | BLOCK labeling_opt block END labeling_end_opt |
| { fun c -> let c' = $2 c $5 in let bt, es = $3 c' in block bt es } |
| | LOOP labeling_opt block END labeling_end_opt |
| { fun c -> let c' = $2 c $5 in let bt, es = $3 c' in loop bt es } |
| | IF labeling_opt block END labeling_end_opt |
| { fun c -> let c' = $2 c $5 in let bt, es = $3 c' in if_ bt es [] } |
| | IF labeling_opt block ELSE labeling_end_opt instr_list END labeling_end_opt |
| { fun c -> let c' = $2 c ($5 @ $8) in |
| let ts, es1 = $3 c' in if_ ts es1 ($6 c') } |
| | TRY_TABLE labeling_opt handler_block END labeling_end_opt |
| { fun c -> let c' = $2 c $5 in |
| let bt, (cs, es) = $3 c c' in try_table bt cs es } |
| |
| block : |
| | typeuse block_param_body |
| { fun c -> let ft, es = $2 c in |
| let x = inline_functype_explicit c ($1 c) ft in |
| VarBlockType x, es } |
| | block_param_body /* Sugar */ |
| { fun c -> let ft, es = $1 c in |
| let bt = |
| match ft with |
| | ([], []) -> ValBlockType None |
| | ([], [t]) -> ValBlockType (Some t) |
| | ft -> VarBlockType (inline_functype c ft $sloc) |
| in bt, es } |
| |
| block_param_body : |
| | block_result_body { $1 } |
| | LPAR PARAM valtype_list RPAR block_param_body |
| { fun c -> let (ts1, ts2), es = $5 c in |
| (snd $3 c @ ts1, ts2), es } |
| |
| block_result_body : |
| | instr_list { fun c -> ([], []), $1 c } |
| | LPAR RESULT valtype_list RPAR block_result_body |
| { fun c -> let (ts1, ts2), es = $5 c in |
| (ts1, snd $3 c @ ts2), es } |
| |
| |
| handler_block : |
| | typeuse handler_block_param_body |
| { fun c c' -> let ft, esh = $2 c c' in |
| VarBlockType (inline_functype_explicit c ($1 c) ft), esh } |
| | handler_block_param_body /* Sugar */ |
| { fun c c' -> let ft, esh = $1 c c' in |
| let bt = |
| match ft with |
| | ([], []) -> ValBlockType None |
| | ([], [t]) -> ValBlockType (Some t) |
| | ft -> VarBlockType (inline_functype c ft $sloc) |
| in bt, esh } |
| |
| handler_block_param_body : |
| | handler_block_result_body { $1 } |
| | LPAR PARAM valtype_list RPAR handler_block_param_body |
| { fun c c' -> let (ts1, ts2), esh = $5 c c' in |
| (snd $3 c @ ts1, ts2), esh } |
| |
| handler_block_result_body : |
| | handler_block_body { fun c c' -> ([], []), $1 c c' } |
| | LPAR RESULT valtype_list RPAR handler_block_result_body |
| { fun c c' -> let (ts1, ts2), esh = $5 c c' in |
| (ts1, snd $3 c @ ts2), esh } |
| |
| handler_block_body : |
| | instr_list |
| { fun c c' -> [], $1 c' } |
| | LPAR CATCH idx idx RPAR handler_block_body |
| { fun c c' -> let cs, es = $6 c c' in |
| (catch ($3 c tag) ($4 c label) @@ $loc($2)) :: cs, es } |
| | LPAR CATCH_REF idx idx RPAR handler_block_body |
| { fun c c' -> let cs, es = $6 c c' in |
| (catch_ref ($3 c tag) ($4 c label) @@ $loc($2)) :: cs, es } |
| | LPAR CATCH_ALL idx RPAR handler_block_body |
| { fun c c' -> let cs, es = $5 c c' in |
| (catch_all ($3 c label) @@ $loc($2)) :: cs, es } |
| | LPAR CATCH_ALL_REF idx RPAR handler_block_body |
| { fun c c' -> let cs, es = $5 c c' in |
| (catch_all_ref ($3 c label) @@ $loc($2)) :: cs, es } |
| |
| |
| expr : /* Sugar */ |
| | LPAR expr1 RPAR |
| { fun c -> let es, e' = $2 c in es @ [e' @@ $sloc] } |
| |
| expr1 : /* Sugar */ |
| | plaininstr expr_list { fun c -> $2 c, $1 c } |
| | SELECT selectexpr_results |
| { fun c -> let b, ts, es = $2 c in es, select (if b then (Some ts) else None) } |
| | CALL_INDIRECT idx callexpr_type |
| { fun c -> let x, es = $3 c in es, call_indirect ($2 c table) x } |
| | CALL_INDIRECT callexpr_type /* Sugar */ |
| { fun c -> let x, es = $2 c in es, call_indirect (0l @@ $loc($1)) x } |
| | RETURN_CALL_INDIRECT idx callexpr_type |
| { fun c -> let x, es = $3 c in es, return_call_indirect ($2 c table) x } |
| | RETURN_CALL_INDIRECT callexpr_type /* Sugar */ |
| { fun c -> let x, es = $2 c in es, return_call_indirect (0l @@ $loc($1)) x } |
| | BLOCK labeling_opt block |
| { fun c -> let c' = $2 c [] in let bt, es = $3 c' in [], block bt es } |
| | LOOP labeling_opt block |
| { fun c -> let c' = $2 c [] in let bt, es = $3 c' in [], loop bt es } |
| | IF labeling_opt if_block |
| { fun c -> let c' = $2 c [] in |
| let bt, (es, es1, es2) = $3 c c' in es, if_ bt es1 es2 } |
| | TRY_TABLE labeling_opt try_block |
| { fun c -> let c' = $2 c [] in |
| let bt, (cs, es) = $3 c c' in [], try_table bt cs es } |
| |
| selectexpr_results : |
| | LPAR RESULT valtype_list RPAR selectexpr_results |
| { fun c -> let _, ts, es = $5 c in true, snd $3 c @ ts, es } |
| | expr_list |
| { fun c -> false, [], $1 c } |
| |
| callexpr_type : |
| | typeuse callexpr_params |
| { fun c -> |
| match $2 c with |
| | ([], []), es -> $1 c, es |
| | ft, es -> inline_functype_explicit c ($1 c) ft, es } |
| | callexpr_params |
| { fun c -> let ft, es = $1 c in inline_functype c ft $loc($1), es } |
| |
| callexpr_params : |
| | LPAR PARAM valtype_list RPAR callexpr_params |
| { fun c -> let (ts1, ts2), es = $5 c in |
| (snd $3 c @ ts1, ts2), es } |
| | callexpr_results |
| { fun c -> let ts, es = $1 c in ([], ts), es } |
| |
| callexpr_results : |
| | LPAR RESULT valtype_list RPAR callexpr_results |
| { fun c -> let ts, es = $5 c in snd $3 c @ ts, es } |
| | expr_list |
| { fun c -> [], $1 c } |
| |
| |
| if_block : |
| | typeuse if_block_param_body |
| { fun c c' -> let ft, es = $2 c c' in |
| let x = inline_functype_explicit c ($1 c) ft in |
| VarBlockType x, es } |
| | if_block_param_body /* Sugar */ |
| { fun c c' -> let ft, es = $1 c c' in |
| let bt = |
| match ft with |
| | ([], []) -> ValBlockType None |
| | ([], [t]) -> ValBlockType (Some t) |
| | ft -> VarBlockType (inline_functype c ft $sloc) |
| in bt, es } |
| |
| if_block_param_body : |
| | if_block_result_body { $1 } |
| | LPAR PARAM valtype_list RPAR if_block_param_body |
| { fun c c' -> let (ts1, ts2), es = $5 c c' in |
| (snd $3 c @ ts1, ts2), es } |
| |
| if_block_result_body : |
| | if_ { fun c c' -> ([], []), $1 c c' } |
| | LPAR RESULT valtype_list RPAR if_block_result_body |
| { fun c c' -> let (ts1, ts2), es = $5 c c' in |
| (ts1, snd $3 c @ ts2), es } |
| |
| if_ : |
| | expr if_ |
| { fun c c' -> let es = $1 c in let es0, es1, es2 = $2 c c' in |
| es @ es0, es1, es2 } |
| | LPAR THEN instr_list RPAR LPAR ELSE instr_list RPAR /* Sugar */ |
| { fun c c' -> [], $3 c', $7 c' } |
| | LPAR THEN instr_list RPAR /* Sugar */ |
| { fun c c' -> [], $3 c', [] } |
| |
| |
| try_block : |
| | typeuse try_block_param_body |
| { fun c c' -> |
| let ft, esh = $2 c c' in |
| let bt = VarBlockType (inline_functype_explicit c' ($1 c') ft) in |
| bt, esh } |
| | try_block_param_body /* Sugar */ |
| { fun c c' -> |
| let ft, esh = $1 c c' in |
| let bt = |
| match ft with |
| | ([], []) -> ValBlockType None |
| | ([], [t]) -> ValBlockType (Some t) |
| | _ -> VarBlockType (inline_functype c' ft $sloc) |
| in bt, esh } |
| |
| try_block_param_body : |
| | try_block_result_body { $1 } |
| | LPAR PARAM valtype_list RPAR try_block_param_body |
| { fun c c' -> let (ts1, ts2), esh = $5 c c' in |
| (snd $3 c @ ts1, ts2), esh } |
| |
| try_block_result_body : |
| | try_block_handler_body { fun c c' -> ([], []), $1 c c' } |
| | LPAR RESULT valtype_list RPAR try_block_result_body |
| { fun c c' -> let (ts1, ts2), esh = $5 c c' in |
| (ts1, snd $3 c @ ts2), esh } |
| |
| try_block_handler_body : |
| | instr_list |
| { fun c c' -> [], $1 c' } |
| | LPAR CATCH idx idx RPAR try_block_handler_body |
| { fun c c' -> let cs, es = $6 c c' in |
| (catch ($3 c tag) ($4 c label) @@ $loc($2)) :: cs, es } |
| | LPAR CATCH_REF idx idx RPAR try_block_handler_body |
| { fun c c' -> let cs, es = $6 c c' in |
| (catch_ref ($3 c tag) ($4 c label) @@ $loc($2)) :: cs, es } |
| | LPAR CATCH_ALL idx RPAR try_block_handler_body |
| { fun c c' -> let cs, es = $5 c c' in |
| (catch_all ($3 c label) @@ $loc($2)) :: cs, es } |
| | LPAR CATCH_ALL_REF idx RPAR try_block_handler_body |
| { fun c c' -> let cs, es = $5 c c' in |
| (catch_all_ref ($3 c label) @@ $loc($2)) :: cs, es } |
| |
| |
| expr_list : |
| | /* empty */ { fun c -> [] } |
| | expr expr_list { fun c -> $1 c @ $2 c } |
| |
| constexpr : |
| | instr_list { fun c -> $1 c @@ $sloc } |
| |
| constexpr1 : |
| | instr1 instr_list { fun c -> ($1 c @ $2 c) @@ $sloc } |
| |
| |
| /* Functions */ |
| |
| func : |
| | LPAR FUNC bindidx_opt func_fields RPAR |
| { fun c -> let x = $3 c anon_func bind_func @@ $sloc in |
| fun () -> $4 c x $sloc } |
| |
| func_fields : |
| | typeuse func_fields_body |
| { fun c x loc -> |
| let c' = enter_func c loc in |
| let y = inline_functype_explicit c' ($1 c') (fst $2 c') in |
| let Func (_, ls, es) = snd $2 c' in |
| [Func (y, ls, es) @@ loc], [], [] } |
| | func_fields_body /* Sugar */ |
| { fun c x loc -> |
| let c' = enter_func c loc in |
| let y = inline_functype c' (fst $1 c') loc in |
| let Func (_, ls, es) = snd $1 c' in |
| [Func (y, ls, es) @@ loc], [], [] } |
| | inline_import typeuse func_fields_import /* Sugar */ |
| { fun c x loc -> |
| let y = inline_functype_explicit c ($2 c) ($3 c) in |
| [], |
| [Import (fst $1, snd $1, ExternFuncT (Idx y.it)) @@ loc ], [] } |
| | inline_import func_fields_import /* Sugar */ |
| { fun c x loc -> |
| let y = inline_functype c ($2 c) loc in |
| [], |
| [Import (fst $1, snd $1, ExternFuncT (Idx y.it)) @@ loc ], [] } |
| | inline_export func_fields /* Sugar */ |
| { fun c x loc -> |
| let fns, ims, exs = $2 c x loc in fns, ims, $1 (FuncX x) c :: exs } |
| |
| func_fields_import : /* Sugar */ |
| | func_fields_import_result { $1 } |
| | LPAR PARAM valtype_list RPAR func_fields_import |
| { fun c -> let (ts1, ts2) = $5 c in (snd $3 c @ ts1, ts2) } |
| | LPAR PARAM bindidx valtype RPAR func_fields_import /* Sugar */ |
| { fun c -> let (ts1, ts2) = $6 c in ($4 c :: ts1, ts2) } |
| |
| func_fields_import_result : /* Sugar */ |
| | /* empty */ { fun c -> ([], []) } |
| | LPAR RESULT valtype_list RPAR func_fields_import_result |
| { fun c -> let (ts1, ts2) = $5 c in (ts1, snd $3 c @ ts2) } |
| |
| func_fields_body : |
| | func_result_body { $1 } |
| | LPAR PARAM valtype_list RPAR func_fields_body |
| { (fun c -> let (ts1, ts2) = fst $5 c in (snd $3 c @ ts1, ts2)), |
| (fun c -> anon_locals c (fst $3) $loc($3); snd $5 c) } |
| | LPAR PARAM bindidx valtype RPAR func_fields_body /* Sugar */ |
| { (fun c -> let (ts1, ts2) = fst $6 c in ($4 c :: ts1, ts2)), |
| (fun c -> ignore (bind_local c $3); snd $6 c) } |
| |
| func_result_body : |
| | func_body { (fun c -> ([], [])), $1 } |
| | LPAR RESULT valtype_list RPAR func_result_body |
| { (fun c -> let (ts1, ts2) = fst $5 c in (ts1, snd $3 c @ ts2)), |
| snd $5 } |
| |
| func_body : |
| | instr_list |
| { fun c -> ignore (anon_label c $sloc); |
| Func (-1l @@ $sloc, [], $1 c) } |
| | LPAR LOCAL localtype_list RPAR func_body |
| { fun c -> anon_locals c (fst $3) $loc($3); |
| let Func (x, ls, es) = $5 c in |
| Func (x, snd $3 c @ ls, es) } |
| | LPAR LOCAL bindidx localtype RPAR func_body /* Sugar */ |
| { fun c -> ignore (bind_local c $3); |
| let Func (x, ls, es) = $6 c in |
| Func (x, $4 c :: ls, es) } |
| |
| |
| localtype : |
| | valtype { fun c -> Local ($1 c) @@ $sloc } |
| |
| localtype_list : |
| | list(localtype) |
| { Lib.List32.length $1, fun c -> List.map (fun f -> f c) $1 } |
| |
| |
| /* Tags, Globals, Memories, Tables */ |
| |
| tag : |
| | LPAR TAG bindidx_opt tag_fields RPAR |
| { fun c -> let x = $3 c anon_tag bind_tag @@ $sloc in fun () -> $4 c x $sloc } |
| |
| tag_fields : |
| | typeuse functype |
| { fun c x loc -> |
| let y = inline_functype_explicit c ($1 c) ($2 c) in |
| let tt = TagT (Idx y.it) in |
| [Tag tt @@ loc], [], [] } |
| | functype /* Sugar */ |
| { fun c x loc -> |
| let y = inline_functype c ($1 c) $sloc in |
| let tt = TagT (Idx y.it) in |
| [Tag tt @@ loc], [], [] } |
| | inline_import typeuse functype /* Sugar */ |
| { fun c x loc -> |
| let y = inline_functype_explicit c ($2 c) ($3 c) in |
| let tt = TagT (Idx y.it) in |
| [], |
| [Import (fst $1, snd $1, ExternTagT tt) @@ loc ], [] } |
| | inline_import functype /* Sugar */ |
| { fun c x loc -> |
| let y = inline_functype c ($2 c) $loc($2) in |
| let tt = TagT (Idx y.it) in |
| [], |
| [Import (fst $1, snd $1, ExternTagT tt) @@ loc ], [] } |
| | inline_export tag_fields /* Sugar */ |
| { fun c x loc -> |
| let tgs, ims, exs = $2 c x loc in tgs, ims, $1 (TagX x) c :: exs } |
| |
| |
| global : |
| | LPAR GLOBAL bindidx_opt global_fields RPAR |
| { fun c -> let x = $3 c anon_global bind_global @@ $sloc in |
| fun () -> $4 c x $sloc } |
| |
| global_fields : |
| | globaltype constexpr |
| { fun c x loc -> [Global ($1 c, $2 c) @@ loc], [], [] } |
| | inline_import globaltype /* Sugar */ |
| { fun c x loc -> |
| [], |
| [Import (fst $1, snd $1, ExternGlobalT ($2 c)) @@ loc], [] } |
| | inline_export global_fields /* Sugar */ |
| { fun c x loc -> let globs, ims, exs = $2 c x loc in |
| globs, ims, $1 (GlobalX x) c :: exs } |
| |
| |
| offset : |
| | LPAR OFFSET constexpr RPAR { $3 } |
| | expr { fun c -> $1 c @@ $sloc } /* Sugar */ |
| |
| data : |
| | LPAR DATA bindidx_opt string_list RPAR |
| { fun c -> ignore ($3 c anon_data bind_data); |
| fun () -> Data ($4, Passive @@ $sloc) @@ $sloc } |
| | LPAR DATA bindidx_opt memoryuse offset string_list RPAR |
| { fun c -> ignore ($3 c anon_data bind_data); |
| fun () -> |
| Data ($6, Active ($4 c memory, $5 c) @@ $sloc) @@ $sloc } |
| | LPAR DATA bindidx_opt offset string_list RPAR /* Sugar */ |
| { fun c -> ignore ($3 c anon_data bind_data); |
| fun () -> |
| Data ($5, Active (0l @@ $sloc, $4 c) @@ $sloc) @@ $sloc } |
| |
| |
| memoryuse : |
| | LPAR MEMORY idx RPAR { fun c -> $3 c } |
| |
| memory : |
| | LPAR MEMORY bindidx_opt memory_fields RPAR |
| { fun c -> let x = $3 c anon_memory bind_memory @@ $sloc in |
| fun () -> $4 c x $sloc } |
| |
| memory_fields : |
| | memorytype |
| { fun c x loc -> [Memory ($1 c) @@ loc], [], [], [] } |
| | inline_import memorytype /* Sugar */ |
| { fun c x loc -> |
| [], [], |
| [Import (fst $1, snd $1, ExternMemoryT ($2 c)) @@ loc], [] } |
| | inline_export memory_fields /* Sugar */ |
| { fun c x loc -> let mems, data, ims, exs = $2 c x loc in |
| mems, data, ims, $1 (MemoryX x) c :: exs } |
| | addrtype LPAR DATA string_list RPAR /* Sugar */ |
| { fun c x loc -> |
| let size = Int64.(div (add (of_int (String.length $4)) 65535L) 65536L) in |
| let offset = [at_const $1 (0L @@ loc) @@ loc] @@ loc in |
| [Memory (MemoryT ($1, {min = size; max = Some size})) @@ loc], |
| [Data ($4, Active (x, offset) @@ loc) @@ loc], |
| [], [] } |
| |
| |
| elemkind : |
| | FUNC { (NoNull, FuncHT) } |
| |
| elemexpr : |
| | LPAR ITEM constexpr RPAR { $3 } |
| | expr { fun c -> $1 c @@ $sloc } /* Sugar */ |
| |
| elemexpr_list : |
| | /* empty */ { fun c -> [] } |
| | elemexpr elemexpr_list { fun c -> $1 c :: $2 c } |
| |
| elemidx_list : |
| | idx_list |
| { let f = function {at; _} as x -> [ref_func x @@@ at] @@@ at in |
| fun c -> List.map f ($1 c func) } |
| |
| elem_list : |
| | elemkind elemidx_list |
| { fun c -> $1, $2 c } |
| | reftype elemexpr_list |
| { fun c -> $1 c, $2 c } |
| |
| elem : |
| | LPAR ELEM bindidx_opt elem_list RPAR |
| { fun c -> ignore ($3 c anon_elem bind_elem); |
| fun () -> let rt, cs = $4 c in |
| Elem (rt, cs, Passive @@ $sloc) @@ $sloc } |
| | LPAR ELEM bindidx_opt tableuse offset elem_list RPAR |
| { fun c -> ignore ($3 c anon_elem bind_elem); |
| fun () -> let rt, cs = $6 c in |
| Elem (rt, cs, Active ($4 c table, $5 c) @@ $sloc) @@ $sloc } |
| | LPAR ELEM bindidx_opt DECLARE elem_list RPAR |
| { fun c -> ignore ($3 c anon_elem bind_elem); |
| fun () -> let rt, cs = $5 c in |
| Elem (rt, cs, Declarative @@ $sloc) @@ $sloc } |
| | LPAR ELEM bindidx_opt offset elem_list RPAR /* Sugar */ |
| { fun c -> ignore ($3 c anon_elem bind_elem); |
| fun () -> let rt, cs = $5 c in |
| Elem (rt, cs, Active (0l @@ $sloc, $4 c) @@ $sloc) @@ $sloc } |
| | LPAR ELEM bindidx_opt offset elemidx_list RPAR /* Sugar */ |
| { fun c -> ignore ($3 c anon_elem bind_elem); |
| fun () -> |
| let rt = (NoNull, FuncHT) in |
| Elem (rt, $5 c, Active (0l @@ $sloc, $4 c) @@ $sloc) @@ $sloc } |
| |
| |
| tableuse : |
| | LPAR TABLE idx RPAR { fun c -> $3 c } |
| |
| table : |
| | LPAR TABLE bindidx_opt table_fields RPAR |
| { fun c -> let x = $3 c anon_table bind_table @@ $sloc in |
| fun () -> $4 c x $sloc } |
| |
| table_fields : |
| | tabletype constexpr1 |
| { fun c x loc -> [Table ($1 c, $2 c) @@ loc], [], [], [] } |
| | tabletype /* Sugar */ |
| { fun c x loc -> let TableT (_, _, (_, ht)) as tt = $1 c in |
| [Table (tt, [RefNull ht @@ loc] @@ loc) @@ loc], [], [], [] } |
| | inline_import tabletype /* Sugar */ |
| { fun c x loc -> |
| [], [], |
| [Import (fst $1, snd $1, ExternTableT ($2 c)) @@ loc], [] } |
| | inline_export table_fields /* Sugar */ |
| { fun c x loc -> let tabs, elems, ims, exs = $2 c x loc in |
| tabs, elems, ims, $1 (TableX x) c :: exs } |
| | addrtype reftype LPAR ELEM elemexpr elemexpr_list RPAR /* Sugar */ |
| { fun c x loc -> |
| let offset = [at_const $1 (0L @@ loc) @@ loc] @@ loc in |
| let einit = $5 c :: $6 c in |
| let size = Lib.List64.length einit in |
| let (_, ht) as rt = $2 c in |
| let tinit = [RefNull ht @@ loc] @@ loc in |
| [Table (TableT ($1, {min = size; max = Some size}, rt), tinit) @@ loc], |
| [Elem (rt, einit, Active (x, offset) @@ loc) @@ loc], |
| [], [] } |
| | addrtype reftype LPAR ELEM elemidx_list RPAR /* Sugar */ |
| { fun c x loc -> |
| let (_, ht) as rt = $2 c in |
| let tinit = [RefNull ht @@ loc] @@ loc in |
| let offset = [at_const $1 (0L @@ loc) @@ loc] @@ loc in |
| let einit = $5 c in |
| let size = Lib.List64.length einit in |
| [Table (TableT ($1, {min = size; max = Some size}, rt), tinit) @@ loc], |
| [Elem (rt, einit, Active (x, offset) @@ loc) @@ loc], |
| [], [] } |
| |
| |
| /* Imports & Exports */ |
| |
| externtype : |
| | LPAR FUNC bindidx_opt typeuse RPAR |
| { fun c -> ignore ($3 c anon_func bind_func); |
| fun () -> ExternFuncT (Idx ($4 c).it) } |
| | LPAR TAG bindidx_opt typeuse RPAR |
| { fun c -> ignore ($3 c anon_tag bind_tag); |
| fun () -> ExternTagT (TagT (Idx ($4 c).it)) } |
| | LPAR TAG bindidx_opt functype RPAR /* Sugar */ |
| { fun c -> ignore ($3 c anon_tag bind_tag); |
| fun () -> ExternTagT (TagT (Idx (inline_functype c ($4 c) $loc($4)).it)) } |
| | LPAR GLOBAL bindidx_opt globaltype RPAR |
| { fun c -> ignore ($3 c anon_global bind_global); |
| fun () -> ExternGlobalT ($4 c) } |
| | LPAR MEMORY bindidx_opt memorytype RPAR |
| { fun c -> ignore ($3 c anon_memory bind_memory); |
| fun () -> ExternMemoryT ($4 c) } |
| | LPAR TABLE bindidx_opt tabletype RPAR |
| { fun c -> ignore ($3 c anon_table bind_table); |
| fun () -> ExternTableT ($4 c) } |
| | LPAR FUNC bindidx_opt functype RPAR /* Sugar */ |
| { fun c -> ignore ($3 c anon_func bind_func); |
| fun () -> ExternFuncT (Idx (inline_functype c ($4 c) $loc($4)).it) } |
| |
| import : |
| | LPAR IMPORT name name externtype RPAR |
| { fun c -> let df = $5 c in |
| fun () -> Import ($3, $4, df ()) @@ $sloc } |
| |
| inline_import : |
| | LPAR IMPORT name name RPAR { $3, $4 } |
| |
| externidx : |
| | LPAR TAG idx RPAR { fun c -> TagX ($3 c tag) } |
| | LPAR GLOBAL idx RPAR { fun c -> GlobalX ($3 c global) } |
| | LPAR MEMORY idx RPAR { fun c -> MemoryX ($3 c memory) } |
| | LPAR TABLE idx RPAR { fun c -> TableX ($3 c table) } |
| | LPAR FUNC idx RPAR { fun c -> FuncX ($3 c func) } |
| |
| export : |
| | LPAR EXPORT name externidx RPAR |
| { fun c -> Export ($3, $4 c @@ $loc($4)) @@ $sloc } |
| |
| inline_export : |
| | LPAR EXPORT name RPAR |
| { fun d c -> Export ($3, d @@ $sloc) @@ $sloc } |
| |
| |
| /* Modules */ |
| |
| type_def : |
| | LPAR TYPE subtype RPAR |
| { fun c -> let x = anon_type c $sloc in fun () -> $3 c x } |
| | LPAR TYPE bindidx subtype RPAR /* Sugar */ |
| { fun c -> let x = bind_type c $3 in fun () -> $4 c x } |
| |
| type_def_list : |
| | /* empty */ { fun c () -> [] } |
| | type_def type_def_list |
| { fun c -> let tf = $1 c in let tsf = $2 c in fun () -> |
| let st = tf () and sts = tsf () in st::sts } |
| |
| rectype : |
| | type_def |
| { fun c -> let tf = $1 c in fun () -> |
| let st = tf () in |
| define_deftype c (DefT (RecT [st], 0l)); |
| RecT [st] } |
| | LPAR REC type_def_list RPAR |
| { fun c -> let tf = $3 c in fun () -> |
| let sts = tf () in |
| Lib.List32.iteri (fun i _ -> define_deftype c (DefT (RecT sts, i))) sts; |
| RecT sts } |
| |
| type_ : |
| | rectype |
| { fun c -> let tf = $1 c in fun () -> define_type c (tf () @@ $sloc) } |
| |
| start : |
| | LPAR START idx RPAR |
| { fun c -> Start ($3 c func) @@ $sloc } |
| |
| module_fields : |
| | /* empty */ |
| { fun (c : context) () () -> {empty_module with types = c.types.list} } |
| | module_fields1 { $1 } |
| |
| module_fields1 : |
| | type_ module_fields |
| { fun c -> let tf = $1 c in let mff = $2 c in |
| fun () -> tf (); mff () } |
| | tag module_fields |
| { fun c -> let ef = $1 c in let mff = $2 c in |
| fun () -> let mf = mff () in |
| fun () -> let tags, ims, exs = ef () in let m = mf () in |
| if tags <> [] && m.imports <> [] then |
| error (List.hd m.imports).at "import after tag definition"; |
| { m with tags = tags @ m.tags; |
| imports = ims @ m.imports; exports = exs @ m.exports } } |
| | global module_fields |
| { fun c -> let gf = $1 c in let mff = $2 c in |
| fun () -> let mf = mff () in |
| fun () -> let globs, ims, exs = gf () in let m = mf () in |
| if globs <> [] && m.imports <> [] then |
| error (List.hd m.imports).at "import after global definition"; |
| { m with globals = globs @ m.globals; |
| imports = ims @ m.imports; exports = exs @ m.exports } } |
| | memory module_fields |
| { fun c -> let mmf = $1 c in let mff = $2 c in |
| fun () -> let mf = mff () in |
| fun () -> let mems, data, ims, exs = mmf () in let m = mf () in |
| if mems <> [] && m.imports <> [] then |
| error (List.hd m.imports).at "import after memory definition"; |
| { m with memories = mems @ m.memories; datas = data @ m.datas; |
| imports = ims @ m.imports; exports = exs @ m.exports } } |
| | table module_fields |
| { fun c -> let tf = $1 c in let mff = $2 c in |
| fun () -> let mf = mff () in |
| fun () -> let tabs, elems, ims, exs = tf () in let m = mf () in |
| if tabs <> [] && m.imports <> [] then |
| error (List.hd m.imports).at "import after table definition"; |
| { m with tables = tabs @ m.tables; elems = elems @ m.elems; |
| imports = ims @ m.imports; exports = exs @ m.exports } } |
| | func module_fields |
| { fun c -> let ff = $1 c in let mff = $2 c in |
| fun () -> let mf = mff () in |
| fun () -> let funcs, ims, exs = ff () in let m = mf () in |
| if funcs <> [] && m.imports <> [] then |
| error (List.hd m.imports).at "import after function definition"; |
| { m with funcs = funcs @ m.funcs; |
| imports = ims @ m.imports; exports = exs @ m.exports } } |
| | data module_fields |
| { fun c -> let df = $1 c in let mff = $2 c in |
| fun () -> let mf = mff () in |
| fun () -> let data = df () in let m = mf () in |
| {m with datas = data :: m.Ast.datas} } |
| | elem module_fields |
| { fun c -> let ef = $1 c in let mff = $2 c in |
| fun () -> let mf = mff () in |
| fun () -> let elems = ef () in let m = mf () in |
| {m with elems = elems :: m.Ast.elems} } |
| | start module_fields |
| { fun c -> let mff = $2 c in |
| fun () -> let mf = mff () in |
| fun () -> let m = mf () in |
| let x = $1 c in |
| match m.start with |
| | Some _ -> error x.at "multiple start sections" |
| | None -> {m with start = Some x} } |
| | import module_fields |
| { fun c -> let imf = $1 c in let mff = $2 c in |
| fun () -> let mf = mff () in |
| fun () -> let im = imf () in let m = mf () in |
| {m with imports = im :: m.imports} } |
| | export module_fields |
| { fun c -> let mff = $2 c in |
| fun () -> let mf = mff () in |
| fun () -> let m = mf () in |
| {m with exports = $1 c :: m.exports} } |
| |
| module_var : |
| | VAR { var $1 $sloc } /* Sugar */ |
| |
| module_ : |
| | LPAR MODULE option(module_var) module_fields RPAR |
| { let m = $4 (empty_context ()) () () @@ $sloc in |
| $3, Textual (m, parse_annots m) @@ $sloc } |
| |
| inline_module : /* Sugar */ |
| | module_fields |
| { let m = $1 (empty_context ()) () () @@ $sloc in |
| (* Hack to handle annotations before first and after last token *) |
| let all = all_region (at $sloc).left.file in |
| Textual (m, parse_annots Source.(m.it @@ all)) @@ $sloc } |
| |
| inline_module1 : /* Sugar */ |
| | module_fields1 |
| { let m = $1 (empty_context ()) () () @@ $sloc in |
| (* Hack to handle annotations before first and after last token *) |
| let all = all_region (at $sloc).left.file in |
| Textual (m, parse_annots Source.(m.it @@ all)) @@ $sloc } |
| |
| |
| /* Scripts */ |
| |
| script_var : |
| | VAR { var $1 $sloc } /* Sugar */ |
| |
| instance_var : |
| | VAR { var $1 $sloc } /* Sugar */ |
| |
| definition_opt : |
| | DEFINITION { true } |
| | /* empty */ { false } |
| |
| script_module : |
| | LPAR MODULE definition_opt option(module_var) module_fields RPAR |
| { let m = $5 (empty_context ()) () () @@ $sloc in |
| $3, $4, Textual (m, parse_annots m) @@ $sloc } |
| | LPAR MODULE definition_opt option(module_var) BIN string_list RPAR |
| { let s = $6 @@ $loc($5) in |
| $3, $4, Encoded ("binary:" ^ string_of_loc (at $sloc).left, s) @@ $sloc } |
| | LPAR MODULE definition_opt option(module_var) QUOTE string_list RPAR |
| { let s = $6 @@ $loc($5) in |
| $3, $4, Quoted ("quote:" ^ string_of_loc (at $sloc).left, s) @@ $sloc } |
| |
| script_instance : |
| | instance { [], $1 } |
| | script_module /* sugar */ |
| { let isdef, var_opt, m = $1 in |
| if isdef then error (at $sloc) "misplaced module definition"; |
| [Module (None, m) @@ $sloc], (var_opt, None) } |
| |
| instance : |
| | LPAR MODULE INSTANCE instance_var module_var RPAR |
| { Some $4, Some $5 } |
| | LPAR MODULE INSTANCE module_var RPAR |
| { None, Some $4 } |
| | LPAR MODULE INSTANCE RPAR |
| { None, None } |
| |
| action : |
| | LPAR INVOKE option(instance_var) name list(literal) RPAR |
| { Invoke ($3, $4, $5) @@ $sloc } |
| | LPAR GET option(instance_var) name RPAR |
| { Get ($3, $4) @@ $sloc } |
| |
| assertion : |
| | LPAR ASSERT_MALFORMED script_module STRING RPAR |
| { [], AssertMalformed (thd $3, $4) @@ $sloc } |
| | LPAR ASSERT_INVALID script_module STRING RPAR |
| { [], AssertInvalid (thd $3, $4) @@ $sloc } |
| | LPAR ASSERT_MALFORMED_CUSTOM script_module STRING RPAR |
| { [], AssertMalformedCustom (thd $3, $4) @@ $sloc } |
| | LPAR ASSERT_INVALID_CUSTOM script_module STRING RPAR |
| { [], AssertInvalidCustom (thd $3, $4) @@ $sloc } |
| | LPAR ASSERT_UNLINKABLE script_instance STRING RPAR |
| { fst $3, AssertUnlinkable (snd (snd $3), $4) @@ $sloc } |
| | LPAR ASSERT_TRAP script_instance STRING RPAR |
| { fst $3, AssertUninstantiable (snd (snd $3), $4) @@ $sloc } |
| | LPAR ASSERT_RETURN action list(result) RPAR |
| { [], AssertReturn ($3, $4) @@ $sloc } |
| | LPAR ASSERT_EXCEPTION action RPAR |
| { [], AssertException $3 @@ $sloc } |
| | LPAR ASSERT_TRAP action STRING RPAR |
| { [], AssertTrap ($3, $4) @@ $sloc } |
| | LPAR ASSERT_EXHAUSTION action STRING RPAR |
| { [], AssertExhaustion ($3, $4) @@ $sloc } |
| |
| cmd : |
| | action { [Action $1 @@ $sloc] } |
| | assertion { fst $1 @ [Assertion (snd $1) @@ $sloc] } |
| | script_module |
| { let isdef, var_opt, m = $1 in |
| if isdef then |
| [Module (var_opt, m) @@ $sloc] |
| else (* sugar *) |
| [Module (var_opt, m) @@ $sloc; Instance (var_opt, var_opt) @@ $sloc] } |
| | instance { [Instance (fst $1, snd $1) @@ $sloc] } |
| | LPAR REGISTER name option(instance_var) RPAR { [Register ($3, $4) @@ $sloc] } |
| | meta { [Meta $1 @@ $sloc] } |
| |
| meta : |
| | LPAR SCRIPT option(script_var) list(cmd) RPAR { Script ($3, List.concat $4) @@ $sloc } |
| | LPAR INPUT option(script_var) STRING RPAR { Input ($3, $4) @@ $sloc } |
| | LPAR OUTPUT option(script_var) STRING RPAR { Output ($3, Some $4) @@ $sloc } |
| | LPAR OUTPUT option(script_var) RPAR { Output ($3, None) @@ $sloc } |
| |
| literal_num : |
| | LPAR CONST num RPAR { snd (num $2 $3) } |
| |
| literal_vec : |
| | LPAR VEC_CONST VECSHAPE list(num) RPAR { snd (vec $2 $3 $4 $sloc) } |
| |
| literal_ref : |
| | LPAR REF_NULL heaptype RPAR { Value.NullRef ($3 (empty_context ())) } |
| | LPAR REF_HOST NAT RPAR { Script.HostRef (nat32 $3 $loc($3)) } |
| | LPAR REF_EXTERN NAT RPAR { Extern.ExternRef (Script.HostRef (nat32 $3 $loc($3))) } |
| |
| literal : |
| | literal_num { Value.Num $1 @@ $sloc } |
| | literal_vec { Value.Vec $1 @@ $sloc } |
| | literal_ref { Value.Ref $1 @@ $sloc } |
| |
| numpat : |
| | num { fun sh -> vec_lane_lit sh $1.it $1.at } |
| | NAN { fun sh -> vec_lane_nan sh $1 (at $sloc) } |
| |
| result : |
| | literal_num { NumResult (NumPat ($1 @@ $sloc)) @@ $sloc } |
| | LPAR CONST NAN RPAR { NumResult (NanPat (nanop $2 ($3 @@ $loc($3)))) @@ $sloc } |
| | literal_ref { RefResult (RefPat ($1 @@ $sloc)) @@ $sloc } |
| | LPAR REF RPAR { RefResult (RefTypePat AnyHT) @@ $sloc } |
| | LPAR REF_EQ RPAR { RefResult (RefTypePat EqHT) @@ $sloc } |
| | LPAR REF_I31 RPAR { RefResult (RefTypePat I31HT) @@ $sloc } |
| | LPAR REF_STRUCT RPAR { RefResult (RefTypePat StructHT) @@ $sloc } |
| | LPAR REF_ARRAY RPAR { RefResult (RefTypePat ArrayHT) @@ $sloc } |
| | LPAR REF_FUNC RPAR { RefResult (RefTypePat FuncHT) @@ $sloc } |
| | LPAR REF_EXN RPAR { RefResult (RefTypePat ExnHT) @@ $sloc } |
| | LPAR REF_EXTERN RPAR { RefResult (RefTypePat ExternHT) @@ $sloc } |
| | LPAR REF_NULL RPAR { RefResult NullPat @@ $sloc } |
| | LPAR VEC_CONST VECSHAPE list(numpat) RPAR |
| { if V128.num_lanes $3 <> List.length $4 then |
| error (at $sloc) "wrong number of lane literals"; |
| VecResult (VecPat |
| (Value.V128 ($3, List.map (fun lit -> lit $3) $4))) @@ $sloc } |
| | LPAR EITHER result list(result) RPAR { EitherResult ($3 :: $4) @@ $sloc } |
| |
| script : |
| | list(cmd) EOF { List.concat $1 } |
| | inline_module1 EOF { [Module (None, $1) @@ $sloc] } /* Sugar */ |
| |
| script1 : |
| | cmd { $1 } |
| |
| module1 : |
| | module_ EOF { $1 } |
| | inline_module EOF { None, $1 } /* Sugar */ |
| %% |