Thank you Luke for the detailed bug report.

I think we should fix this by making "!" behave like "not" and remove this
special case from the grammar. The only unary operator that will bind
tightly to numbers then will be &, which is already behaves differently
from the others as it has very low precedence.

Note that @ will still bind tightly to numbers but that's rather because it
has very high precedence and not a special case.

I will push a commit to master later today.


*José Valim*
www.plataformatec.com.br
Skype: jv.ptec
Founder and Director of R&D

On Sun, May 14, 2017 at 4:18 AM, Luke Imhoff <[email protected]> wrote:

> I noticed this when splitting `not` from the other unary operators in
> IntelliJ Elixir's lexer grammar (because I can only do spacing rules on
> lexer tokens, so I need NOT_OPERATOR separate from UNARY_OPERATOR for
> https://github.com/KronicDeth/intellij-elixir/issues/98 so I can have no
> space between the symbolic operators, but require the space after `not` as
> it will blend into the argument otherwise).  I'm not sure this is really a
> problem or not.  It's just a weird edge-case that I produced since I test
> unary numeric and unary non-numeric operators.
>
> `not` is part of `unary_op_eol` (https://github.com/elixir-lan
> g/elixir/blob/39dd31c7d96f302986579bb6938d23c9db101661/lib/
> elixir/src/elixir_parser.yrl#L73), which also contains `+`, `-`, `!`,
> `^`, `~~~`.
>
> Let's start with unary numeric at the top-level
>
> iex> Code.string_to_quoted("not 1")
> {:ok, {:not, [line: 1], [1]}}
> iex> Code.string_to_quoted("! 1")
> {:ok, {:!, [line: 1], [1]}}
>
> Next, let's do something weird and make the `1` act something you can do
> dot calls on.  This is gibberish semantically in current Elixir, but
> something the syntax allows.
>
> iex> Code.string_to_quoted("not 1.(2)")
> {:ok, {{:., [line: 1], [{:not, [line: 1], [1]}]}, [line: 1], [2]}}
> iex> Code.string_to_quoted("! 1.(2)")
> {:ok, {{:., [line: 1], [{:!, [line: 1], [1]}]}, [line: 1], [2]}}
>
> So, the precedence of the AST is the same: (1) `not`/`!` on `1`; (2) dot
> call with `2` on the result of (1).
>
> Finally, let's try to capture the weird syntax
>
> iex> Code.string_to_quoted("&not 1.(2)")
> {:ok, {:&, [line: 1], [{:not, [line: 1], [{{:., [line: 1], [1]}, [line:
> 1], [2]}]}]}}
> iex> Code.string_to_quoted("&! 1.(2)")
> {:ok, {:&, [line: 1], [{{:., [line: 1], [{:!, [line: 1], [1]}]}, [line:
> 1], [2]}]}}
>
> So the precedence of the symbolic `!` and word `not` is no longer the same.
> For `not`: (1) `1.(2)` is called; (2) `not` the  result of (1)`; (3)
> capture
> For `!`: `!1` is called; (2) `.(2)` is called on the result of (1); (3)
> capture
>
> What has happened is that `not` has lost it's "keywordness" and is moving
> the position of a normal function name (like `foo` below)
>
> iex> Code.string_to_quoted("&foo 1.(2)")
> {:ok, {:&, [line: 1], [{:foo, [line: 1], [{{:., [line: 1], [1]}, [line:
> 1], [2]}]}]}}
>
> So, this example is gibberish.  Does it apply to non-numeric unary
> operations?
>
> iex> Code.string_to_quoted("&! a.(2)")
> {:ok, {:&, [line: 1], [{:!, [line: 1], [{{:., [line: 1], [{:a, [line: 1],
> nil}]}, [line: 1], [2]}]}]}}
> iex> Code.string_to_quoted("&not a.(2)")
> {:ok, {:&, [line: 1], [{:not, [line: 1], [{{:., [line: 1], [{:a, [line:
> 1], nil}]}, [line: 1], [2]}]}]}}
> iex(56)> Code.string_to_quoted("&foo a.(2)")
> {:ok, {:&, [line: 1], [{:foo, [line: 1], [{{:., [line: 1], [{:a, [line:
> 1], nil}]}, [line: 1], [2]}]}]}}
>
> So, it's all consistent there: (1) `a.(2)` is evaluated; (2) the
> operator/function call; and (3) it's all captured.
>
> So, is the inconsistency in unary numeric `not` a bug in the native
> grammar or something to be expected?  If the unary operators should bind
> more tightly to numerics than non-numerics (as is my understanding of the
> current grammar) then `{:ok, {:&, [line: 1], [{{:., [line: 1], [{:!, [line:
> 1], [1]}]}, [line: 1], [2]}]}}` is correct and `not` should be `{:ok, {:&,
> [line: 1], [{{:., [line: 1], [{:not, [line: 1], [1]}]}, [line: 1], [2]}]}}`.
>
> The unary numeric operations in current language semantics seem to be
> there for positional captures, like `&1`, so this is mostly me bringing it
> up because I have to change IntelliJ Elixir's grammar to take this
> behaviour for unary numeric `not` into account separately from symbolic
> unary numerics.
>
> --
> You received this message because you are subscribed to the Google Groups
> "elixir-lang-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion on the web visit https://groups.google.com/d/ms
> gid/elixir-lang-core/f5f75451-93dc-4163-bd9a-7055dab69d62%
> 40googlegroups.com
> <https://groups.google.com/d/msgid/elixir-lang-core/f5f75451-93dc-4163-bd9a-7055dab69d62%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4LkhHOfJVjokBgpiNy8Fh9T1WMTRvWQ8%3Du9HmMA9MdpUA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to