Fix error lexer error messages for to large numbers (#10394)
This commit is contained in:
parent
5491f40d54
commit
9a003bae06
2 changed files with 43 additions and 32 deletions
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
|
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
|
||||||
wordrecg, lineinfos, pathutils
|
wordrecg, lineinfos, pathutils, parseutils
|
||||||
|
|
||||||
const
|
const
|
||||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
MaxLineLength* = 80 # lines longer than this lead to a warning
|
||||||
|
|
@ -307,20 +307,6 @@ template tokenEndPrevious(tok, pos) =
|
||||||
when defined(nimpretty):
|
when defined(nimpretty):
|
||||||
tok.offsetB = L.offsetBase + pos
|
tok.offsetB = L.offsetBase + pos
|
||||||
|
|
||||||
{.push overflowChecks: off.}
|
|
||||||
# We need to parse the largest uint literal without overflow checks
|
|
||||||
proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
|
|
||||||
var i = start
|
|
||||||
if i < s.len and s[i] in {'0'..'9'}:
|
|
||||||
b = 0
|
|
||||||
while i < s.len and s[i] in {'0'..'9'}:
|
|
||||||
b = b * 10 + (ord(s[i]) - ord('0'))
|
|
||||||
inc(i)
|
|
||||||
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
|
||||||
result = i - start
|
|
||||||
{.pop.} # overflowChecks
|
|
||||||
|
|
||||||
|
|
||||||
template eatChar(L: var TLexer, t: var TToken, replacementChar: char) =
|
template eatChar(L: var TLexer, t: var TToken, replacementChar: char) =
|
||||||
add(t.literal, replacementChar)
|
add(t.literal, replacementChar)
|
||||||
inc(L.bufpos)
|
inc(L.bufpos)
|
||||||
|
|
@ -586,33 +572,43 @@ proc getNumber(L: var TLexer, result: var TToken) =
|
||||||
of floatTypes:
|
of floatTypes:
|
||||||
result.fNumber = parseFloat(result.literal)
|
result.fNumber = parseFloat(result.literal)
|
||||||
of tkUint64Lit:
|
of tkUint64Lit:
|
||||||
xi = 0
|
var iNumber: uint64
|
||||||
let len = unsafeParseUInt(result.literal, xi)
|
var len: int
|
||||||
if len != result.literal.len or len == 0:
|
try:
|
||||||
raise newException(ValueError, "invalid integer: " & $xi)
|
len = parseBiggestUInt(result.literal, iNumber)
|
||||||
result.iNumber = xi
|
except ValueError:
|
||||||
|
raise newException(OverflowError, "number out of range: " & $result.literal)
|
||||||
|
if len != result.literal.len:
|
||||||
|
raise newException(ValueError, "invalid integer: " & $result.literal)
|
||||||
|
result.iNumber = cast[int64](iNumber)
|
||||||
else:
|
else:
|
||||||
result.iNumber = parseBiggestInt(result.literal)
|
var iNumber: int64
|
||||||
|
var len: int
|
||||||
|
try:
|
||||||
|
len = parseBiggestInt(result.literal, iNumber)
|
||||||
|
except ValueError:
|
||||||
|
raise newException(OverflowError, "number out of range: " & $result.literal)
|
||||||
|
if len != result.literal.len:
|
||||||
|
raise newException(ValueError, "invalid integer: " & $result.literal)
|
||||||
|
result.iNumber = iNumber
|
||||||
|
|
||||||
# Explicit bounds checks
|
# Explicit bounds checks. Only T.high needs to be considered
|
||||||
|
# since result.iNumber can't be negative.
|
||||||
let outOfRange =
|
let outOfRange =
|
||||||
case result.tokType
|
case result.tokType
|
||||||
of tkInt8Lit: (result.iNumber < int8.low or result.iNumber > int8.high)
|
of tkInt8Lit: result.iNumber > int8.high
|
||||||
of tkUInt8Lit: (result.iNumber < BiggestInt(uint8.low) or
|
of tkUInt8Lit: result.iNumber > BiggestInt(uint8.high)
|
||||||
result.iNumber > BiggestInt(uint8.high))
|
of tkInt16Lit: result.iNumber > int16.high
|
||||||
of tkInt16Lit: (result.iNumber < int16.low or result.iNumber > int16.high)
|
of tkUInt16Lit: result.iNumber > BiggestInt(uint16.high)
|
||||||
of tkUInt16Lit: (result.iNumber < BiggestInt(uint16.low) or
|
of tkInt32Lit: result.iNumber > int32.high
|
||||||
result.iNumber > BiggestInt(uint16.high))
|
of tkUInt32Lit: result.iNumber > BiggestInt(uint32.high)
|
||||||
of tkInt32Lit: (result.iNumber < int32.low or result.iNumber > int32.high)
|
|
||||||
of tkUInt32Lit: (result.iNumber < BiggestInt(uint32.low) or
|
|
||||||
result.iNumber > BiggestInt(uint32.high))
|
|
||||||
else: false
|
else: false
|
||||||
|
|
||||||
if outOfRange: lexMessageLitNum(L, "number out of range: '$1'", startpos)
|
if outOfRange: lexMessageLitNum(L, "number out of range: '$1'", startpos)
|
||||||
|
|
||||||
# Promote int literal to int64? Not always necessary, but more consistent
|
# Promote int literal to int64? Not always necessary, but more consistent
|
||||||
if result.tokType == tkIntLit:
|
if result.tokType == tkIntLit:
|
||||||
if (result.iNumber < low(int32)) or (result.iNumber > high(int32)):
|
if result.iNumber > high(int32):
|
||||||
result.tokType = tkInt64Lit
|
result.tokType = tkInt64Lit
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|
|
||||||
15
tests/errmsgs/tinteger_literals.nim
Normal file
15
tests/errmsgs/tinteger_literals.nim
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
discard """
|
||||||
|
cmd: "nim check $file"
|
||||||
|
errormsg: "number out of range: '300'u8'"
|
||||||
|
nimout: '''
|
||||||
|
tinteger_literals.nim(12, 9) Error: number out of range: '18446744073709551616'u64'
|
||||||
|
tinteger_literals.nim(13, 9) Error: number out of range: '9223372036854775808'i64'
|
||||||
|
tinteger_literals.nim(14, 9) Error: number out of range: '9223372036854775808'
|
||||||
|
tinteger_literals.nim(15, 9) Error: number out of range: '300'u8'
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
discard 18446744073709551616'u64 # high(uint64) + 1
|
||||||
|
discard 9223372036854775808'i64 # high(int64) + 1
|
||||||
|
discard 9223372036854775808 # high(int64) + 1
|
||||||
|
discard 300'u8
|
||||||
Loading…
Add table
Add a link
Reference in a new issue