Skip to content

Commit 12be999

Browse files
committed
Document do block differences
1 parent 8b7f102 commit 12be999

File tree

1 file changed

+28
-14
lines changed

1 file changed

+28
-14
lines changed

docs/src/reference.md

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ the source text more closely.
4343
* The right hand side of `x where {T}` retains the `K"braces"` node around the `T` to distinguish it from `x where T`.
4444
* Ternary syntax is not immediately lowered to an `if` node: `a ? b : c` parses as `(? a b c)` rather than `Expr(:if, :a, :b, :c)` (#85)
4545
* `global const` and `const global` are not normalized by the parser. This is done in `Expr` conversion (#130)
46-
* The AST for `do` is flatter and not lowered to a lambda by the parser: `f(x) do y ; body end` is parsed as `(do (call f x) (tuple y) (block body))` (#98)
46+
* [`do` syntax](#Do-blocks) is nested as the last child of the call which the `do` lambda will be passed to (#98, #322)
4747
* `@.` is not lowered to `@__dot__` inside the parser (#146)
4848
* Docstrings use the `K"doc"` kind, and are not lowered to `Core.@doc` until later (#217)
4949
* Juxtaposition uses the `K"juxtapose"` kind rather than lowering immediately to `*` (#220)
@@ -77,7 +77,6 @@ class of tokenization errors and lets the parser deal with them.
7777
* We use flags rather than child nodes to represent the difference between `struct` and `mutable struct`, `module` and `baremodule` (#220)
7878
* Multiple iterations within the header of a `for`, as in `for a=as, b=bs body end` are represented with a `cartesian_iterator` head rather than a `block`, as these lists of iterators are neither semantically nor syntactically a sequence of statements. Unlike other uses of `block` (see also generators).
7979

80-
8180
## More detail on tree differences
8281

8382
### Generators
@@ -195,23 +194,38 @@ The same goes for command strings which are always wrapped in `K"cmdstring"`
195194
regardless of whether they have multiple pieces (due to triple-quoted
196195
dedenting) or otherwise.
197196

198-
### No desugaring of the closure in do blocks
197+
### Do blocks
199198

200-
The reference parser represents `do` syntax with a closure for the second
201-
argument. That is,
199+
`do` syntax is represented in the `Expr` AST with the `do` outside the call.
200+
This makes some sense syntactically (do appears as "an operator" after the
201+
function call).
202202

203-
```julia
204-
f(x) do y
205-
body
206-
end
207-
```
203+
However semantically this nesting is awkward because the lambda represented by
204+
the do block is passed to the call. This same problem occurs for the macro form
205+
`@f(x) do \n body end` where the macro expander needs a special rule to expand
206+
nestings of the form `Expr(:do, Expr(:macrocall ...), ...)`, rearranging the
207+
expression which are passed to this macro call rather than passing the
208+
expressions up the tree.
209+
210+
The implied closure is also lowered to a nested `Expr(:->)` expression, though
211+
it this somewhat premature to do this during parsing.
212+
213+
To resolve these problems we parse
214+
215+
@f(x, y) do a, b\n body\n end
216+
f(x, y) do a, b\n body\n end
208217

209-
becomes `(do (call f x) (-> (tuple y) (block body)))` in the reference parser.
218+
by tacking the `do` onto the end of the call argument list:
210219

211-
However, the nested closure with `->` head is implied here rather than present
212-
in the surface syntax, which suggests this is a premature desugaring step.
213-
Instead we emit the flatter structure `(do (call f x) (tuple y) (block body))`.
220+
(macrocall @f x y (do (tuple a b) body))
221+
(call f x y (do (tuple a b) body))
214222

223+
This achieves the following desirable properties
224+
1. Content of `do` is nested inside the call which improves the match between AST and semantics
225+
2. Macro can be passed the syntax as-is rather than the macro expander rearranging syntax before passing it to the macro
226+
3. In the future, a macro can detect when it's being passed do syntax rather than lambda syntax
227+
4. `do` head is used uniformly for both call and macrocall
228+
5. We preserve the source ordering properties we need for the green tree.
215229

216230
## Tree structure reference
217231

0 commit comments

Comments
 (0)