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}

Where Next?

Popular in Questions Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
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
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
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
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
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
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

peerreynders
Manning 2016 Halloween weekend sale via Deal of the Day Friday, October 28 - Half off all MEAPs - code WM102816LT Saturday, October 29 ...
326 29600 154
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
William
I would like to know that is there any online source for learning Phoenix Framework for building E-Commerce Store? Any advantage on build...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New

We're in Beta

About us Mission Statement