• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #38162

06 Aug 2025 08:25PM UTC coverage: 25.688% (-43.6%) from 69.336%
#38162

push

local

web-flow
fix runtime cglobal builtin function implementation (#59210)

This had failed to be updated for the LazyLibrary changes to codegen.

12976 of 50513 relevant lines covered (25.69%)

676965.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

31.94
/base/parse.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
import Base.Checked: add_with_overflow, mul_with_overflow
4

5
## string to integer functions ##
6

7
"""
8
    parse(type, str; base)
9

10
Parse a string as a number. For `Integer` types, a base can be specified
11
(the default is 10). For floating-point types, the string is parsed as a decimal
12
floating-point number.  `Complex` types are parsed from decimal strings
13
of the form `"R±Iim"` as a `Complex(R,I)` of the requested type; `"i"` or `"j"` can also be
14
used instead of `"im"`, and `"R"` or `"Iim"` are also permitted.
15
If the string does not contain a valid number, an error is raised.
16

17
!!! compat "Julia 1.1"
18
    `parse(Bool, str)` requires at least Julia 1.1.
19

20
# Examples
21
```jldoctest
22
julia> parse(Int, "1234")
23
1234
24

25
julia> parse(Int, "1234", base = 5)
26
194
27

28
julia> parse(Int, "afc", base = 16)
29
2812
30

31
julia> parse(Float64, "1.2e-3")
32
0.0012
33

34
julia> parse(Complex{Float64}, "3.2e-1 + 4.5im")
35
0.32 + 4.5im
36
```
37
"""
38
parse(T::Type, str; base = Int)
39
parse(::Type{Union{}}, slurp...; kwargs...) = error("cannot parse a value as Union{}")
×
40

41
function parse(::Type{T}, c::AbstractChar; base::Integer = 10) where T<:Integer
×
42
    a::Int = (base <= 36 ? 10 : 36)
×
43
    2 <= base <= 62 || throw(ArgumentError("invalid base: base must be 2 ≤ base ≤ 62, got $base"))
×
44
    d = '0' <= c <= '9' ? c-'0'    :
×
45
        'A' <= c <= 'Z' ? c-'A'+10 :
46
        'a' <= c <= 'z' ? c-'a'+a  : throw(ArgumentError("invalid digit: $(repr(c))"))
47
    d < base || throw(ArgumentError("invalid base $base digit $(repr(c))"))
×
48
    convert(T, d)
×
49
end
50

51
function parseint_iterate(s::AbstractString, startpos::Int, endpos::Int)
52
    (0 < startpos <= endpos) || (return Char(0), 0, 0)
390✔
53
    j = startpos
×
54
    c, startpos = iterate(s,startpos)::Tuple{Char, Int}
760✔
55
    c, startpos, j
×
56
end
57

58
function parseint_preamble(signed::Bool, base::Int, s::AbstractString, startpos::Int, endpos::Int)
193✔
59
    c, i, j = parseint_iterate(s, startpos, endpos)
381✔
60

61
    while isspace(c)
386✔
62
        c, i, j = parseint_iterate(s,i,endpos)
×
63
    end
×
64
    (j == 0) && (return 0, 0, 0)
193✔
65

66
    sgn = 1
188✔
67
    if signed
188✔
68
        if c == '-' || c == '+'
376✔
69
            (c == '-') && (sgn = -1)
×
70
            c, i, j = parseint_iterate(s,i,endpos)
×
71
        end
72
    end
73

74
    while isspace(c)
376✔
75
        c, i, j = parseint_iterate(s,i,endpos)
×
76
    end
×
77
    (j == 0) && (return 0, 0, 0)
188✔
78

79
    if base == 0
188✔
80
        if c == '0' && i <= endpos
188✔
81
            c, i = iterate(s,i)::Tuple{Char, Int}
×
82
            base = c=='b' ? 2 : c=='o' ? 8 : c=='x' ? 16 : 10
×
83
            if base != 10
×
84
                c, i, j = parseint_iterate(s,i,endpos)
×
85
            end
86
        else
87
            base = 10
188✔
88
        end
89
    end
90
    return sgn, base, j
188✔
91
end
92

93
# '0':'9' -> 0:9
94
# 'A':'Z' -> 10:35
95
# 'a':'z' -> 10:35 if base <= 36, 36:61 otherwise
96
# input outside of that is mapped to base
97
@inline function __convert_digit(_c::UInt32, base::UInt32)
98
    _0 = UInt32('0')
×
99
    _9 = UInt32('9')
×
100
    _A = UInt32('A')
×
101
    _a = UInt32('a')
×
102
    _Z = UInt32('Z')
×
103
    _z = UInt32('z')
×
104
    a = base <= 36 ? UInt32(10) : UInt32(36) # converting here instead of via a type assertion prevents typeassert related errors
299✔
105
    d = _0 <= _c <= _9 ? _c-_0             :
20,582✔
106
        _A <= _c <= _Z ? _c-_A+ UInt32(10) :
107
        _a <= _c <= _z ? _c-_a+a           :
108
        base
109
end
110

111

112
function tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::Int, base_::Integer, raise::Bool) where T<:Integer
197✔
113
    sgn, base, i = parseint_preamble(T<:Signed, Int(base_), s, startpos, endpos)
197✔
114
    if sgn == 0 && base == 0 && i == 0
197✔
115
        raise && throw(ArgumentError("input string is empty or only contains whitespace"))
5✔
116
        return nothing
5✔
117
    end
118
    if !(2 <= base <= 62)
192✔
119
        raise && throw(ArgumentError(LazyString("invalid base: base must be 2 ≤ base ≤ 62, got ", base)))
×
120
        return nothing
×
121
    end
122
    if i == 0
192✔
123
        raise && throw(ArgumentError("premature end of integer: $(repr(SubString(s,startpos,endpos)))"))
×
124
        return nothing
×
125
    end
126
    c, i = parseint_iterate(s,i,endpos)
384✔
127
    if i == 0
192✔
128
        raise && throw(ArgumentError("premature end of integer: $(repr(SubString(s,startpos,endpos)))"))
×
129
        return nothing
×
130
    end
131

132
    base = convert(T, base)
192✔
133
    # Special case the common cases of base being 10 or 16 to avoid expensive runtime div
134
    m::T = base == 10 ? div(typemax(T) - T(9), T(10)) :
192✔
135
           base == 16 ? div(typemax(T) - T(15), T(16)) :
136
                        div(typemax(T) - base + 1, base)
137
    n::T = 0
192✔
138
    while n <= m
299✔
139
        # Fast path from `UInt32(::Char)`; non-ascii will be >= 0x80
140
        _c = reinterpret(UInt32, c) >> 24
299✔
141
        d::T = __convert_digit(_c, base % UInt32) # we know 2 <= base <= 62, so prevent an incorrect InexactError here
299✔
142
        if d >= base
299✔
143
            raise && throw(ArgumentError("invalid base $base digit $(repr(c)) in $(repr(SubString(s,startpos,endpos)))"))
×
144
            return nothing
×
145
        end
146
        n *= base
299✔
147
        n += d
299✔
148
        if i > endpos
299✔
149
            n *= sgn
192✔
150
            return n
192✔
151
        end
152
        c, i = iterate(s,i)::Tuple{Char, Int}
214✔
153
        isspace(c) && break
214✔
154
    end
107✔
155
    (T <: Signed) && (n *= sgn)
×
156
    while !isspace(c)
×
157
        # Fast path from `UInt32(::Char)`; non-ascii will be >= 0x80
158
        _c = reinterpret(UInt32, c) >> 24
×
159
        d::T = __convert_digit(_c, base % UInt32) # we know 2 <= base <= 62
×
160
        if d >= base
×
161
            raise && throw(ArgumentError("invalid base $base digit $(repr(c)) in $(repr(SubString(s,startpos,endpos)))"))
×
162
            return nothing
×
163
        end
164
        (T <: Signed) && (d *= sgn)
×
165

166
        n, ov_mul = mul_with_overflow(n, base)
×
167
        n, ov_add = add_with_overflow(n, d)
×
168
        if ov_mul | ov_add
×
169
            raise && throw(OverflowError("overflow parsing $(repr(SubString(s,startpos,endpos)))"))
×
170
            return nothing
×
171
        end
172
        (i > endpos) && return n
×
173
        c, i = iterate(s,i)::Tuple{Char, Int}
×
174
    end
×
175
    while i <= endpos
×
176
        c, i = iterate(s,i)::Tuple{Char, Int}
×
177
        if !isspace(c)
×
178
            raise && throw(ArgumentError("extra characters after whitespace in $(repr(SubString(s,startpos,endpos)))"))
×
179
            return nothing
×
180
        end
181
    end
×
182
    return n
×
183
end
184

185
function tryparse_internal(::Type{Bool}, sbuff::AbstractString,
2✔
186
        startpos::Int, endpos::Int, base::Integer, raise::Bool)
187
    if isempty(sbuff)
2✔
188
        raise && throw(ArgumentError("input string is empty"))
×
189
        return nothing
×
190
    end
191

192
    if isnumeric(sbuff[1])
2✔
193
        intres = tryparse_internal(UInt8, sbuff, startpos, endpos, base, false)
×
194
        (intres == 1) && return true
×
195
        (intres == 0) && return false
×
196
        raise && throw(ArgumentError("invalid Bool representation: $(repr(sbuff))"))
×
197
    end
198

199
    orig_start = startpos
2✔
200
    orig_end   = endpos
2✔
201

202
    # Ignore leading and trailing whitespace
203
    while startpos <= endpos && isspace(sbuff[startpos])
4✔
204
        startpos = nextind(sbuff, startpos)
×
205
    end
×
206
    while endpos >= startpos && isspace(sbuff[endpos])
4✔
207
        endpos = prevind(sbuff, endpos)
×
208
    end
×
209

210
    len = endpos - startpos + 1
2✔
211
    if sbuff isa Union{String, SubString{String}}
2✔
212
        p = pointer(sbuff) + startpos - 1
2✔
213
        truestr = "true"
2✔
214
        falsestr = "false"
2✔
215
        GC.@preserve sbuff truestr falsestr begin
2✔
216
            (len == 4) && (0 == memcmp(p, unsafe_convert(Ptr{UInt8}, truestr), 4)) && (return true)
2✔
217
            (len == 5) && (0 == memcmp(p, unsafe_convert(Ptr{UInt8}, falsestr), 5)) && (return false)
1✔
218
        end
219
    else
220
        (len == 4) && (SubString(sbuff, startpos:startpos+3) == "true") && (return true)
×
221
        (len == 5) && (SubString(sbuff, startpos:startpos+4) == "false") && (return false)
×
222
    end
223

224
    if raise
×
225
        substr = SubString(sbuff, orig_start, orig_end) # show input string in the error to avoid confusion
×
226
        if all(isspace, substr)
×
227
            throw(ArgumentError("input string only contains whitespace"))
×
228
        else
229
            throw(ArgumentError("invalid Bool representation: $(repr(substr))"))
×
230
        end
231
    end
232
    return nothing
×
233
end
234

235
@inline function check_valid_base(base)
236
    if 2 <= base <= 62
×
237
        return base
×
238
    end
239
    throw(ArgumentError("invalid base: base must be 2 ≤ base ≤ 62, got $base"))
×
240
end
241

242
"""
243
    tryparse(type, str; base)
244

245
Like [`parse`](@ref), but returns either a value of the requested type,
246
or [`nothing`](@ref) if the string does not contain a valid number.
247
"""
248
function tryparse(::Type{T}, s::AbstractString; base::Union{Nothing,Integer} = nothing) where {T<:Integer}
247✔
249
    # Zero base means, "figure it out"
250
    tryparse_internal(T, s, firstindex(s), lastindex(s), base===nothing ? 0 : check_valid_base(base), false)
247✔
251
end
252

253
function parse(::Type{T}, s::AbstractString; base::Union{Nothing,Integer} = nothing) where {T<:Integer}
5,683✔
254
    v = tryparse_internal(T, s, firstindex(s), lastindex(s), base===nothing ? 0 : check_valid_base(base), true)
182✔
255
    v === nothing && error("should not happoen")
108✔
256
    convert(T, v)
108✔
257
end
258
tryparse(::Type{Union{}}, slurp...; kwargs...) = error("cannot parse a value as Union{}")
×
259

260
## string to float functions ##
261

262
function tryparse(::Type{Float64}, s::String)
263
    hasvalue, val = ccall(:jl_try_substrtod, Tuple{Bool, Float64},
45✔
264
                          (Ptr{UInt8},Csize_t,Csize_t), s, 0, sizeof(s) % UInt)
265
    hasvalue ? val : nothing
45✔
266
end
267
function tryparse(::Type{Float64}, s::SubString{String})
268
    hasvalue, val = ccall(:jl_try_substrtod, Tuple{Bool, Float64},
×
269
                          (Ptr{UInt8},Csize_t,Csize_t), s.string, s.offset, s.ncodeunits % UInt)
270
    hasvalue ? val : nothing
×
271
end
272
function tryparse_internal(::Type{Float64}, s::String, startpos::Int, endpos::Int)
×
273
    hasvalue, val = ccall(:jl_try_substrtod, Tuple{Bool, Float64},
×
274
                          (Ptr{UInt8},Csize_t,Csize_t), s, startpos-1, endpos-startpos+1)
275
    hasvalue ? val : nothing
×
276
end
277
function tryparse_internal(::Type{Float64}, s::SubString{String}, startpos::Int, endpos::Int)
×
278
    hasvalue, val = ccall(:jl_try_substrtod, Tuple{Bool, Float64},
×
279
                          (Ptr{UInt8},Csize_t,Csize_t), s.string, s.offset+startpos-1, endpos-startpos+1)
280
    hasvalue ? val : nothing
×
281
end
282
function tryparse(::Type{Float32}, s::String)
×
283
    hasvalue, val = ccall(:jl_try_substrtof, Tuple{Bool, Float32},
×
284
                          (Ptr{UInt8},Csize_t,Csize_t), s, 0, sizeof(s) % UInt)
285
    hasvalue ? val : nothing
×
286
end
287
function tryparse(::Type{Float32}, s::SubString{String})
×
288
    hasvalue, val = ccall(:jl_try_substrtof, Tuple{Bool, Float32},
×
289
                          (Ptr{UInt8},Csize_t,Csize_t), s.string, s.offset, s.ncodeunits % UInt)
290
    hasvalue ? val : nothing
×
291
end
292
function tryparse_internal(::Type{Float32}, s::String, startpos::Int, endpos::Int)
×
293
    hasvalue, val = ccall(:jl_try_substrtof, Tuple{Bool, Float32},
×
294
                          (Ptr{UInt8},Csize_t,Csize_t), s, startpos-1, endpos-startpos+1)
295
    hasvalue ? val : nothing
×
296
end
297
function tryparse_internal(::Type{Float32}, s::SubString{String}, startpos::Int, endpos::Int)
×
298
    hasvalue, val = ccall(:jl_try_substrtof, Tuple{Bool, Float32},
×
299
                          (Ptr{UInt8},Csize_t,Csize_t), s.string, s.offset+startpos-1, endpos-startpos+1)
300
    hasvalue ? val : nothing
×
301
end
302
tryparse(::Type{T}, s::AbstractString) where {T<:Union{Float32,Float64}} = tryparse(T, String(s))
×
303
tryparse(::Type{Float16}, s::AbstractString) =
×
304
    convert(Union{Float16, Nothing}, tryparse(Float32, s))
305
tryparse_internal(::Type{Float16}, s::AbstractString, startpos::Int, endpos::Int) =
×
306
    convert(Union{Float16, Nothing}, tryparse_internal(Float32, s, startpos, endpos))
307

308
## string to complex functions ##
309

310
function tryparse_internal(::Type{Complex{T}}, s::Union{String,SubString{String}}, i::Int, e::Int, raise::Bool) where {T<:Real}
×
311
    # skip initial whitespace
312
    while i ≤ e && isspace(s[i])
×
313
        i = nextind(s, i)
×
314
    end
×
315
    if i > e
×
316
        raise && throw(ArgumentError("input string is empty or only contains whitespace"))
×
317
        return nothing
×
318
    end
319

320
    # find index of ± separating real/imaginary parts (if any)
321
    i₊ = something(findnext(in(('+','-')), s, i), 0)
×
322
    if i₊ == i # leading ± sign
×
323
        i₊ = something(findnext(in(('+','-')), s, i₊+1), 0)
×
324
    end
325
    if i₊ != 0 && s[prevind(s, i₊)] in ('e','E') # exponent sign
×
326
        i₊ = something(findnext(in(('+','-')), s, i₊+1), 0)
×
327
    end
328

329
    # find trailing im/i/j
330
    iᵢ = something(findprev(in(('m','i','j')), s, e), 0)
×
331
    if iᵢ > 0 && s[iᵢ] == 'm' # im
×
332
        iᵢ = prevind(s, iᵢ)
×
333
        if s[iᵢ] != 'i'
×
334
            raise && throw(ArgumentError("expected trailing \"im\", found only \"m\""))
×
335
            return nothing
×
336
        end
337
    end
338

339
    if i₊ == 0 # purely real or imaginary value
×
340
        if iᵢ > i && !(iᵢ == i+1 && s[i] in ('+','-')) # purely imaginary (not "±inf")
×
341
            x = tryparse_internal(T, s, i, prevind(s, iᵢ), raise)
×
342
            x === nothing && return nothing
×
343
            return Complex{T}(zero(x),x)
×
344
        else # purely real
345
            x = tryparse_internal(T, s, i, e, raise)
×
346
            x === nothing && return nothing
×
347
            return Complex{T}(x)
×
348
        end
349
    end
350

351
    if iᵢ < i₊
×
352
        raise && throw(ArgumentError("missing imaginary unit"))
×
353
        return nothing # no imaginary part
×
354
    end
355

356
    # parse real part
357
    re = tryparse_internal(T, s, i, prevind(s, i₊), raise)
×
358
    re === nothing && return nothing
×
359

360
    # parse imaginary part
361
    im = tryparse_internal(T, s, i₊+1, prevind(s, iᵢ), raise)
×
362
    im === nothing && return nothing
×
363

364
    return Complex{T}(re, s[i₊]=='-' ? -im : im)
×
365
end
366

367
# the ±1 indexing above for ascii chars is specific to String, so convert:
368
tryparse_internal(T::Type{Complex{S}}, s::AbstractString, i::Int, e::Int, raise::Bool) where S<:Real =
×
369
    tryparse_internal(T, String(s), i, e, raise)
370

371
# fallback methods for tryparse_internal
372
tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::Int) where T<:Real =
×
373
    startpos == firstindex(s) && endpos == lastindex(s) ? tryparse(T, s) : tryparse(T, SubString(s, startpos, endpos))
374
function tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::Int, raise::Bool) where T<:Real
×
375
    result = tryparse_internal(T, s, startpos, endpos)
×
376
    if raise && result === nothing
×
377
        _parse_failure(T, s, startpos, endpos)
×
378
    end
379
    return result
×
380
end
381
function tryparse_internal(::Type{T}, s::AbstractString, raise::Bool; kwargs...) where T<:Real
45✔
382
    result = tryparse(T, s; kwargs...)
45✔
383
    if raise && result === nothing
45✔
384
        _parse_failure(T, s)
×
385
    end
386
    return result
45✔
387
end
388
@noinline _parse_failure(T, s::AbstractString, startpos = firstindex(s), endpos = lastindex(s)) =
×
389
    throw(ArgumentError(LazyString("cannot parse ", repr(s[startpos:endpos]), " as ", T)))
390

391
tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::Int, raise::Bool) where T<:Integer =
×
392
    tryparse_internal(T, s, startpos, endpos, 10, raise)
393

394
parse(::Type{T}, s::AbstractString; kwargs...) where T<:Real =
90✔
395
    convert(T, tryparse_internal(T, s, true; kwargs...))
396
parse(::Type{T}, s::AbstractString) where T<:Complex =
×
397
    convert(T, tryparse_internal(T, s, firstindex(s), lastindex(s), true))
398

399
tryparse(T::Type{Complex{S}}, s::AbstractString) where S<:Real =
×
400
    tryparse_internal(T, s, firstindex(s), lastindex(s), false)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc