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

AST node for iteration #432

Open
c42f opened this issue May 12, 2024 · 0 comments
Open

AST node for iteration #432

c42f opened this issue May 12, 2024 · 0 comments

Comments

@c42f
Copy link
Member

c42f commented May 12, 2024

There's been something niggling at me about the way iteration is represented in the AST.

Currently we have the following parsing:

julia> parsestmt(SyntaxNode, """
       for x = xs
          body
       end""")
line:col│ tree                                   │ file_name
   1:1  │[for]                                   │
   1:4  │  [=]
   1:5  │    x
   1:9  │    xs
   1:11 │  [block]
   2:4  │    body

julia> parsestmt(SyntaxNode, """
       for x = xs, y = ys
          body
       end""")
line:col│ tree                                   │ file_name
   1:1  │[for]                                   │
   1:4  │  [cartesian_iterator]
   1:4  │    [=]
   1:5  │      x
   1:9  │      xs
   1:12 │    [=]
   1:13 │      y
   1:17 │      ys
   1:19 │  [block]
   2:4  │    body

But the = node here doesn't have normal assignment semantics. It does create a binding for x, but not to the expression on the right hand side of the =. Also the user may use in rather than = in the source; this is normalized to = by the parser for consistency, but this only emphasizes that there's something a bit weird going on: it's not assignment; merely assignment-like.

The use of cartesian_iterator is semantically nice because we also get to reuse it for array comprehensions where it means the same thing (the representation in Expr doesn't have this level of uniformity so things are already, hopefully, a bit of an improvement).

Complex comprehensions only make this worse, where = nodes can appear all over the place in the AST. For example,

julia> parsestmt(SyntaxNode, """
       [a for i = xs, j = ys if z]""")
line:col│ tree                                   │ file_name
   1:1  │[comprehension]                         │
   1:2  │  [generator]
   1:2  │    a
   1:7  │    [filter]
   1:7  │      [cartesian_iterator]
   1:7  │        [=]
   1:8  │          i
   1:12 │          xs
   1:15 │        [=]
   1:16 │          j
   1:20 │          ys
   1:26 │      z

julia> parsestmt(SyntaxNode, """
       [a for i = xs for j = ys if z]""")
line:col│ tree                                   │ file_name
   1:1  │[comprehension]                         │
   1:2  │  [generator]
   1:2  │    a
   1:7  │    [=]
   1:8  │      i
   1:12 │      xs
   1:18 │    [filter]
   1:18 │      [=]
   1:19 │        j
   1:23 │        ys
   1:29 │      z

Possible solution

I'd like to propose a syntax kind K"iteration" to replace the use of both K"=" and K"cartesian_iterator".

A possible rule could be:

  • Existing (= x xs) AST for iteration becomes (iteration x xs)
  • Existing (cartesian_iterator (= x xs) (= y ys)) becomes (iteration x xs y ys).

The cases above would look like

julia> parsestmt(SyntaxNode, """
       [a for i = xs, j = ys if z]""")
line:col│ tree                                   │ file_name
   1:1  │[comprehension]                         │
   1:2  │  [generator]
   1:2  │    a
   1:7  │    [filter]
   1:7  │      [iteration]
   1:8  │        i
   1:12 │        xs
   1:16 │        j
   1:20 │        ys
   1:26 │      z

julia> parsestmt(SyntaxNode, """
       [a for i = xs for j = ys if z]""")
line:col│ tree                                   │ file_name
   1:1  │[comprehension]                         │
   1:2  │  [generator]
   1:2  │    a
   1:7  │    [iteration]
   1:8  │      i
   1:12 │      xs
   1:18 │    [filter]
   1:18 │      [iteration]
   1:19 │        j
   1:23 │        ys
   1:29 │      z

Some possible advantages

  • a semantically sound syntax kind fixes the awkwardness of preferring = vs in for a concept which is neither really assignment nor set inclusion
  • This makes recursive processing of the syntax tree a bit simpler if one wants to find = but omit special-casing the first child of for
  • Possibly makes writing macros simpler when processing cartesian iterators, as there's less nesting? Unclear.
  • Renaming cartesian_iterator to something less specific feels sane because cartesian iteration is a very semantically precise/narrow concept, but AST for surface syntax is, somewhat, just trying to represent what's there visually. For macros to process, for example.

Alternatives?

Is allowing iteration to have any even number of children to represent cartesian iteration a good call? Would writing macro code against a nested AST be easier?

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

No branches or pull requests

1 participant