diff --git a/src/internal/binary/types.gleam b/src/internal/binary/types.gleam index c9b6ae2..bc43865 100644 --- a/src/internal/binary/types.gleam +++ b/src/internal/binary/types.gleam @@ -613,7 +613,7 @@ pub fn decode_sub_type(bits: BitArray) { /// and a single composite type. /// 3. A single composite type that is *FINAL* pub fn encode_sub_type(builder: BytesBuilder, sub_type: SubType) { - case sub_type.final, sub_type.type_idxs { + case sub_type.final, sub_type.match_idxs { True, [] -> builder |> encode_composite_type(sub_type.composite_type) True, match_idxs -> { use builder <- result.try( diff --git a/src/internal/structure/types.gleam b/src/internal/structure/types.gleam index 4425af5..661aaa8 100644 --- a/src/internal/structure/types.gleam +++ b/src/internal/structure/types.gleam @@ -7,75 +7,75 @@ import internal/structure/numbers.{ } /// Get the lane_16 indx nvalue as an integer -pub fn unwrap_lane_16(val: LaneIDX16) { - val.val +pub fn unwrap_lane_16(lane_idx: LaneIDX16) { + lane_idx.lane } /// Create a lane index that indexes 16 lanes -pub fn lane_16(val: Int) { - case val |> between(#(0, 15)) { - True -> Ok(LaneIDX16(val)) +pub fn lane_16(lane: Int) { + case lane |> between(#(0, 15)) { + True -> Ok(LaneIDX16(lane)) _ -> Error("Lane index out of range") } } /// This type is used to describe lane indexes with a range of [0, 15] pub opaque type LaneIDX16 { - LaneIDX16(val: Int) + LaneIDX16(lane: Int) } /// Get the lane_2 index value as an integer -pub fn unwrap_lane_2(val: LaneIDX2) { - val.val +pub fn unwrap_lane_2(lane_idx: LaneIDX2) { + lane_idx.lane } /// Create a lane index that indexes 2 lanes -pub fn lane_2(val: Int) { - case val |> between(#(0, 1)) { - True -> Ok(LaneIDX2(val)) +pub fn lane_2(lane: Int) { + case lane |> between(#(0, 1)) { + True -> Ok(LaneIDX2(lane)) _ -> Error("Lane index out of range") } } /// This type is used to describe lane indexes with a range of [0, 1] pub opaque type LaneIDX2 { - LaneIDX2(val: Int) + LaneIDX2(lane: Int) } /// Get the lane_4 index value as an integer -pub fn unwrap_lane_4(val: LaneIDX4) { - val.val +pub fn unwrap_lane_4(lane_idx: LaneIDX4) { + lane_idx.lane } /// Create a lane index that indexes 4 lanes -pub fn lane_4(val: Int) { - case val |> between(#(0, 3)) { - True -> Ok(LaneIDX4(val)) +pub fn lane_4(lane: Int) { + case lane |> between(#(0, 3)) { + True -> Ok(LaneIDX4(lane)) _ -> Error("Lane index out of range") } } /// This type is used to describe lane indexes with a range of [0, 3] pub opaque type LaneIDX4 { - LaneIDX4(val: Int) + LaneIDX4(lane: Int) } /// Get the lane_8 index value as an integer -pub fn unwrap_lane_8(val: LaneIDX8) { - val.val +pub fn unwrap_lane_8(lane_idx: LaneIDX8) { + lane_idx.lane } /// Create a lane index that indexes 8 lanes -pub fn lane_8(val: Int) { - case val |> between(#(0, 7)) { - True -> Ok(LaneIDX8(val)) +pub fn lane_8(lane: Int) { + case lane |> between(#(0, 7)) { + True -> Ok(LaneIDX8(lane)) _ -> Error("Lane index out of range") } } /// This type is used to describe lane indexes with a range of [0, 7] pub opaque type LaneIDX8 { - LaneIDX8(val: Int) + LaneIDX8(lane: Int) } /// Please see: https://webassembly.github.io/gc/core/syntax/types.html#heap-types @@ -291,7 +291,7 @@ pub type MemIDX { /// also an array of matching subtype indexes that the type matches. /// Please see: https://webassembly.github.io/gc/core/syntax/types.html#recursive-types pub type SubType { - SubType(final: Bool, type_idxs: List(TypeIDX), composite_type: CompositeType) + SubType(final: Bool, match_idxs: List(TypeIDX), composite_type: CompositeType) } /// A definition of a limit range, which has a minimum, and an optional maximum which defaults diff --git a/src/internal/validation/common.gleam b/src/internal/validation/common.gleam index b0b62f8..cb01c1e 100644 --- a/src/internal/validation/common.gleam +++ b/src/internal/validation/common.gleam @@ -1,25 +1,90 @@ -import gleam/dict.{type Dict} -import gleam/list -import internal/structure/numbers.{type U32} +import gleam/int +import gleamy/red_black_tree_map.{type Map} +import internal/structure/numbers import internal/structure/types.{ - type Data, type DefType, type Elem, type FuncIDX, type GlobalType, type Locals, - type MemType, type RecType, type TableType, type ValType, + type DefType, type RecType, type SubType, type TypeIDX, DefType, TypeIDX, +} +import shine_tree.{type ShineTree} + +pub type TypeEntry { + TypeEntry( + type_idx: Int, + def_type: DefType, + rec_type: RecType, + sub_type: SubType, + rec_type_idx: Int, + ) } pub type Context { - Context(types: List(DefType)) + Context(types_length: Int, types: Map(TypeIDX, TypeEntry)) } -pub const empty_context = Context(types: []) +fn compare_type_idx(type_idx_a: TypeIDX, type_idx_b: TypeIDX) { + let TypeIDX(type_idx_a) = type_idx_a + let TypeIDX(type_idx_b) = type_idx_b + let type_idx_a = numbers.unwrap_u32(type_idx_a) + let type_idx_b = numbers.unwrap_u32(type_idx_b) + int.compare(type_idx_a, type_idx_b) +} -pub fn get_def_type(ctx: Context, idx: U32) { - let idx = numbers.unwrap_u32(idx) - case list.drop(ctx.types, idx) { - [def_type, ..] -> Ok(def_type) - _ -> Error("Invalid TypeIDX") +pub fn new_context(rec_types: List(RecType)) { + do_new_context( + rec_types, + 0, + Context(0, red_black_tree_map.new(compare_type_idx)), + ) +} + +fn do_new_context(rec_types: List(RecType), type_idx: Int, acc: Context) { + case rec_types { + [] -> acc + [rec_type, ..rec_types] -> + do_new_sub_types( + rec_type.sub_types, + rec_type, + rec_types, + type_idx, + 0, + acc, + ) } } -pub fn roll_rec_type(ctx: Context, rec_type: RecType) { - todo +fn do_new_sub_types( + sub_types: List(SubType), + rec_type: RecType, + rec_types: List(RecType), + type_idx: Int, + rec_type_idx: Int, + acc: Context, +) { + case sub_types { + [] -> do_new_context(rec_types, type_idx, acc) + [sub_type, ..sub_types] -> { + let assert Ok(type_idx_key) = numbers.u32(type_idx) + + do_new_sub_types( + sub_types, + rec_type, + rec_types, + type_idx + 1, + rec_type_idx + 1, + Context( + types_length: acc.types_length + 1, + types: red_black_tree_map.insert( + acc.types, + TypeIDX(type_idx_key), + TypeEntry( + type_idx, + DefType(rec_type, rec_type_idx), + rec_type, + sub_type, + rec_type_idx, + ), + ), + ), + ) + } + } } diff --git a/src/internal/validation/match.gleam b/src/internal/validation/match.gleam index ab0b26a..d5505a1 100644 --- a/src/internal/validation/match.gleam +++ b/src/internal/validation/match.gleam @@ -1,17 +1,19 @@ +import gleam/list.{Continue, Stop} +import gleamy/red_black_tree_map as map +import internal/structure/numbers import internal/structure/types.{ type ArrayType, type CompositeType, type DefType, type FieldType, type FuncType, type HeapType, type RefType, type StorageType, type StructType, - type ValType, AnyHeapType, AnyRefType, ArrayCompositeType, ArrayHeapType, - ArrayRefType, ArrayType, BotHeapType, BotValType, ConcreteHeapType, Const, - EqHeapType, EqRefType, ExternHeapType, ExternRefType, FieldType, - FuncCompositeType, FuncHeapType, FuncRefType, FuncType, HeapTypeRefType, - I31HeapType, I31RefType, NoExternHeapType, NoExternRefType, NoFuncHeapType, - NoFuncRefType, NoneHeapType, NoneRefType, RefTypeValType, StructCompositeType, - StructHeapType, StructRefType, StructType, SubType, TypeIDX, - ValTypeStorageType, Var, + type TypeIDX, type ValType, AnyHeapType, AnyRefType, ArrayCompositeType, + ArrayHeapType, ArrayRefType, ArrayType, BotHeapType, BotValType, + ConcreteHeapType, Const, EqHeapType, EqRefType, ExternHeapType, ExternRefType, + FieldType, FuncCompositeType, FuncHeapType, FuncRefType, FuncType, + HeapTypeRefType, I31HeapType, I31RefType, NoExternHeapType, NoExternRefType, + NoFuncHeapType, NoFuncRefType, NoneHeapType, NoneRefType, RefTypeValType, + StructCompositeType, StructHeapType, StructRefType, StructType, SubType, + TypeIDX, ValTypeStorageType, Var, } - -import internal/validation/common.{type Context} +import internal/validation/common.{type Context, TypeEntry} pub fn matches_val_type(ctx: Context, val_type_1: ValType, val_type_2: ValType) { case val_type_1, val_type_2 { @@ -55,51 +57,34 @@ pub fn matches_heap_type( heap_type_2: HeapType, ) { case heap_type_1, heap_type_2 { + // Either both heaptype1 and heaptype2 are the same. heap_type_1, heap_type_2 if heap_type_1 == heap_type_2 -> True + ConcreteHeapType(type_idx_1), ConcreteHeapType(type_idx_2) -> + match_heap_type_idxs(ctx, type_idx_1, type_idx_2) + ConcreteHeapType(type_idx), heap_type_2 -> + match_type_idx_to_heap_type(ctx, type_idx, heap_type_2) + heap_type_1, ConcreteHeapType(type_idx) -> + match_heap_type_to_type_idx(ctx, heap_type_1, type_idx) + + // Or heaptype1 is bot. BotHeapType, _ - | EqHeapType, AnyHeapType - | I31HeapType, EqHeapType + | // Or heaptype1 is eq and heaptype2 is any + EqHeapType, + AnyHeapType + | // Or heaptype1 is one of i31, struct, or array and heaptype2 is eq. + I31HeapType, + EqHeapType | StructHeapType, EqHeapType | ArrayHeapType, EqHeapType -> True - - // TODO: Fix how type indices are matched - // ConcreteHeapType(DefTypeReference(def_type_1)), - // ConcreteHeapType(DefTypeReference(def_type_2)) - // -> matches_def_type(ctx, def_type_1, def_type_2) - // ConcreteHeapType(DefTypeReference(def_type)), heap_type_2 -> { - // case types.def_type_expand(def_type), heap_type_2 { - // Ok(FuncCompositeType(_)), FuncHeapType - // | Ok(StructCompositeType(_)), StructHeapType - // | Ok(ArrayCompositeType(_)), ArrayHeapType - // -> True - // _, _ -> False - // } - // } - // ConcreteHeapType(TypeIDX(idx)), heap_type_2 -> - // case common.get_def_type(ctx, idx) { - // Ok(def_type) -> - // matches_heap_type( - // ctx, - // ConcreteHeapType(DefTypeReference(def_type)), - // heap_type_2, - // ) - // _ -> False - // } - // heap_type_1, ConcreteHeapType(TypeIDX(idx)) -> - // case common.get_def_type(ctx, idx) { - // Ok(def_type) -> - // matches_heap_type( - // ctx, - // heap_type_1, - // ConcreteHeapType(DefTypeReference(def_type)), - // ) - // _ -> False - // } NoneHeapType, heap_type_2 -> matches_heap_type(ctx, heap_type_2, AnyHeapType) + + // Or heaptype1 is nofunc and heaptype2 matches func. NoFuncHeapType, heap_type_2 -> matches_heap_type(ctx, heap_type_2, FuncHeapType) + + // Or heaptype1 is noextern and heaptype2 matches extern. NoExternHeapType, heap_type_2 -> matches_heap_type(ctx, heap_type_2, ExternHeapType) @@ -109,6 +94,49 @@ pub fn matches_heap_type( } } +fn match_type_idx_to_heap_type( + ctx: Context, + type_idx: TypeIDX, + heap_type: HeapType, +) { + case ctx.types |> map.find(type_idx) { + Ok(TypeEntry(_, _, _, SubType(_, _, composite_type), _)) -> + case composite_type, heap_type { + FuncCompositeType(_), FuncHeapType + | ArrayCompositeType(_), ArrayHeapType + | StructCompositeType(_), StructHeapType + -> True + _, _ -> False + } + _ -> False + } +} + +// TODO: How to compare heap types to def_types +fn match_heap_type_to_type_idx( + ctx: Context, + heap_type: HeapType, + type_idx: TypeIDX, +) { + case map.find(ctx.types, type_idx) { + Ok(TypeEntry(_, _, _, SubType(_, _, _composite_type), _)) -> False + _ -> False + } +} + +fn match_heap_type_idxs(ctx: Context, type_idx_1: TypeIDX, type_idx_2: TypeIDX) { + // Or there exists a valid heap type heaptype', such that heaptype1 matches heaptype' and heaptype' matches + // heaptype2. + case map.find(ctx.types, type_idx_1) { + Ok(TypeEntry(_, _, _, SubType(_, match_idxs, _), _)) -> { + use type_idx_1 <- list.any(match_idxs) + match_heap_type_idxs(ctx, type_idx_1, type_idx_2) + } + + _ -> False + } +} + pub fn matches_result_type( ctx: Context, result_type_1: List(ValType), diff --git a/test/decode_test.gleam b/test/decode_test.gleam index 9575c17..9784c73 100644 --- a/test/decode_test.gleam +++ b/test/decode_test.gleam @@ -450,7 +450,7 @@ fn do_func_idxs_equal( fn sub_type_equals(a: structure_types.SubType, b: structure_types.SubType) { a.final |> should.equal(b.final) - do_type_idxs_equal(a.type_idxs, b.type_idxs) + do_type_idxs_equal(a.match_idxs, b.match_idxs) composite_type_equals(a.composite_type, b.composite_type) }