Skip to content

Commit 4d9c50a

Browse files
authored
Add braces node around T in x where {T} (#264)
This allows `x where T` to be distinguished from `x where {T}` easily which should be quite helpful for source formatting tooling. It's also more consistent with the other allowed (but weird) forms such as `x where {T S}`.
1 parent d18dc3f commit 4d9c50a

File tree

5 files changed

+19
-13
lines changed

5 files changed

+19
-13
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ the source text more closely.
400400

401401
* `K"macrocall"` - allow users to easily distinguish macrocalls with parentheses from those without them (#218)
402402
* Grouping parentheses are represented with a node of kind `K"parens"` (#222)
403+
* The right hand side of `x where {T}` retains the `K"braces"` node around the `T` to distinguish it from `x where T`.
403404
* 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)
404405
* `global const` and `const global` are not normalized by the parser. This is done in `Expr` conversion (#130)
405406
* 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)

src/expr.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,11 @@ function _to_expr(node::SyntaxNode; iteration_spec=false, need_linenodes=true,
212212
end
213213
end
214214
elseif headsym === :where
215-
reorder_parameters!(args, 2)
215+
if length(args) == 2 && Meta.isexpr(args[2], :braces)
216+
a2 = args[2].args
217+
reorder_parameters!(a2, 2)
218+
args = Any[args[1], a2...]
219+
end
216220
elseif headsym === :parens
217221
# parens are used for grouping and don't appear in the Expr AST
218222
if length(args) == 1

src/parser.jl

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,17 +1047,15 @@ function parse_where_chain(ps0::ParseState, mark)
10471047
bump_trivia(ps, skip_newlines=true)
10481048
k = peek(ps)
10491049
if k == K"{"
1050+
# x where \n {T} ==> (where x (braces T))
1051+
# x where {T,S} ==> (where x (braces T S))
1052+
# Also various nonsensical forms permitted
1053+
# x where {T S} ==> (where x (bracescat (row T S)))
1054+
# x where {y for y in ys} ==> (where x (braces (generator y (= y ys))))
10501055
m = position(ps)
10511056
bump(ps, TRIVIA_FLAG)
1052-
# x where \n {T} ==> (where x T)
1053-
# x where {T,S} ==> (where x T S)
10541057
ckind, cflags = parse_cat(ps, K"}", ps.end_symbol)
1055-
if ckind != K"vect"
1056-
# Various nonsensical forms permitted here
1057-
# x where {T S} ==> (where x (bracescat (row T S)))
1058-
# x where {y for y in ys} ==> (where x (braces (generator y (= y ys))))
1059-
emit_braces(ps, m, ckind, cflags)
1060-
end
1058+
emit_braces(ps, m, ckind, cflags)
10611059
emit(ps, mark, K"where")
10621060
else
10631061
# x where T ==> (where x T)
@@ -2170,7 +2168,7 @@ function parse_function_signature(ps::ParseState, is_function::Bool)
21702168
end
21712169
if peek(ps) == K"where"
21722170
# Function signature where syntax
2173-
# function f() where {T} end ==> (function (where (call f) T) (block))
2171+
# function f() where {T} end ==> (function (where (call f) (braces T)) (block))
21742172
# function f() where T end ==> (function (where (call f) T) (block))
21752173
parse_where_chain(ps, mark)
21762174
end

test/expr.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,9 @@
317317
end
318318

319319
@testset "where" begin
320+
@test parsestmt(Expr, "A where T") == Expr(:where, :A, :T)
321+
@test parsestmt(Expr, "A where {T}") == Expr(:where, :A, :T)
322+
@test parsestmt(Expr, "A where {S, T}") == Expr(:where, :A, :S, :T)
320323
@test parsestmt(Expr, "A where {X, Y; Z}") == Expr(:where, :A, Expr(:parameters, :Z), :X, :Y)
321324
end
322325

test/parser.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,8 @@ tests = [
287287
# compatible with the reference parser (see #248)
288288
"+ <: A where B" => "(where (call-pre + (<:-pre A)) B)"
289289
# Really for parse_where
290-
"x where \n {T}" => "(where x T)"
291-
"x where {T,S}" => "(where x T S)"
290+
"x where \n {T}" => "(where x (braces T))"
291+
"x where {T,S}" => "(where x (braces T S))"
292292
"x where {T S}" => "(where x (bracescat (row T S)))"
293293
"x where {y for y in ys}" => "(where x (braces (generator y (= y ys))))"
294294
"x where T" => "(where x T)"
@@ -578,7 +578,7 @@ tests = [
578578
"function f body end" => "(function (error f) (block body))"
579579
"function f()::T end" => "(function (::-i (call f) T) (block))"
580580
"function f()::g(T) end" => "(function (::-i (call f) (call g T)) (block))"
581-
"function f() where {T} end" => "(function (where (call f) T) (block))"
581+
"function f() where {T} end" => "(function (where (call f) (braces T)) (block))"
582582
"function f() where T end" => "(function (where (call f) T) (block))"
583583
"function f()::S where T end" => "(function (where (::-i (call f) S) T) (block))"
584584
# Ugly cases for compat where extra parentheses existed and we've

0 commit comments

Comments
 (0)