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-lang/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/msgid/elixir-lang-core/f5f75451-93dc-4163-bd9a-7055dab69d62%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to