Skip to content

Commit 06801f2

Browse files
authored
Fix for function signatures with grouping parens (#140)
Cater for cases where some parts of the signature are inside and some outside of the parentheses. For example the reference parser allows an extra set of parens such as function (f()) where T body end and unfortunately this syntax is used in several packages.
1 parent 108b6c9 commit 06801f2

File tree

2 files changed

+28
-17
lines changed

2 files changed

+28
-17
lines changed

src/parser.jl

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,6 +2016,7 @@ end
20162016
# Parse function and macro definitions
20172017
function parse_function_signature(ps::ParseState, is_function::Bool)
20182018
is_anon_func = false
2019+
parsed_call = false
20192020

20202021
mark = position(ps)
20212022
if !is_function
@@ -2053,17 +2054,7 @@ function parse_function_signature(ps::ParseState, is_function::Bool)
20532054
parsed_call = _parsed_call)
20542055
end
20552056
is_anon_func = opts.is_anon_func
2056-
if opts.parsed_call
2057-
# Compat: Ugly case where extra parentheses existed and we've
2058-
# already parsed the whole signature.
2059-
# function (f() where T) end ==> (function (where (call f) T) (block))
2060-
# function (f()::S) end ==> (function (:: (call f) S) (block))
2061-
#
2062-
# TODO: Warn for use of parens? The precedence of `::` and
2063-
# `where` don't work inside parens so this is a bit of a syntax
2064-
# oddity/aberration.
2065-
return true
2066-
end
2057+
parsed_call = opts.parsed_call
20672058
if is_anon_func
20682059
# function (x) body end ==> (function (tuple x) (block body))
20692060
# function (x::f()) end ==> (function (tuple (:: x (call f))) (block))
@@ -2099,10 +2090,10 @@ function parse_function_signature(ps::ParseState, is_function::Bool)
20992090
end
21002091
end
21012092
end
2102-
if peek(ps, skip_newlines=true) == K"end" && !is_anon_func
2093+
if peek(ps, skip_newlines=true) == K"end" && !is_anon_func && !parsed_call
21032094
return false
21042095
end
2105-
if !is_anon_func
2096+
if !is_anon_func && !parsed_call
21062097
# Parse function argument list
21072098
# function f(x,y) end ==> (function (call f x y) (block))
21082099
# function f{T}() end ==> (function (call (curly f T)) (block))
@@ -2129,6 +2120,19 @@ function parse_function_signature(ps::ParseState, is_function::Bool)
21292120
parse_where_chain(ps, mark)
21302121
end
21312122
# function f()::S where T end ==> (function (where (:: (call f) S) T) (block))
2123+
#
2124+
# Ugly cases for compat where extra parentheses existed and we've
2125+
# already parsed at least the call part of the signature
2126+
#
2127+
# function (f() where T) end ==> (function (where (call f) T) (block))
2128+
# function (f()) where T end ==> (function (where (call f) T) (block))
2129+
# function (f() where T) where U end ==> (function (where (where (call f) T) U) (block))
2130+
# function (f()::S) end ==> (function (:: (call f) S) (block))
2131+
# function ((f()::S) where T) end ==> (function (where (:: (call f) S) T) (block))
2132+
#
2133+
# TODO: Warn for use of parens? The precedence of `::` and
2134+
# `where` don't work inside parens so this is a bit of a syntax
2135+
# oddity/aberration.
21322136
return true
21332137
end
21342138

test/parser.jl

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,6 @@ tests = [
459459
"macro (type)(ex) end" => "(macro (call type ex) (block))"
460460
"macro \$f() end" => "(macro (call (\$ f)) (block))"
461461
"macro (\$f)() end" => "(macro (call (\$ f)) (block))"
462-
"function (f() where T) end" => "(function (where (call f) T) (block))" => Expr(:function, Expr(:where, Expr(:call, :f), :T), Expr(:block))
463-
"function (f()::S) end"=> "(function (:: (call f) S) (block))" => Expr(:function, Expr(:(::), Expr(:call, :f), :S), Expr(:block))
464462
"function (x) body end"=> "(function (tuple x) (block body))"
465463
"function (x,y) end" => "(function (tuple x y) (block))"
466464
"function (x=1) end" => "(function (tuple (= x 1)) (block))"
@@ -488,8 +486,17 @@ tests = [
488486
"function f body end" => "(function (error f) (block body))"
489487
"function f()::T end" => "(function (:: (call f) T) (block))"
490488
"function f()::g(T) end" => "(function (:: (call f) (call g T)) (block))"
491-
"function f() where {T} end" => "(function (where (call f) T) (block))"
492-
"function f() where T end" => "(function (where (call f) T) (block))"
489+
"function f() where {T} end" => "(function (where (call f) T) (block))"
490+
"function f() where T end" => "(function (where (call f) T) (block))"
491+
"function f()::S where T end" => "(function (where (:: (call f) S) T) (block))"
492+
# Ugly cases for compat where extra parentheses existed and we've
493+
# already parsed at least the call part of the signature
494+
"function (f() where T) end" => "(function (where (call f) T) (block))" => Expr(:function, Expr(:where, Expr(:call, :f), :T), Expr(:block))
495+
"function (f()) where T end" => "(function (where (call f) T) (block))"
496+
"function (f() where T) where U end" => "(function (where (where (call f) T) U) (block))"
497+
"function (f()::S) end"=> "(function (:: (call f) S) (block))" => Expr(:function, Expr(:(::), Expr(:call, :f), :S), Expr(:block))
498+
"function ((f()::S) where T) end" => "(function (where (:: (call f) S) T) (block))"
499+
# body
493500
"function f() \n a \n b end" => "(function (call f) (block a b))"
494501
"function f() end" => "(function (call f) (block))"
495502
# Errors

0 commit comments

Comments
 (0)