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("¬ 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("¬ 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.
