@@ -199,6 +199,68 @@ let heap_type_sub (ty : W.heap_type) (ty' : W.heap_type) st =
199199 (* I31, struct, array and none have no other subtype *)
200200 | _ , (I31 | Type _ | Struct | Array | None_ ) -> false , st
201201
202+ (* ZZZ*)
203+ let rec type_index_lub ty ty' st =
204+ if Var. equal ty ty'
205+ then Some ty
206+ else
207+ let type_field = Var.Hashtbl. find st.context.types ty in
208+ match type_field.supertype with
209+ | None -> None
210+ | Some ty -> (
211+ match type_index_lub ty ty' st with
212+ | Some ty -> Some ty
213+ | None -> (
214+ let type_field = Var.Hashtbl. find st.context.types ty' in
215+ match type_field.supertype with
216+ | None -> None
217+ | Some ty' -> type_index_lub ty ty' st))
218+
219+ let heap_type_lub (ty : W.heap_type ) (ty' : W.heap_type ) =
220+ match ty, ty' with
221+ | (Func | Extern ), _ | _ , (Func | Extern ) -> assert false
222+ | None_ , _ -> return ty'
223+ | _ , None_ | Struct , Struct | Array , Array -> return ty
224+ | Any , _ | _ , Any -> return W. Any
225+ | Eq , _
226+ | _, Eq
227+ | (Struct | Array | Type _), I31
228+ | I31 , (Struct | Array | Type _)
229+ | Struct , Array
230+ | Array , Struct -> return (Eq : W.heap_type )
231+ | Struct , Type t | Type t , Struct -> (
232+ fun st ->
233+ let type_field = Var.Hashtbl. find st.context.types t in
234+ match type_field.typ with
235+ | Struct _ -> W. Struct , st
236+ | Array _ | Func _ -> W. Eq , st)
237+ | Array , Type t | Type t , Array -> (
238+ fun st ->
239+ let type_field = Var.Hashtbl. find st.context.types t in
240+ match type_field.typ with
241+ | Array _ -> W. Struct , st
242+ | Struct _ | Func _ -> W. Eq , st)
243+ | Type t , Type t' -> (
244+ let * r = fun st -> type_index_lub t t' st, st in
245+ match r with
246+ | Some t'' -> return (Type t'' : W.heap_type )
247+ | None -> (
248+ fun st ->
249+ let type_field = Var.Hashtbl. find st.context.types t in
250+ let type_field' = Var.Hashtbl. find st.context.types t' in
251+ match type_field.typ, type_field'.typ with
252+ | Struct _ , Struct _ -> (Struct : W.heap_type ), st
253+ | Array _ , Array _ -> W. Array , st
254+ | (Array _ | Struct _ | Func _ ), (Array _ | Struct _ | Func _ ) -> W. Eq , st))
255+ | I31 , I31 -> return W. I31
256+
257+ let value_type_lub (ty : W.value_type ) (ty' : W.value_type ) =
258+ match ty, ty' with
259+ | Ref { nullable; typ } , Ref { nullable = nullable' ; typ = typ' } ->
260+ let * typ = heap_type_lub typ typ' in
261+ return (W. Ref { nullable = nullable || nullable'; typ })
262+ | _ -> assert false
263+
202264let register_global name ?exported_name ?(constant = false ) typ init st =
203265 st.context.other_fields < -
204266 W. Global { name; exported_name; typ; init } :: st.context.other_fields;
@@ -703,13 +765,28 @@ let push e =
703765 instr (Push e')
704766 | _ -> instr (Push e)
705767
768+ let blk' ty l st =
769+ let instrs = st.instrs in
770+ let () , st = l { st with instrs = [] } in
771+ let ty, st =
772+ match st.instrs with
773+ | Push e :: _ ->
774+ (let * ty' = expression_type e in
775+ match ty' with
776+ | None -> return ty
777+ | Some ty' -> return { ty with W. result = [ ty' ] })
778+ st
779+ | _ -> ty, st
780+ in
781+ (List. rev st.instrs, ty), { st with instrs }
782+
706783let loop ty l =
707- let * instrs = blk l in
708- instr (Loop (ty, instrs))
784+ let * instrs, ty' = blk' ty l in
785+ instr (Loop (ty' , instrs))
709786
710787let block ty l =
711- let * instrs = blk l in
712- instr (Block (ty, instrs))
788+ let * instrs, ty' = blk' ty l in
789+ instr (Block (ty' , instrs))
713790
714791let block_expr ty l =
715792 let * instrs = blk l in
@@ -782,7 +859,7 @@ let init_code context = instrs context.init_code
782859
783860let function_body ~context ~param_names ~body =
784861 let st = { var_count = 0 ; vars = Var.Map. empty; instrs = [] ; context } in
785- let () , st = body st in
862+ let res , st = body st in
786863 let local_count, body = st.var_count, List. rev st.instrs in
787864 let local_types = Array. make local_count (Var. fresh () , None ) in
788865 List. iteri ~f: (fun i x -> local_types.(i) < - x, None ) param_names;
@@ -800,4 +877,10 @@ let function_body ~context ~param_names ~body =
800877 |> (fun a -> Array. sub a ~pos: param_count ~len: (Array. length a - param_count))
801878 |> Array. to_list
802879 in
803- locals, body
880+ locals, res, body
881+
882+ let eval ~context e =
883+ let st = { var_count = 0 ; vars = Var.Map. empty; instrs = [] ; context } in
884+ let r, st = e st in
885+ assert (st.var_count = 0 && List. is_empty st.instrs);
886+ r
0 commit comments