Repository: JuliaLang/julia
File: JuliaSyntax/src/julia/parser.jl (Julia)

Code before:
            # between
            # * The function name in parens, followed by (args...)
            # * An anonymous function argument list in parens
            # * The whole function declaration, in parens
            bump(ps, TRIVIA_FLAG)
            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)
                _maybe_grouping_parens = !had_commas && !had_splat && num_semis == 0 && num_subexprs == 1
                # Skip intervening newlines only when the parentheses hold a single
                # expression, which is the ambiguous case between a name like (::T)
                # and an anonymous function parameter list.
                next_kind = peek(ps, 2, skip_newlines=_maybe_grouping_parens)
                _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 = _maybe_grouping_parens)
            end
            is_anon_func = opts.is_anon_func
            parsed_call = opts.parsed_call
            needs_parse_call = opts.needs_parse_call
            if is_anon_func
                # function (x) body end ==>  (function (tuple-p x) (block body))
                # function (x::f()) end ==>  (function (tuple-p (::-i x (call f))) (block))
                # function (x,y) end    ==>  (function (tuple-p x y) (block))
                # function (x=1) end    ==>  (function (tuple-p (= x 1)) (block))
                # function (;x=1) end   ==>  (function (tuple-p (parameters (= x 1))) (block))
                # function (f(x),) end  ==>  (function (tuple-p (call f x)) (block))
                ambiguous_parens = opts.maybe_grouping_parens &&
                                   peek_behind(ps).kind in KSet"macrocall $"
                emit(ps, mark, K"tuple", PARENS_FLAG|opts.delim_flags)
                if ambiguous_parens
                    # Got something like `(@f(x))`. Is it anon `(@f(x),)` or named sig `@f(x)` ??
                    emit(ps, mark, K"error", error="Ambiguous signature. Add a trailing comma if this is a 1-argument anonymous function; remove parentheses if this is a macro call acting as function signature.")
                end
            elseif is_empty_tuple
                # Weird case which is consistent with parse_paren but will be
                # rejected in lowering
                # function ()(x) end  ==> (function (call (tuple-p) x) (block))
                emit(ps, mark, K"tuple", PARENS_FLAG)
            else
                # function (A).f() end  ==> (function (call (. (parens A) f)) (block))
                # function (:)() end    ==> (function (call (parens :)) (block))
                # function (x::T)() end ==> (function (call (parens (::-i x T))) (block))
                # function (::T)() end  ==> (function (call (parens (::-pre T))) (block))
                # function (:*=(f))() end  ==> (function (call (parens (call (quote-: *=) f))) (block))
                emit(ps, mark, K"parens", PARENS_FLAG)
            end

Review comment (suggestion):
I think it would make a lot of sense to split the logic with a case distinction on `_maybe_grouping_parens`:

```suggestion
                next_kind = if _maybe_grouping_parens
                    # 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
                    # Get the next significant token to determine if we need to parse a call
                    peek(ps, 2, skip_newlines= token_after_paren != K"NewlineWs")
                else
                    # Get the next significant token to determine if we need to parse a call
                    peek(ps, 2, skip_newlines=false)
                end
```

Code after:
            # between
            # * The function name in parens, followed by (args...)
            # * An anonymous function argument list in parens
            # * The whole function declaration, in parens
            bump(ps, TRIVIA_FLAG)
            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)
                _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 = _maybe_grouping_parens)
            end
            is_anon_func = opts.is_anon_func
            parsed_call = opts.parsed_call
            needs_parse_call = opts.needs_parse_call
            if is_anon_func
                # function (x) body end ==>  (function (tuple-p x) (block body))
                # function (x::f()) end ==>  (function (tuple-p (::-i x (call f))) (block))
                # function (x,y) end    ==>  (function (tuple-p x y) (block))
                # function (x=1) end    ==>  (function (tuple-p (= x 1)) (block))
                # function (;x=1) end   ==>  (function (tuple-p (parameters (= x 1))) (block))
                # function (f(x),) end  ==>  (function (tuple-p (call f x)) (block))
                ambiguous_parens = opts.maybe_grouping_parens &&
                                   peek_behind(ps).kind in KSet"macrocall $"
                emit(ps, mark, K"tuple", PARENS_FLAG|opts.delim_flags)
                if ambiguous_parens
                    # Got something like `(@f(x))`. Is it anon `(@f(x),)` or named sig `@f(x)` ??
                    emit(ps, mark, K"error", error="Ambiguous signature. Add a trailing comma if this is a 1-argument anonymous function; remove parentheses if this is a macro call acting as function signature.")
                end