Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help to create a Macro that use defparsec #27

Closed
meox opened this issue May 10, 2018 · 5 comments
Closed

Help to create a Macro that use defparsec #27

meox opened this issue May 10, 2018 · 5 comments

Comments

@meox
Copy link
Contributor

meox commented May 10, 2018

I'm trying to write a super-parser, smthg like this:

  defmacro named_parser(name, parser, tag) do
    defparsec(
      name,
      symbol
      |> map({:extract, []})
      |> ignore(spaces)
      |> optional(int_t |> tag(:tag))
      |> ignore(spaces)
      |> ignore(ascii_char([?:]))
      |> ignore(spaces1)
      |> concat(parser)
      |> tag(tag)
      |> map({:data_field_prettify, []})
    )
  end

but it doesn't works.
So I tried this:

  defmacro named_parser(name, parser, tag) do
    quote do
      defparsec(
        unquote(name),
        symbol
        |> map({:extract, []})
        |> ignore(spaces)
        |> optional(int_t |> tag(:tag))
        |> ignore(spaces)
        |> ignore(ascii_char([?:]))
        |> ignore(spaces1)
        |> concat(unquote(parser))
        |> tag(unquote(tag))
        |> map({:data_field_prettify, []})
      )
    end
  end

but I get this error:

== Compilation error in file lib/rulec/rulec_parser.ex ==
** (CompileError) lib/rulec/rulec_parser.ex:456: undefined function symbol/0
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    (elixir) expanding macro: Kernel.|>/2

Any suggestion?

@whatyouhide
Copy link

Where is symbol coming from? Is it defined outside the macro?

@josevalim
Copy link
Member

Hi @meox! As @whatyouhide said, make sure that all variables are unquoted, otherwise you will get undefined function/variable errors.

@meox
Copy link
Contributor Author

meox commented May 11, 2018

Ok, I've moved my code in the same module.
The problem now is a different

defmodule RuleC.Macro do
  import NimbleParsec

  # some other stuff here

  defmacro named_parser(name, parser, tag) do
    quote do
      defparsec(
        unquote(name),
        symbol
        |> map({:extract, []})
        |> ignore(spaces)
        |> optional(int_t |> tag(:tag))
        |> ignore(spaces)
        |> ignore(ascii_char([?:]))
        |> ignore(spaces1)
        |> concat(unquote(parser))
        |> tag(unquote(tag))
        |> map({:data_field_prettify, []})
      )
    end
  end

  named_parser(
    :data_map_type,
    parsec(:data_anonymous_map_t),
    :tag_data_map_type
  )

end

I'm getting:

== Compilation error in file lib/rulec/rulec_parser.ex ==
** (CompileError) lib/rulec/rulec_parser.ex:472: undefined function named_parser/3

I semplified the problem with this stupid module:

defmodule TestMacro do

  defmacro my_macro(x) do
    quote do
      unquote(x) + 1
    end
  end

  def my_fun() do
    my_macro(5)
  end
end

This works (as expected) but not this one:

defmodule TestMacro do

  defmacro my_macro(x) do
    quote do
      unquote(x) + 1
    end
  end

  my_macro(5)
end

So seems that I have to define the macro in a different module. Is it right?

@josevalim
Copy link
Member

Yes, exactly.

@meox
Copy link
Contributor Author

meox commented May 11, 2018

In order to resolve this issue I found now another problem:
seems that is not possible to invoke a parser defined in onother module using parsec.

I'm going to explain it better.
I have now 3 files:

  • RuleC.Parser (that contains the main parser spec)
  • RuleC.BasicDef (that contains only some basic definition of the language)
  • RuleC.Macro (that contain 1 macro)

RuleC.BasicDef "import" NimbleParsec
RuleC.Macro "import" NimbleParsec and RuleC.BasicDef
RuleC.Parser "import" NimbleParsec, RuleC.BasicDef and RuleC.Macro

Inside RuleC.Parser there are many defparsec that use parser defined in RuleC.BasicDef.

== Compilation error in file lib/rulec/rulec_parser.ex ==
** (CompileError) lib/rulec/rulec_parser.ex:17: undefined function spaces__0/6
    (stdlib) lists.erl:1338: :lists.foreach/2
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6

Any suggestion?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants