From f272dbab5371ae73caa56e8d6dc4ad074fc027d0 Mon Sep 17 00:00:00 2001 From: Daniel Kukula Date: Thu, 13 Jul 2023 22:46:28 +0100 Subject: [PATCH] parse_integers_using_lower_nibble --- lib/nimble_parsec.ex | 19 +++++++++++++------ lib/nimble_parsec/compiler.ex | 24 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/nimble_parsec.ex b/lib/nimble_parsec.ex index 27e22d6..6a374a1 100644 --- a/lib/nimble_parsec.ex +++ b/lib/nimble_parsec.ex @@ -691,6 +691,13 @@ defmodule NimbleParsec do bin_segment(combinator, inclusive, exclusive, :integer) end + @spec integer_nibble() :: t + @spec integer_nibble(t) :: t + def integer_nibble(combinator \\ empty()) + when is_combinator(combinator) do + [{:integer_nibble} | combinator] + end + @doc ~S""" Defines a single UTF-8 codepoint in the given ranges. @@ -812,7 +819,7 @@ defmodule NimbleParsec do min_max_compile_runtime_chars( combinator, - ascii_char([?0..?9]), + integer_nibble(), count, :__compile_integer__, :__runtime_integer__, @@ -828,7 +835,7 @@ defmodule NimbleParsec do min_max_compile_runtime_chars( combinator, - ascii_char([?0..?9]), + integer_nibble(), opts, :__compile_integer__, :__runtime_integer__, @@ -2083,7 +2090,7 @@ defmodule NimbleParsec do ast = quote do [head | tail] = unquote(reverse_now_or_later(acc)) - [:lists.foldl(fn x, acc -> x - ?0 + acc * 10 end, head, tail)] + [:lists.foldl(fn x, acc -> x + acc * 10 end, head, tail)] end {:{}, [], [rest, ast, context]} @@ -2093,7 +2100,7 @@ defmodule NimbleParsec do ast = quote do [head | tail] = unquote(reverse_now_or_later(acc)) - [:lists.foldl(fn x, acc -> x - ?0 + acc * 10 end, head - ?0, tail)] + [:lists.foldl(fn x, acc -> x + acc * 10 end, head, tail)] end {:{}, [], [rest, ast, context]} @@ -2113,11 +2120,11 @@ defmodule NimbleParsec do defp reverse_now_or_later(expr), do: quote(do: :lists.reverse(unquote(expr))) defp quoted_ascii_to_integer([var | vars], 1) do - [quote(do: unquote(var) - ?0) | quoted_ascii_to_integer(vars, 10)] + [quote(do: unquote(var)) | quoted_ascii_to_integer(vars, 10)] end defp quoted_ascii_to_integer([var | vars], index) do - [quote(do: (unquote(var) - ?0) * unquote(index)) | quoted_ascii_to_integer(vars, index * 10)] + [quote(do: unquote(var) * unquote(index)) | quoted_ascii_to_integer(vars, index * 10)] end defp quoted_ascii_to_integer([], _index) do diff --git a/lib/nimble_parsec/compiler.ex b/lib/nimble_parsec/compiler.ex index 3ed1868..425b0b2 100644 --- a/lib/nimble_parsec/compiler.ex +++ b/lib/nimble_parsec/compiler.ex @@ -856,6 +856,26 @@ defmodule NimbleParsec.Compiler do {:ok, [string], [], [string], %{metadata | line: line, offset: offset}} end + defp bound_combinator({:integer_nibble}, metadata) do + %{offset: offset, counter: counter} = metadata + {inputs, vars, guards} = build_integer_nibble(counter) + counter = counter + 1 + offset = add_offset(offset, length(vars)) + + metadata = %{metadata | offset: offset, counter: counter} + {:ok, inputs, guards, vars, metadata} + end + + @nibble_size 4 + @integer_hi_nibble 3 + defp build_integer_nibble(counter) do + lo_nibble = {:"x#{counter}", [], Elixir} + guard = quote(do: unquote(lo_nibble) < unquote(10)) + + {[{:"::", [], [@integer_hi_nibble, @nibble_size]}, {:"::", [], [lo_nibble, @nibble_size]}], + [lo_nibble], [guard]} + end + defp bound_combinator({:bin_segment, inclusive, exclusive, modifier}, metadata) do %{line: line, offset: offset, counter: counter} = metadata @@ -986,6 +1006,10 @@ defmodule NimbleParsec.Compiler do "string #{inspect(binary)}" end + defp label({:integer_nibble}) do + "ASCII character in the range \"0\" to \"9\"" + end + defp label({:label, _combinator, label}) do label end