dashbitco / nimble_parsec

A simple and fast library for text-based parser combinators

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MatchError from choice with integer and string.

thebearmayor opened this issue · comments

choice with integer and string choices throws a MatchError when integer is first and the input is a string. When the string is first, it does not error, nor does it error when matching an integer.

This is my first time using the library, so apologies if I've misunderstood how to use it.

Parser

defparsec(:int_or_test, choice([integer(max: 2), string("test")]), debug: true)

Use

iex(1)> Parsertest.int_or_test("test")
** (MatchError) no match of right hand side value: []
    (parsertest 0.1.0) Parsertest.int_or_test__10/6
    (parsertest 0.1.0) Parsertest.int_or_test/2
    iex:1: (file)
iex(1)> Parsertest.int_or_test("99")  
{:ok, 'c', "", %{}, {1, 0}, 2}

Debug

defp int_or_test__0(rest, acc, stack, context, line, offset) do
  int_or_test__5(rest, [], [{rest, context, line, offset}, acc | stack], context, line, offset)
end

defp int_or_test__2(<<"test", rest::binary>>, acc, stack, context, comb__line, comb__offset) do
  int_or_test__3(rest, ["test"] ++ acc, stack, context, comb__line, comb__offset + 4)
end

defp int_or_test__2(rest, _acc, _stack, context, line, offset) do
  {:error, "expected ASCII character in the range '0' to '9' or string \"test\"", rest, context,
 line, offset}
end

defp int_or_test__3(rest, acc, [_, previous_acc | stack], context, line, offset) do
  int_or_test__1(rest, acc ++ previous_acc, stack, context, line, offset)
end

defp int_or_test__4(_, _, [{rest, context, line, offset} | _] = stack, _, _, _) do
  int_or_test__2(rest, [], stack, context, line, offset)
end

defp int_or_test__5(rest, acc, stack, context, line, offset) do
  int_or_test__6(rest, [], [acc | stack], context, line, offset)
end

defp int_or_test__6(rest, acc, stack, context, line, offset) do
  int_or_test__8(rest, acc, [2 | stack], context, line, offset)
end

defp int_or_test__8(<<x0, rest::binary>>, acc, stack, context, comb__line, comb__offset) when x0 >= 48 and x0 <= 57 do
  int_or_test__9(rest, [x0] ++ acc, stack, context, comb__line, comb__offset + 1)
end

defp int_or_test__8(rest, acc, stack, context, line, offset) do
  int_or_test__7(rest, acc, stack, context, line, offset)
end

defp int_or_test__7(rest, acc, [_ | stack], context, line, offset) do
  int_or_test__10(rest, acc, stack, context, line, offset)
end

defp int_or_test__9(rest, acc, [1 | stack], context, line, offset) do
  int_or_test__10(rest, acc, stack, context, line, offset)
end

defp int_or_test__9(rest, acc, [count | stack], context, line, offset) do
  int_or_test__8(rest, acc, [count - 1 | stack], context, line, offset)
end

defp int_or_test__10(rest, user_acc, [acc | stack], context, line, offset) do
  _ = user_acc

int_or_test__11(
  rest,
  (
    [head | tail] = :lists.reverse(user_acc)
    [:lists.foldl(fn x, acc -> x - 48 + acc * 10 end, head - 48, tail)]
  ) ++ acc,
  stack,
  context,
  line,
  offset
)
end

defp int_or_test__11(rest, acc, [_, previous_acc | stack], context, line, offset) do
  int_or_test__1(rest, acc ++ previous_acc, stack, context, line, offset)
end

defp int_or_test__1(rest, acc, _stack, context, line, offset) do
  {:ok, acc, rest, context, line, offset}
end

Yup, definitely looks like a bug. Thanks for breaking it down and the report!