///|
/// Parsing for component import/export sections (sections 10 and 11).
///
/// This is still a subset: we primarily parse the framing and enough structure
/// to keep index spaces and types wired up for later validation/linking.

///|
pub(all) enum Sort {
  Core(Int) // core:sort opcode (0x00..)
  Func
  Value
  Type
  Component
  Instance
} derive(Debug, Eq)

///|
pub(all) struct SortIdx {
  sort : Sort
  idx : Int
} derive(Debug, Eq)

///|
pub impl Show for SortIdx with fn output(self, logger) {
  logger.write_string(@types.compact_show_repr(Repr(self).to_string()))
}

///|
pub(all) enum TypeBound {
  Eq(Int)
  SubResource
} derive(Debug, Eq)

///|
pub(all) enum ValueBound {
  Eq(Int)
  Type(ValType)
} derive(Debug, Eq)

///|
pub(all) enum ExternDesc {
  CoreModuleType(Int) // core:typeidx (u32)
  FuncType(Int) // typeidx
  Value(ValueBound)
  Type(TypeBound)
  ComponentType(Int) // typeidx
  InstanceType(Int) // typeidx
} derive(Debug, Eq)

///|
pub impl Show for ExternDesc with fn output(self, logger) {
  logger.write_string(@types.compact_show_repr(Repr(self).to_string()))
}

///|
pub(all) enum ImportName {
  Plain(Bytes)
  WithVersion(Bytes, Bytes)
} derive(Debug, Eq)

///|
pub(all) enum ExportName {
  Plain(Bytes)
  WithVersion(Bytes, Bytes)
} derive(Debug, Eq)

///|
pub(all) enum NameAttribute {
  Implements(Bytes)
  VersionSuffix(Bytes)
  ExternalId(Bytes)
} derive(Debug, Eq)

///|
pub(all) struct Import {
  name : ImportName
  attributes : Array[NameAttribute]
  desc : ExternDesc
} derive(Debug, Eq)

///|
pub(all) struct Export {
  name : ExportName
  attributes : Array[NameAttribute]
  sortidx : SortIdx
  desc : ExternDesc?
} derive(Debug, Eq)

///|
fn parse_name_annot(reader : Reader) -> Bytes raise ComponentParseError {
  let len = reader.read_leb_u32()
  reader.read_bytes(len)
}

///|
fn parse_versionsuffix(reader : Reader) -> Bytes raise ComponentParseError {
  let len = reader.read_leb_u32()
  reader.read_bytes(len)
}

///|
fn parse_attribute(reader : Reader) -> NameAttribute raise ComponentParseError {
  let tag = reader.read_u8()
  if tag == 0x00 {
    Implements(parse_name_annot(reader))
  } else if tag == 0x01 {
    VersionSuffix(parse_versionsuffix(reader))
  } else if tag == 0x02 {
    ExternalId(parse_name_annot(reader))
  } else {
    raise InvalidTypeSection
  }
}

///|
fn parse_attributes(
  reader : Reader,
) -> Array[NameAttribute] raise ComponentParseError {
  let count = reader.read_leb_u32()
  let attributes : Array[NameAttribute] = []
  for _ in 0.. (ImportName, Array[NameAttribute]) raise ComponentParseError {
  let tag = reader.read_u8()
  if tag == 0x00 {
    (Plain(parse_name_annot(reader)), [])
  } else if tag == 0x01 {
    (Plain(parse_name_annot(reader)), [])
  } else if tag == 0x02 {
    (Plain(parse_name_annot(reader)), parse_attributes(reader))
  } else {
    raise InvalidTypeSection
  }
}

///|
fn parse_exportname(
  reader : Reader,
) -> (ExportName, Array[NameAttribute]) raise ComponentParseError {
  let tag = reader.read_u8()
  if tag == 0x00 {
    (Plain(parse_name_annot(reader)), [])
  } else if tag == 0x01 {
    (Plain(parse_name_annot(reader)), [])
  } else if tag == 0x02 {
    (Plain(parse_name_annot(reader)), parse_attributes(reader))
  } else {
    raise InvalidTypeSection
  }
}

///|
fn parse_sort(reader : Reader) -> Sort raise ComponentParseError {
  let tag = reader.read_u8()
  if tag == 0x00 {
    let core_sort = reader.read_u8()
    Core(core_sort)
  } else if tag == 0x01 {
    Func
  } else if tag == 0x02 {
    Value
  } else if tag == 0x03 {
    Type
  } else if tag == 0x04 {
    Component
  } else if tag == 0x05 {
    Instance
  } else {
    raise InvalidTypeSection
  }
}

///|
fn parse_sortidx(reader : Reader) -> SortIdx raise ComponentParseError {
  let sort = parse_sort(reader)
  let idx = reader.read_leb_u32()
  { sort, idx, }
}

///|
fn parse_typebound(reader : Reader) -> TypeBound raise ComponentParseError {
  let tag = reader.read_u8()
  if tag == 0x00 {
    Eq(reader.read_typeidx())
  } else if tag == 0x01 {
    SubResource
  } else {
    raise InvalidTypeSection
  }
}

///|
fn parse_valuebound(reader : Reader) -> ValueBound raise ComponentParseError {
  let tag = reader.read_u8()
  if tag == 0x00 {
    Eq(reader.read_leb_u32())
  } else if tag == 0x01 {
    Type(parse_valtype(reader))
  } else {
    raise InvalidTypeSection
  }
}

///|
fn parse_externdesc(reader : Reader) -> ExternDesc raise ComponentParseError {
  let tag = reader.read_u8()
  if tag == 0x00 {
    let must_be_core_module = reader.read_u8()
    if must_be_core_module != 0x11 {
      raise InvalidTypeSection
    }
    CoreModuleType(reader.read_leb_u32())
  } else if tag == 0x01 {
    FuncType(reader.read_typeidx())
  } else if tag == 0x02 {
    Value(parse_valuebound(reader))
  } else if tag == 0x03 {
    Type(parse_typebound(reader))
  } else if tag == 0x04 {
    ComponentType(reader.read_typeidx())
  } else if tag == 0x05 {
    InstanceType(reader.read_typeidx())
  } else {
    raise InvalidTypeSection
  }
}

///|
fn parse_opt_externdesc(
  reader : Reader,
) -> ExternDesc? raise ComponentParseError {
  let tag = reader.read_u8()
  if tag == 0x00 {
    None
  } else if tag == 0x01 {
    Some(parse_externdesc(reader))
  } else {
    raise InvalidTypeSection
  }
}

///|
pub fn parse_import_section(
  payload : Bytes,
) -> Array[Import] raise ComponentParseError {
  let reader = Reader::Reader(payload)
  let n = reader.read_leb_u32()
  let imports : Array[Import] = []
  for _i in 0.. Array[Export] raise ComponentParseError {
  let reader = Reader::Reader(payload)
  let n = reader.read_leb_u32()
  let exports : Array[Export] = []
  for _ in 0..