defmodule WaParserTest do use ExUnit.Case def parse_file(filename) do filename |> File.read!() |> WaParser.stream() |> Enum.to_list() end test "0_return_0" do assert parse_file("test_data/0_return_0.opt.wasm") == [ {:magic, <<0, 97, 115, 109>>}, {:version, <<1, 0, 0, 0>>}, {:section_id, 1}, {:section_type, :type}, {:section_length, 5}, {:section_body, [{[], [:i32]}]}, {:section_id, 3}, {:section_type, :function}, {:section_length, 2}, {:section_body, [0]}, {:section_id, 5}, {:section_type, :memory}, {:section_length, 3}, {:section_body, [{2, nil}]}, {:section_id, 6}, {:section_type, :global}, {:section_length, 14}, {:section_body, [{{:i32, :const}, ["i32.const": 66560]}, {{:i32, :const}, ["i32.const": 1024]}]}, {:section_id, 7}, {:section_type, :export}, {:section_length, 48}, {:section_body, [ {"memory", {:mem, 0}}, {"__heap_base", {:global, 0}}, {"__data_end", {:global, 1}}, {"return_0", {:func, 0}} ]}, {:section_id, 10}, {:section_type, :code}, {:section_length, 6}, {:section_body, [%{code: %{expr: ["i32.const": 0], locals: []}, size: 4}]} ] end test "1_int_identity" do assert parse_file("test_data/1_int_identity.opt.wasm") |> Enum.filter(fn {k, _} -> k == :section_type or k == :section_body end) == [ {:section_type, :type}, {:section_body, [{[:i32], [:i32]}]}, {:section_type, :function}, {:section_body, [0]}, {:section_type, :memory}, {:section_body, [{2, nil}]}, {:section_type, :global}, {:section_body, [{{:i32, :const}, ["i32.const": 66560]}, {{:i32, :const}, ["i32.const": 1024]}]}, {:section_type, :export}, {:section_body, [ {"memory", {:mem, 0}}, {"__heap_base", {:global, 0}}, {"__data_end", {:global, 1}}, {"identity", {:func, 0}} ]}, {:section_type, :code}, {:section_body, [%{code: %{expr: ["local.get": 0], locals: []}, size: 4}]} ] end test "2_int_arithm" do assert parse_file("test_data/2_int_arithm.opt.wasm") |> Enum.filter(fn {k, _} -> k == :section_type or k == :section_body end) == [ {:section_type, :type}, {:section_body, [{[:i32], [:i32]}]}, {:section_type, :function}, {:section_body, [0, 0, 0, 0]}, {:section_type, :memory}, {:section_body, [{2, nil}]}, {:section_type, :global}, {:section_body, [{{:i32, :const}, ["i32.const": 66560]}, {{:i32, :const}, ["i32.const": 1024]}]}, {:section_type, :export}, {:section_body, [ {"memory", {:mem, 0}}, {"__heap_base", {:global, 0}}, {"__data_end", {:global, 1}}, {"inc", {:func, 0}}, {"dec", {:func, 1}}, {"tri", {:func, 2}}, {"third", {:func, 3}} ]}, {:section_type, :code}, {:section_body, [ %{ code: %{ expr: [ {:"local.get", 0}, {:"i32.const", 1}, :"i32.add" ], locals: [] }, size: 7 }, %{ code: %{ expr: [ {:"local.get", 0}, {:"i32.const", 1}, :"i32.sub" ], locals: [] }, size: 7 }, %{ code: %{ expr: [ {:"local.get", 0}, {:"i32.const", 3}, :"i32.mul" ], locals: [] }, size: 7 }, %{ code: %{ expr: [ {:"local.get", 0}, {:"i32.const", 3}, :"i32.div_s" ], locals: [] }, size: 7 } ]} ] end test "3_int_cond" do assert parse_file("test_data/3_int_cond.opt.wasm") |> Enum.filter(fn {k, _} -> k == :section_type or k == :section_body end) == [ {:section_type, :type}, {:section_body, [{[:i32, :i32], [:i32]}]}, {:section_type, :function}, {:section_body, [0]}, {:section_type, :memory}, {:section_body, [{2, nil}]}, {:section_type, :global}, {:section_body, [{{:i32, :const}, ["i32.const": 66560]}, {{:i32, :const}, ["i32.const": 1024]}]}, {:section_type, :export}, {:section_body, [ {"memory", {:mem, 0}}, {"__heap_base", {:global, 0}}, {"__data_end", {:global, 1}}, {"ge_select", {:func, 0}} ]}, {:section_type, :code}, {:section_body, [ %{ code: %{ expr: [ {:"local.get", 1}, {:"local.get", 0}, {:"local.get", 0}, {:"local.get", 1}, :"i32.lt_s", :select ], locals: [] }, size: 12 } ]} ] end test "4_int_comp" do assert parse_file("test_data/4_int_comp.opt.wasm") |> Enum.filter(fn {k, _} -> k == :section_type or k == :section_body end) == [ {:section_type, :type}, {:section_body, [{[:i32, :i32], [:i32]}]}, {:section_type, :function}, {:section_body, [0, 0, 0, 0, 0, 0]}, {:section_type, :memory}, {:section_body, [{2, nil}]}, {:section_type, :global}, {:section_body, [{{:i32, :const}, ["i32.const": 66560]}, {{:i32, :const}, ["i32.const": 1024]}]}, {:section_type, :export}, {:section_body, [ {"memory", {:mem, 0}}, {"__heap_base", {:global, 0}}, {"__data_end", {:global, 1}}, {"eq", {:func, 0}}, {"ne", {:func, 1}}, {"lt", {:func, 2}}, {"gt", {:func, 3}}, {"le", {:func, 4}}, {"ge", {:func, 5}} ]}, {:section_type, :code}, {:section_body, [ %{ code: %{ expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.eq"], locals: [] }, size: 7 }, %{ code: %{expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.ne"], locals: []}, size: 7 }, %{ code: %{expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.lt_s"], locals: []}, size: 7 }, %{ code: %{expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.gt_s"], locals: []}, size: 7 }, %{ code: %{expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.le_s"], locals: []}, size: 7 }, %{ code: %{expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.ge_s"], locals: []}, size: 7 } ]} ] end test "5_int_factorial" do assert parse_file("test_data/5_int_factorial.opt.wasm") |> Enum.filter(fn {k, _} -> k == :section_type or k == :section_body end) == [ {:section_type, :type}, {:section_body, [{[:i32], [:i32]}]}, {:section_type, :function}, {:section_body, [0]}, {:section_type, :memory}, {:section_body, [{2, nil}]}, {:section_type, :global}, {:section_body, [{{:i32, :const}, ["i32.const": 66560]}, {{:i32, :const}, ["i32.const": 1024]}]}, {:section_type, :export}, {:section_body, [ {"memory", {:mem, 0}}, {"__heap_base", {:global, 0}}, {"__data_end", {:global, 1}}, {"factorial", {:func, 0}} ]}, {:section_type, :code}, {:section_body, [ %{ code: %{ expr: [ {:"i32.const", 1}, {:"local.set", 1}, {:"local.get", 0}, {:"i32.const", 1}, :"i32.ge_s", {:if, %{ blocktype: :empty, instr: [ loop: %{ blocktype: :empty, instr: [ {:"local.get", 2}, {:"i32.const", 1}, :"i32.add", {:"local.tee", 2}, {:"local.get", 1}, :"i32.mul", {:"local.set", 1}, {:"local.get", 0}, {:"local.get", 2}, :"i32.ne", {:br_if, 0} ] } ] }}, {:"local.get", 1} ], locals: [%{num: 2, type: :i32}] }, size: 40 } ]} ] end test "9_all" do assert parse_file("test_data/9_all.opt.wasm") |> Enum.filter(fn {k, _} -> k == :section_type or k == :section_body end) == [ {:section_type, :type}, {:section_body, [{[:i32, :i32], [:i32]}, {[:i32], [:i32]}, {[], [:i32]}]}, {:section_type, :function}, {:section_body, [2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1]}, {:section_type, :memory}, {:section_body, [{2, nil}]}, {:section_type, :global}, {:section_body, [{{:i32, :const}, ["i32.const": 66560]}, {{:i32, :const}, ["i32.const": 1024]}]}, {:section_type, :export}, {:section_body, [ {"memory", {:mem, 0}}, {"__heap_base", {:global, 0}}, {"__data_end", {:global, 1}}, {"return_0", {:func, 0}}, {"identity", {:func, 1}}, {"inc", {:func, 2}}, {"dec", {:func, 3}}, {"tri", {:func, 4}}, {"third", {:func, 5}}, {"ge_select", {:func, 6}}, {"eq", {:func, 7}}, {"ne", {:func, 8}}, {"lt", {:func, 9}}, {"gt", {:func, 10}}, {"le", {:func, 11}}, {"ge", {:func, 12}}, {"factorial", {:func, 13}} ]}, {:section_type, :code}, {:section_body, [ %{code: %{expr: ["i32.const": 0], locals: []}, size: 4}, %{code: %{expr: ["local.get": 0], locals: []}, size: 4}, %{ code: %{ expr: [ {:"local.get", 0}, {:"i32.const", 1}, :"i32.add" ], locals: [] }, size: 7 }, %{ code: %{ expr: [ {:"local.get", 0}, {:"i32.const", 1}, :"i32.sub" ], locals: [] }, size: 7 }, %{ code: %{ expr: [ {:"local.get", 0}, {:"i32.const", 3}, :"i32.mul" ], locals: [] }, size: 7 }, %{ code: %{ expr: [ {:"local.get", 0}, {:"i32.const", 3}, :"i32.div_s" ], locals: [] }, size: 7 }, %{ code: %{ expr: [ {:"local.get", 1}, {:"local.get", 0}, {:"local.get", 0}, {:"local.get", 1}, :"i32.lt_s", :select ], locals: [] }, size: 12 }, %{ code: %{ expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.eq"], locals: [] }, size: 7 }, %{ code: %{expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.ne"], locals: []}, size: 7 }, %{ code: %{expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.lt_s"], locals: []}, size: 7 }, %{ code: %{expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.gt_s"], locals: []}, size: 7 }, %{ code: %{expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.le_s"], locals: []}, size: 7 }, %{ code: %{expr: [{:"local.get", 0}, {:"local.get", 1}, :"i32.ge_s"], locals: []}, size: 7 }, %{ code: %{ expr: [ {:"i32.const", 1}, {:"local.set", 1}, {:"local.get", 0}, {:"i32.const", 1}, :"i32.ge_s", {:if, %{ blocktype: :empty, instr: [ loop: %{ blocktype: :empty, instr: [ {:"local.get", 2}, {:"i32.const", 1}, :"i32.add", {:"local.tee", 2}, {:"local.get", 1}, :"i32.mul", {:"local.set", 1}, {:"local.get", 0}, {:"local.get", 2}, :"i32.ne", {:br_if, 0} ] } ] }}, {:"local.get", 1} ], locals: [%{num: 2, type: :i32}] }, size: 40 } ]} ] end end