overflows(::Type{T}) where {T} = true overflows(::Type{BigInt}) = false overflowval(::Type{T}) where {T <: Integer} = div(typemax(T) - T(9), T(10)) # if we eventually support non-base 10 # overflowval(::Type{T}, base) where {T <: Integer} = div(typemax(T) - base + 1, base) @inline function typeparser(::AbstractConf{T}, source, pos, len, b, code, pl, opts) where {T <: Integer} x = zero(T) neg = false has_groupmark = _has_groupmark(opts, code) groupmark0 = something(opts.groupmark, 0xff) - UInt8('0') # start actual int parsing neg = b == UInt8('-') if neg || b == UInt8('+') pos += 1 incr!(source) end if eof(source, pos, len) code |= INVALID | EOF @goto done end b = peekbyte(source, pos) - UInt8('0') if b > 0x09 # character isn't a digit, INVALID value code |= INVALID @goto done end prev_b0 = b while true if b <= 0x09 overflows(T) && x > overflowval(T) && break x = T(10) * x + unsafe_trunc(T, b) pos += 1 incr!(source) if eof(source, pos, len) x = ifelse(neg, -x, x) code |= OK | EOF @goto done end elseif has_groupmark && b == groupmark0 prev_b0 == groupmark0 && (code |= INVALID; @goto done) # two groupmarks in a row pos += 1 Parsers.incr!(source) Parsers.eof(source, pos, len) && (code |= INVALID | EOF; @goto done) # groupmark at end of input else # detected a non-digit, time to bail on value parsing x = ifelse(neg, -x, x) # Cannot end on a groupmark (has_groupmark && prev_b0 == groupmark0) ? (code |= INVALID) : (code |= OK) @goto done end prev_b0 = b b = peekbyte(source, pos) - UInt8('0') end # extra loop because we got too close to overflowing while parsing digits x = ifelse(neg, -x, x) while true if b <= 0x09 x, ov_mul = Base.mul_with_overflow(x, T(10)) x, ov_add = Base.add_with_overflow(x, ifelse(neg, -T(b), T(b))) if ov_mul | ov_add # we overflowed, mark as OVERFLOW code |= OVERFLOW # in this case, we know b is a digit that caused us # to overflow, so we don't really want to consider it for # a close quote character or delimiter, so if b is the last character # let's just bail as eof pos += 1 incr!(source) if eof(source, pos, len) code |= EOF end @goto done end pos += 1 incr!(source) if eof(source, pos, len) code |= OK | EOF @goto done end elseif has_groupmark && b == groupmark0 prev_b0 == groupmark0 && (code |= INVALID; @goto done) # two groupmarks in a row pos += 1 Parsers.incr!(source) Parsers.eof(source, pos, len) && (code |= INVALID | EOF; @goto done) # groupmark at end of input else # detected a non-digit, time to bail on value parsing x = ifelse(neg, -x, x) # Cannot end on a groupmark (has_groupmark && prev_b0 == groupmark0) ? (code |= INVALID) : (code |= OK) @goto done end prev_b0 = b b = peekbyte(source, pos) - UInt8('0') end @label done return pos, code, PosLen(pl.pos, pos - pl.pos), x end @inline function typeparser(::AbstractConf{Number}, source, pos, len, b, code, pl, opts) x = Ref{Number}() pos, code = parsenumber(source, pos, len, b, y -> (x[] = y), opts) return pos, code, PosLen(pl.pos, pos - pl.pos), isdefined(x, :x) ? x[] : (0::Number) end @inline function parsenumber(source, pos, len, b, f::F, opts=OPTIONS) where {F} startpos = pos code = startcode = SUCCESS # begin parsing neg = b == UInt8('-') if neg || b == UInt8('+') pos += 1 incr!(source) end if eof(source, pos, len) code |= INVALID | EOF @goto done end b = peekbyte(source, pos) # parse rest of number _, code, pos = parsedigits(DefaultConf{Number}(), source, pos, len, b, code, OPTIONS, Int64(0), neg, startpos, true, 0, f) if invalid(code) # by default, parsedigits only has up to Float64 precision; if we overflow # let's try BigFloat pos, code, _, x = typeparser(DefaultConf{BigFloat}(), source, startpos, len, b, startcode, poslen(pos, 0), opts) if ok(code) f(x) end end @label done return pos, code end