Skip to content

multiline ternary operator fails to parse with : on second line #62477

Description

@rokke-git

if you have the : of ?: on the second line, it fails to parse correctly:

julia> true ? 1
            : 2
ERROR: ParseError:
# Error @ REPL[166]:1:9
true ? 1
#       └ ── `:` expected in `?` expression
Stacktrace:
 [1] top-level scope
   @ REPL:1

julia> Meta.@lower(true ? 1
                        : 2)
:($(Expr(:thunk, CodeInfo(
1 ─     goto #3 if not true
2return 1
3return 2
))))

this doesn't matter for simple expressions like this, but kinda hurts when you need readable nested if statements:

julia> function divrem(x::Integer, y::Integer, rnd::typeof(RoundNearest))  # parse error
           (q, r) = divrem(x, y)
           parity = isodd(y) | iseven(q)
           x >= 0 ? y >= 0 ? r >=        (y÷2) + parity ? (q+true, r-y) : (q, r)
                           : r >=       -(y÷2) + parity ? (q-true, r+y) : (q, r)
                  : y >= 0 ? r <= -signed(y÷2) - parity ? (q-true, r+y) : (q, r)
                           : r <=        (y÷2) - parity ? (q+true, r-y) : (q, r)
       end

julia> function divrem(x::Integer, y::Integer, rnd::typeof(RoundNearest))  # workaround
           (q, r) = divrem(x, y)
           parity = isodd(y) | iseven(q)
           (
           x >= 0 ? y >= 0 ? r >=        (y÷2) + parity ? (q+true, r-y) : (q, r)
                           : r >=       -(y÷2) + parity ? (q-true, r+y) : (q, r)
                  : y >= 0 ? r <= -signed(y÷2) - parity ? (q-true, r+y) : (q, r)
                           : r <=        (y÷2) - parity ? (q+true, r-y) : (q, r)
           )
       end

julia> function divrem(x::Integer, y::Integer, rnd::typeof(RoundNearest))  # alternate workaround, harder to read
           (q, r) = divrem(x, y)
           parity = isodd(y) | iseven(q)
           x >= 0 ? y >= 0 ? r >=        (y÷2) + parity ? (q+true, r-y) : (q, r) :
                             r >=       -(y÷2) + parity ? (q-true, r+y) : (q, r) :
                    y >= 0 ? r <= -signed(y÷2) - parity ? (q-true, r+y) : (q, r) :
                             r <=        (y÷2) - parity ? (q+true, r-y) : (q, r)
       end

julia> function divrem(x::Integer, y::Integer, rnd::typeof(RoundNearest))  # unreadable abomination from Base
           (q, r) = divrem(x, y)
           if x >= 0
               if y >= 0
                   r >=        (y÷2) + (isodd(y) | iseven(q)) ? (q+true, r-y) : (q, r)
               else
                   r >=       -(y÷2) + (isodd(y) | iseven(q)) ? (q-true, r+y) : (q, r)
               end
           else
               if y >= 0
                   r <= -signed(y÷2) - (isodd(y) | iseven(q)) ? (q-true, r+y) : (q, r)
               else
                   r <=        (y÷2) - (isodd(y) | iseven(q)) ? (q+true, r-y) : (q, r)
               end
           end
       end

julia> function divrem(x::Integer, y::Integer, rnd::typeof(RoundNearest))  # trololololol
           if x >= 0
               if y >= 0
                   if r >= (y÷2) + (isodd(y) | iseven(q))
                       divrem(x, y) .+ (true, -y)
                   else
                       divrem(x, y)
                   end
               else
                   if r >= -(y÷2) + (isodd(y) | iseven(q))
                       divrem(x, y) .- (true, -y)
                   else
                       divrem(x, y)
                   end
               end
           else
               if y >= 0
                   if r <= -signed(y÷2) - (isodd(y) | iseven(q))
                       divrem(x, y) .- (true, -y)
                   else
                       divrem(x, y)
                   end
               else
                   if r <= (y÷2) - (isodd(y) | iseven(q))
                       divrem(x, y) .+ (true, -y)
                   else
                       divrem(x, y)
                   end
               end
           end
       end

julia> function divrem(x::Integer, y::Integer, rnd::typeof(RoundNearest))  # also technically equivalent
           if x >= 0
               if y >= 0
                   if r >= (y÷2) + (isodd(y) | iseven(q))
                       divrem(x, y) .+ (true, -y)
                   else
                       divrem(x, y)
                   end
               elseif r >= -(y÷2) + (isodd(y) | iseven(q))
                   divrem(x, y) .- (true, -y)
               else
                   divrem(x, y)
               end
           elseif y >= 0
               if r <= -signed(y÷2) - (isodd(y) | iseven(q))
                   divrem(x, y) .- (true, -y)
               else
                   divrem(x, y)
               end
           elseif r <= (y÷2) - (isodd(y) | iseven(q))
               divrem(x, y) .+ (true, -y)
           else
               divrem(x, y)
           end
       end

(those (y÷2)'s should prob all be (y÷0x2)'s so that it doesn't need to cast y for the division, but that's a totally different tangent)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions