Repository: JuliaLang/julia
File: base/parse.jl (Julia)

Code before:
@noinline function _invalid_base(base)
    throw(ArgumentError("invalid base: base must be 2 ≤ base ≤ 62, got $base"))
end

@noinline _invalid_digit(base, char) = throw(ArgumentError("invalid base $base digit $(repr(char))"))

function parse_char(::Type{T}, c::AbstractChar, base::Integer, throw::Bool) where {T <: Integer}
    a::UInt8 = (base <= 36 ? 10 : 36)
    (2 <= base <= 62) || (throw ? _invalid_base(base) : return nothing)
    base = base % UInt8
    codepoint = c > 'z' ? 0xff : UInt8(c)
    d = UInt8('0') ≤ codepoint ≤ UInt8('9') ? codepoint - UInt8('0') :
        UInt8('A') ≤ codepoint ≤ UInt8('Z') ? codepoint - UInt8('A') + UInt8(10) :
        UInt8('a') ≤ codepoint ≤ UInt8('z') ? codepoint - UInt8('a') + a :
        0xff
    d < base || (throw ? _invalid_digit(base, c) : return nothing)
    convert(T, d)::T
end

function parse(::Type{T}, c::AbstractChar; base::Integer=10) where {T <: Integer}
    @inline parse_char(T, c, base, true)
end

function tryparse(::Type{T}, c::AbstractChar; base::Integer=10) where {T <: Integer}
    @inline parse_char(T, c, base, false)
end

function parseint_iterate(s::AbstractString, startpos::Int, endpos::Int)
    (0 < startpos <= endpos) || (return Char(0), 0, 0)
    j = startpos
    c, startpos = iterate(s,startpos)::Tuple{Char, Int}
    c, startpos, j
end

function parseint_preamble(signed::Bool, base::Int, s::AbstractString, startpos::Int, endpos::Int)
    c, i, j = parseint_iterate(s, startpos, endpos)

    while isspace(c)
        c, i, j = parseint_iterate(s,i,endpos)
    end
    (j == 0) && (return 0, 0, 0)

    sgn = 1
    if signed
        if c == '-' || c == '+'
            (c == '-') && (sgn = -1)
            c, i, j = parseint_iterate(s,i,endpos)
        end
    end

    while isspace(c)

Review comment (suggestion):
Consider allowing `parse(Float64, '1')` to work.

I did it like this in my PR:

https://github.com/JuliaLang/julia/blob/48bd70bcd8537043179440779b7b426282ff466d/base/parse.jl#L54-L68

Code after:
@noinline function _invalid_base(base)
    throw(ArgumentError("invalid base: base must be 2 ≤ base ≤ 62, got $base"))
end

@noinline _invalid_digit(base, char) = throw(ArgumentError("invalid base $base digit $(repr(char))"))

function parse_char(::Type{T}, c::AbstractChar, base::Integer, throw::Bool) where T
    a::UInt8 = (base <= 36 ? 10 : 36)
    (2 <= base <= 62) || _invalid_base(base)
    base = base % UInt8
    cp = codepoint(c)
    cp = cp > 0x7a ? 0xff : cp % UInt8
    d = UInt8('0') ≤ cp ≤ UInt8('9') ? cp - UInt8('0') :
        UInt8('A') ≤ cp ≤ UInt8('Z') ? cp - UInt8('A') + UInt8(10) :
        UInt8('a') ≤ cp ≤ UInt8('z') ? cp - UInt8('a') + a :
        0xff
    d < base || (throw ? _invalid_digit(base, c) : return nothing)
    convert(T, d)::T
end

function parse(::Type{T}, c::AbstractChar; base::Integer=10) where {T <: Integer}
    @inline parse_char(T, c, base, true)
end

function tryparse(::Type{T}, c::AbstractChar; base::Integer=10) where {T <: Integer}
    @inline parse_char(T, c, base, false)
end

# For consistency with parse(t, AbstractString), support a `base` argument only when T<:Integer
parse(::Type{T}, c::AbstractChar) where T = @inline parse_char(T, c, 10, true)
tryparse(::Type{T}, c::AbstractChar) where T = @inline parse_char(T, c, 10, false)

function parseint_iterate(s::AbstractString, startpos::Int, endpos::Int)
    (0 < startpos <= endpos) || (return Char(0), 0, 0)
    j = startpos
    c, startpos = iterate(s,startpos)::Tuple{Char, Int}
    c, startpos, j
end

function parseint_preamble(signed::Bool, base::Int, s::AbstractString, startpos::Int, endpos::Int)
    c, i, j = parseint_iterate(s, startpos, endpos)

    while isspace(c)
        c, i, j = parseint_iterate(s,i,endpos)
    end
    (j == 0) && (return 0, 0, 0)

    sgn = 1
    if signed
        if c == '-' || c == '+'
            (c == '-') && (sgn = -1)