taguniversalmachine

taguniversalmachine

Help with NimbleParsec

Hi,

I am trying to define a parser for a simple grammar and I am getting hung up on something that I think is simple but I can’t figure out.

The grammar has two main structures, a definition and an invocation, of the form:

invocationname($a$b)(c<>d<>)
definitionname[(a<>b<>)($c$d)somestuff:someotherstuff]

I have the invocation one working, but for some reason even though the definition structure is very similar, I get an error that it is expecting the opening bracket, even though I am sending it.

The whole parser definition is here, and I will copy my interaction with it:

defmodule Atomix.Invocation.Parser do
  import NimbleParsec

  name = ascii_string([?A..?z], min: 1)

  definition_name = ascii_string([?A..?z], min: 1)

  invocation_name = ascii_string([?a..?z], min: 1)

  content_name = ascii_string([?A..?Z], min: 1)

  destination_place =
    string("$")
    |> concat(name)

  destination_list =
    destination_place
    |> repeat(destination_place)

  source_place =
    name
    |> string("<>")

  source_list =
    source_place
    |> repeat(source_place)

  place_of_resolution =
    string("+")

  contained_definitions =
    string("=")


  defparsec(
    :invocation,
    invocation_name
    |> string("(")
    |> concat(destination_list)
    |> string(")")
    |> string("(")
    |> concat(source_list)
    |> string(")")
  )

  defparsec(
    :definition,
    definition_name
    |> string("[")
    |> concat(source_list)
    |> concat(destination_list)
    |> concat(place_of_resolution)
    |> string(":")
    |> concat(contained_definitions)
    |> string("]")
  )
end

iex(2)> Parser.invocation(“dfsd($a$b)(a<>b<>)”)
{:ok, [“dfsd”, “(”, “$”, “a”, “$”, “b”, “)”, “(”, “a”, “<>”, “b”, “<>”, “)”],
“”, %{}, {1, 0}, 18}
iex(3)> Parser.definition(“fdafa[(a<>b<>)fdsaf:fadf]”)
{:error, “expected string "["”, “(a<>b<>)fdsaf:fadf]”, %{}, {1, 0}, 6}

Why am I getting the error about expecting the bracket when it is clearly there?
Thanks for any pointers.

Marked As Solved

kip

kip

ex_cldr Core Team

The problem is that you are defining character ranges that encompass the [ character:

  name = ascii_string([?A..?z], min: 1)
  definition_name = ascii_string([?A..?z], min: 1)

In the ASCII character set, ?a..?z and ?A..?Z are not contiguous with each other. For example:

iex> ?A..?z
65..122
iex> ?[
91

So you can see that [ fits in the range ?A..?z and therefore your [ is being consumed by definition_name. You can add a call to debug() in your combinator pipeline which will output some information that can often help with tracking down these issues.

I think you probably meant:

  name = ascii_string([?A..?Z,?a..?z], min: 1)
  definition_name = ascii_string([?A..?Z,?a..?z], min: 1)

Also Liked

kip

kip

ex_cldr Core Team

I think your definition parser still needs some development but I took a stab at a version of invocation that is a bit more idiomatic:

defmodule Atomix.Invocation.Parser do
  import NimbleParsec

  name = 
    |> ascii_string([?A..?Z, ?a..?z], min: 1)
    |> unwrap_and_tag(:name)

  definition_name =
    ascii_string([?a..?z, ?A..?Z], min: 1)
    |> unwrap_and_tag(:destination_name)

  invocation_name =
    ascii_string([?a..?z], min: 1)
    |> unwrap_and_tag(:invocation_name)

  content_name =
    ascii_string([?A..?Z], min: 1)
    |> unwrap_and_tag(:content_name)

  destination_place =
    ignore(string("$"))
    |> concat(name)
    |> unwrap_and_tag(:destination_place)

  destination_list =
    destination_place
    |> repeat(destination_place)
    |> tag(:destination_list)

  source_place =
    name
    |> ignore(string("<>"))
    |> unwrap_and_tag(:source_place)

  source_list =
    source_place
    |> repeat(source_place)
    |> tag(:source_list)

  place_of_resolution =
    string("+")

  contained_definitions =
    string("=")


  defparsec(
    :invocation,
    invocation_name
    |> ignore(string("("))
    |> concat(destination_list)
    |> ignore(string(")"))
    |> ignore(string("("))
    |> concat(source_list)
    |> ignore(string(")"))
  )

  defparsec(
    :definition,
    definition_name
    |> ignore(string("["))
    |> concat(source_list)
    |> concat(destination_list)
    |> concat(place_of_resolution)
    |> string(":")
    |> concat(contained_definitions)
    |> string("]")
  )
end

In use:

iex> Parser.invocation("dfsd($a$b)(a<>b<>)")
{:ok,
 [
   invocation_name: "dfsd",
   destination_list: [destination_place: "a", destination_place: "b"],
   source_list: [source_place: "a", source_place: "b"]
 ], "", %{}, {1, 0}, 18}

Last Post!

taguniversalmachine

taguniversalmachine

oh gotcha, thank you very much for the explanation!

Where Next?

Popular in Questions Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 130579 1222
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 54092 488
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42576 114
New

We're in Beta

About us Mission Statement