`repeat_while` passing the wrong `context` in nested context
Kabie opened this issue · comments
Kabie commented
An example:
Mix.install([{:nimble_parsec, "~> 1.2"}])
defmodule Bug do
import NimbleParsec
def n_times(_, context, _, _) do
context
|> IO.inspect()
if context.count > 0 do
{:cont, %{context | count: context.count - 1}}
else
{:halt, context}
end
end
# If remove `repeat` below, it works fine
value = repeat(ascii_char([?0..?9]))
key = ascii_char([?a..?z])
segment = key |> concat(value)
defparsec :parse, repeat_while(segment, {:n_times, []}), debug: true
end
Bug.parse("a1b2c3d4e5f6g7h8", context: %{count: 3})
The output:
defp parse__0(rest, acc, stack, context, line, offset) do
case n_times(rest, context, line, offset) do
{:cont, context} ->
parse__2(rest, [], [{rest, acc, context, line, offset} | stack], context, line, offset)
{:halt, context} ->
parse__6(rest, acc, stack, context, line, offset)
end
end
defp parse__2(<<x0, rest::binary>>, acc, stack, context, comb__line, comb__offset) when x0 >= 97 and x0 <= 122 do
parse__3(rest, [x0] ++ acc, stack, context, comb__line, comb__offset + 1)
end
defp parse__2(rest, acc, stack, context, line, offset) do
parse__1(rest, acc, stack, context, line, offset)
end
defp parse__3(<<x0, rest::binary>>, acc, stack, context, comb__line, comb__offset) when x0 >= 48 and x0 <= 57 do
parse__5(rest, [x0] ++ acc, stack, context, comb__line, comb__offset + 1)
end
defp parse__3(rest, acc, stack, context, line, offset) do
parse__4(rest, acc, stack, context, line, offset)
end
defp parse__5(rest, acc, stack, context, line, offset) do
parse__3(rest, acc, stack, context, line, offset)
end
defp parse__1(_, _, [{rest, acc, context, line, offset} | stack], _, _, _) do
parse__6(rest, acc, stack, context, line, offset)
end
defp parse__4(
inner_rest,
inner_acc,
[{rest, acc, context, line, offset} | stack],
inner_context,
inner_line,
inner_offset
) do
case n_times(rest, context, line, offset) do
{:cont, context} ->
parse__2(
inner_rest,
[],
[{inner_rest, inner_acc ++ acc, inner_context, inner_line, inner_offset} | stack],
inner_context,
inner_line,
inner_offset
)
{:halt, context} ->
parse__6(rest, acc, stack, context, line, offset)
end
end
defp parse__6(rest, acc, _stack, context, line, offset) do
{:ok, acc, rest, context, line, offset}
end
%{count: 3}
%{count: 2}
%{count: 2}
%{count: 2}
%{count: 2}
%{count: 2}
%{count: 2}
%{count: 2}
%{count: 2}
You can see in defp parse__4
, it passes inner_context
instead of the returned context
to next iteration.