AQQ7DH2OU4OKCVRQECS427ICA4OAT5NLQBE4TLKFBJ3TAUMQHXKAC QOY4V3F5WXC4HJ3EP5F4CQ5NYJ6QJF6REKTME3RQS7AQT3RMXZ7AC O2DTNJ3ZOJJKDHGPNE2DZSZF7CFU4G5D65RIDOYZHYYBH3JZAAIAC YNPPEQEWMXS4B2EKRR54WUZMXO222YOWC2I5NPXPDG2ABOIBH7RAC ZR7U7TRCUHXMBXQFA3XXNGJPPYFACMOWPQKGUH7E22KGFM35HSNAC 7VZF66GPW6DKQB4FU4PTU3CEE32MTYNP4MH6GY4SMICRERO76WDQC Y7IBP4INTUL42R7TC7O4DXGR27CKTD6VEEL6BHJNGCVIFVUVGCMQC Q62EXKAKNM5FMIW3UZBUAJFKOZLE2O2VIRTJAVDOTTSWX5JSMX4QC XMQU7NVKDFNL5MN2BECGAQI4LXQQX3GCIESGJM54GYDDLBVODLWAC UVNP57VT7S7OSGWK5XXKEBAVZMHDGGPMFGSSCT25GGSK5QFYNMFQC def new() do%__MODULE__{parsers: [s(:magic, bytes(<<0x00, 0x61, 0x73, 0x6D>>)),s(:version, bytes(<<0x01, 0x00, 0x00, 0x00>>)),s(:type_section,section([s(:id, bytes(<<0x01>>)),&u32/1,s(:content, &get_bytes/1)]))]}
def parse(<<0x00, 0x61, 0x73, 0x6D, rest::binary>>) do{:ok, {{:magic, <<0x00, 0x61, 0x73, 0x6D>>}, rest, &parse_version/1}}
def parse_one(chunk, state = %__MODULE__{parsers: [parser | rest_parsers]}) doresults = parser.(chunk)new_state = %{state | parsers: rest_parsers}for result <- results, reduce: {new_state, chunk} do{state, chunk} ->case result do{:add_tag, tag} ->{%{state | tags: [tag | state.tags]}, chunk}{:cont, cont} ->{%{state | parsers: [cont | state.parsers]}, chunk}
{:add_acc, result, tail} ->{%{state | acc: [result | state.acc]}, tail}{:add_acc, result} ->{%{state | acc: [result | state.acc]}, chunk}:keep_result ->[last | acc] = state.acc{new_acc, new_tags} =case state.tags do[tag] -> {[{tag, last} | acc], []}[_tag | rest_tags] = tags -> {[{tags |> Enum.reverse(), last} | acc], rest_tags}end{%{state | tags: new_tags, acc: new_acc}, chunk}{:pop_and_cont, cont} ->[top | acc] = state.acccont = cont.(top){%{state | parsers: [cont | state.parsers], acc: acc}, chunk}{:error, err} ->{%{state | stop: true, acc: [{:error, err} | state.acc]}, chunk}end
defp do_parse_section(id) dofn chunk ->do_parse_section_len(id, chunk)
def parse_all(chunk, state) do{state, tail} = parse_one(chunk, state)if state.stop do{state, tail}elseparse_all(tail, state)end
defp do_parse_section_len(id, <<0::1, _::bitstring>> = chunk) do<<len::binary-size(1), rest::binary>> = chunklength = WaParser.LEB128.decode_unsigned(len){:ok, {{:section_length, length}, rest, parse_section_body(id, length)}}
def get_results({state, chunk}) do{state.acc |> Enum.reverse(), state, chunk}enddefp s(name, cont) dofn _chunk ->[{:add_tag, name},{:cont, &keep_result/1},{:cont, cont}]endenddefp keep_result(_chunk) do[:keep_result]enddef bytes(expected) doexpected_size = :erlang.size(expected)
defp parse_section_body(id, length) do
case chunk do<<^expected::binary-size(expected_size), rest::binary>> = ^chunk ->[{:add_acc, expected, rest}]_ ->[{:error, :not_matched}]end
do_parse_section_body(id, length, chunk)
def section([]) dofn _chunk ->[{:add_acc, :section_end}]endenddef section(parts) when is_list(parts) do[next | rest] = partsfn _chunk ->[{:cont, section(rest)},{:cont, next}]end
defp do_parse_section_body(_id, len, chunk) do<<section::binary-size(len), rest::binary>> = chunk{:ok, {{:section_body, section}, rest, &parse_section/1}}
defp read_bytes(count) dofn <<bytes::binary-size(count), rest::binary>> ->[{:add_acc, bytes, rest}]
defp parse_reducer(data, parser) docase parser.(data) do{:ok, {result, rest, next}} ->IO.inspect(result)parse_reducer(rest, next)