diff --git a/src/parser.jl b/src/parser.jl index 73ddb5e2..1699033b 100644 --- a/src/parser.jl +++ b/src/parser.jl @@ -2153,13 +2153,31 @@ function parse_function_signature(ps::ParseState, is_function::Bool) is_empty_tuple = peek(ps, skip_newlines=true) == K")" opts = parse_brackets(ps, K")") do had_commas, had_splat, num_semis, num_subexprs _parsed_call = was_eventually_call(ps) - _needs_parse_call = peek(ps, 2) ∈ KSet"( ." + _maybe_grouping_parens = !had_commas && !had_splat && num_semis == 0 && num_subexprs == 1 + # Check if there's a newline between `)` and the next `(` or `.`. + # We need to find where `)` is and check what immediately follows it. + # If peek(1, skip_newlines=false) is `)`, we're directly before it. + # Otherwise there's whitespace/newline before `)`. + next_token_pos = if peek(ps, 1, skip_newlines=false) == K")" + # Directly before ), token after ) is at 2 + 2 + else + # There's whitespace before ), so ) is at 2 + # and what follows ) is at 3 + 3 + end + token_after_paren = peek(ps, next_token_pos, skip_newlines=false) + # If token_after_paren is a newline, this is an anonymous function + has_newline_after_paren = _maybe_grouping_parens && token_after_paren == K"NewlineWs" + # Get the next significant token to determine if we need to parse a call + next_kind = peek(ps, 2, skip_newlines=_maybe_grouping_parens && !has_newline_after_paren) + _needs_parse_call = next_kind ∈ KSet"( ." _is_anon_func = (!_needs_parse_call && !_parsed_call) || had_commas - return (needs_parameters = _is_anon_func, - is_anon_func = _is_anon_func, - parsed_call = _parsed_call, - needs_parse_call = _needs_parse_call, - maybe_grouping_parens = !had_commas && !had_splat && num_semis == 0 && num_subexprs == 1) + return (needs_parameters = _is_anon_func, + is_anon_func = _is_anon_func, + parsed_call = _parsed_call, + needs_parse_call = _needs_parse_call, + maybe_grouping_parens = _maybe_grouping_parens) end::NamedTuple{(:needs_parameters, :is_anon_func, :parsed_call, :needs_parse_call, :maybe_grouping_parens, :delim_flags), Tuple{Bool, Bool, Bool, Bool, Bool, RawFlags}} is_anon_func = opts.is_anon_func diff --git a/test/parser.jl b/test/parser.jl index f208e24c..9723f3cd 100644 --- a/test/parser.jl +++ b/test/parser.jl @@ -594,6 +594,8 @@ tests = [ "macro \$f() end" => "(macro (call (\$ f)) (block))" "macro (\$f)() end" => "(macro (call (parens (\$ f))) (block))" "function (x) body end"=> "(function (tuple-p x) (block body))" + "function (x)\n body\nend" => "(function (tuple-p x) (block body))" + "function (x)\n() end" => "(function (tuple-p x) (block (tuple-p)))" "function (x,y) end" => "(function (tuple-p x y) (block))" "function (x,y,) end" => "(function (tuple-p-, x y) (block))" "function (x=1) end" => "(function (tuple-p (= x 1)) (block))" @@ -610,6 +612,13 @@ tests = [ "function (::g(x))() end" => "(function (call (parens (::-pre (call g x)))) (block))" "function (f::T{g(i)})() end" => "(function (call (parens (::-i f (curly T (call g i))))) (block))" "function (::T)() end" => "(function (call (parens (::-pre T))) (block))" + "function (\n ::T\n )() end" => "(function (call (parens (::-pre T))) (block))" + "function (\n x::T\n )() end" => "(function (call (parens (::-i x T))) (block))" + "function (\n f\n )() end" => "(function (call (parens f)) (block))" + "function (\n A\n ).f() end" => "(function (call (. (parens A) f)) (block))" + "function (\n ::T\n )(x, y) end" => "(function (call (parens (::-pre T)) x y) (block))" + "function (\n f::T{g(i)}\n )() end" => "(function (call (parens (::-i f (curly T (call g i))))) (block))" + "function (\n x, y\n ) x + y end" => "(function (tuple-p x y) (block (call-i x + y)))" "function (:*=(f))() end" => "(function (call (parens (call (quote-: *=) f))) (block))" "function begin() end" => "(function (call (error begin)) (block))" "function f() end" => "(function (call f) (block))"