Added 'openArray[char]' overloads to 'std/parseutils' (#20527)
* Added 'openarray[char]' overloads to 'std/parseutils' * Removed redundant `start` and `last` params from slice using procs * Fixed type for parseIdent overload * fixed one by off with 'substr' * removed missed start parameters for procedures * Added 'openarray[char]' overloads to 'std/parseutils' * Removed redundant `start` and `last` params from slice using procs * Fixed type for parseIdent overload * fixed one by off with 'substr' * removed missed start parameters for procedures * Fixed VM op to work with new 'opcSlice' * Corrected captureBetween's logic to work with openarray * js sys's parsefloat logic now uses openarray Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
This commit is contained in:
parent
eed1b6df20
commit
ea0e45e62f
8 changed files with 550 additions and 162 deletions
|
|
@ -134,6 +134,7 @@
|
||||||
`toggleAttribute`, and `matches` to `std/dom`.
|
`toggleAttribute`, and `matches` to `std/dom`.
|
||||||
- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices)
|
- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices)
|
||||||
- Added `capacity` for `string` and `seq` to return the current capacity, see https://github.com/nim-lang/RFCs/issues/460
|
- Added `capacity` for `string` and `seq` to return the current capacity, see https://github.com/nim-lang/RFCs/issues/460
|
||||||
|
- Added `openArray[char]` overloads for `std/parseutils` allowing more code reuse.
|
||||||
- Added `safe` parameter to `base64.encodeMime`
|
- Added `safe` parameter to `base64.encodeMime`
|
||||||
|
|
||||||
[//]: # "Deprecations:"
|
[//]: # "Deprecations:"
|
||||||
|
|
|
||||||
|
|
@ -1308,15 +1308,32 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||||
regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode))
|
regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode))
|
||||||
of opcParseFloat:
|
of opcParseFloat:
|
||||||
decodeBC(rkInt)
|
decodeBC(rkInt)
|
||||||
inc pc
|
|
||||||
assert c.code[pc].opcode == opcParseFloat
|
|
||||||
let rd = c.code[pc].regA
|
|
||||||
var rcAddr = addr(regs[rc])
|
var rcAddr = addr(regs[rc])
|
||||||
if rcAddr.kind == rkRegisterAddr: rcAddr = rcAddr.regAddr
|
if rcAddr.kind == rkRegisterAddr: rcAddr = rcAddr.regAddr
|
||||||
elif regs[rc].kind != rkFloat:
|
elif regs[rc].kind != rkFloat:
|
||||||
regs[rc] = TFullReg(kind: rkFloat)
|
regs[rc] = TFullReg(kind: rkFloat)
|
||||||
regs[ra].intVal = parseBiggestFloat(regs[rb].node.strVal,
|
|
||||||
rcAddr.floatVal, regs[rd].intVal.int)
|
let coll = regs[rb].node
|
||||||
|
|
||||||
|
case coll.kind
|
||||||
|
of nkTupleConstr:
|
||||||
|
let
|
||||||
|
data = coll[0]
|
||||||
|
left = coll[1].intVal
|
||||||
|
right = coll[2].intVal
|
||||||
|
case data.kind
|
||||||
|
of nkStrKinds:
|
||||||
|
regs[ra].intVal = parseBiggestFloat(data.strVal.toOpenArray(int left, int right), rcAddr.floatVal)
|
||||||
|
of nkBracket:
|
||||||
|
var s = newStringOfCap(right - left + 1)
|
||||||
|
for i in left..right:
|
||||||
|
s.add char data[int i].intVal
|
||||||
|
regs[ra].intVal = parseBiggestFloat(s, rcAddr.floatVal)
|
||||||
|
else:
|
||||||
|
internalError(c.config, c.debug[pc], "opcParseFloat: Incorrectly created openarray")
|
||||||
|
else:
|
||||||
|
regs[ra].intVal = parseBiggestFloat(regs[ra].node.strVal, rcAddr.floatVal)
|
||||||
|
|
||||||
of opcRangeChck:
|
of opcRangeChck:
|
||||||
let rb = instr.regB
|
let rb = instr.regB
|
||||||
let rc = instr.regC
|
let rc = instr.regC
|
||||||
|
|
|
||||||
|
|
@ -1189,11 +1189,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||||
d2 = c.genx(d2AsNode)
|
d2 = c.genx(d2AsNode)
|
||||||
var
|
var
|
||||||
tmp1 = c.genx(n[1])
|
tmp1 = c.genx(n[1])
|
||||||
tmp3 = c.genx(n[3])
|
|
||||||
c.gABC(n, opcParseFloat, dest, tmp1, d2)
|
c.gABC(n, opcParseFloat, dest, tmp1, d2)
|
||||||
c.gABC(n, opcParseFloat, tmp3)
|
|
||||||
c.freeTemp(tmp1)
|
c.freeTemp(tmp1)
|
||||||
c.freeTemp(tmp3)
|
|
||||||
c.genAsgnPatch(d2AsNode, d2)
|
c.genAsgnPatch(d2AsNode, d2)
|
||||||
c.freeTemp(d2)
|
c.freeTemp(d2)
|
||||||
of mReset:
|
of mReset:
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@
|
||||||
|
|
||||||
include "system/inclrtl"
|
include "system/inclrtl"
|
||||||
|
|
||||||
|
template toOa(s: string): openArray[char] = openArray[char](s)
|
||||||
|
|
||||||
const
|
const
|
||||||
Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
|
Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
|
||||||
IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
|
IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
|
||||||
|
|
@ -59,8 +61,7 @@ const
|
||||||
proc toLower(c: char): char {.inline.} =
|
proc toLower(c: char): char {.inline.} =
|
||||||
result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c
|
result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c
|
||||||
|
|
||||||
proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0,
|
proc parseBin*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): int {.noSideEffect.} =
|
||||||
maxLen = 0): int {.noSideEffect.} =
|
|
||||||
## Parses a binary number and stores its value in ``number``.
|
## Parses a binary number and stores its value in ``number``.
|
||||||
##
|
##
|
||||||
## Returns the number of the parsed characters or 0 in case of an error.
|
## Returns the number of the parsed characters or 0 in case of an error.
|
||||||
|
|
@ -89,7 +90,7 @@ proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
var num64: int64
|
var num64: int64
|
||||||
doAssert parseBin("0100111001101001111011010100111001101001", num64) == 40
|
doAssert parseBin("0100111001101001111011010100111001101001", num64) == 40
|
||||||
doAssert num64 == 336784608873
|
doAssert num64 == 336784608873
|
||||||
var i = start
|
var i = 0
|
||||||
var output = T(0)
|
var output = T(0)
|
||||||
var foundDigit = false
|
var foundDigit = false
|
||||||
let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
|
let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
|
||||||
|
|
@ -104,10 +105,9 @@ proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
inc(i)
|
inc(i)
|
||||||
if foundDigit:
|
if foundDigit:
|
||||||
number = output
|
number = output
|
||||||
result = i - start
|
result = i
|
||||||
|
|
||||||
proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0,
|
proc parseOct*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): int {.noSideEffect.} =
|
||||||
maxLen = 0): int {.noSideEffect.} =
|
|
||||||
## Parses an octal number and stores its value in ``number``.
|
## Parses an octal number and stores its value in ``number``.
|
||||||
##
|
##
|
||||||
## Returns the number of the parsed characters or 0 in case of an error.
|
## Returns the number of the parsed characters or 0 in case of an error.
|
||||||
|
|
@ -136,7 +136,7 @@ proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
var num64: int64
|
var num64: int64
|
||||||
doAssert parseOct("2346475523464755", num64) == 16
|
doAssert parseOct("2346475523464755", num64) == 16
|
||||||
doAssert num64 == 86216859871725
|
doAssert num64 == 86216859871725
|
||||||
var i = start
|
var i = 0
|
||||||
var output = T(0)
|
var output = T(0)
|
||||||
var foundDigit = false
|
var foundDigit = false
|
||||||
let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
|
let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
|
||||||
|
|
@ -151,10 +151,9 @@ proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
inc(i)
|
inc(i)
|
||||||
if foundDigit:
|
if foundDigit:
|
||||||
number = output
|
number = output
|
||||||
result = i - start
|
result = i
|
||||||
|
|
||||||
proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0,
|
proc parseHex*[T: SomeInteger](s: openArray[char], number: var T, maxLen = 0): int {.noSideEffect.} =
|
||||||
maxLen = 0): int {.noSideEffect.} =
|
|
||||||
## Parses a hexadecimal number and stores its value in ``number``.
|
## Parses a hexadecimal number and stores its value in ``number``.
|
||||||
##
|
##
|
||||||
## Returns the number of the parsed characters or 0 in case of an error.
|
## Returns the number of the parsed characters or 0 in case of an error.
|
||||||
|
|
@ -184,7 +183,7 @@ proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
var num64: int64
|
var num64: int64
|
||||||
doAssert parseHex("4E69ED4E69ED", num64) == 12
|
doAssert parseHex("4E69ED4E69ED", num64) == 12
|
||||||
doAssert num64 == 86216859871725
|
doAssert num64 == 86216859871725
|
||||||
var i = start
|
var i = 0
|
||||||
var output = T(0)
|
var output = T(0)
|
||||||
var foundDigit = false
|
var foundDigit = false
|
||||||
let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
|
let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
|
||||||
|
|
@ -206,9 +205,9 @@ proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
inc(i)
|
inc(i)
|
||||||
if foundDigit:
|
if foundDigit:
|
||||||
number = output
|
number = output
|
||||||
result = i - start
|
result = i
|
||||||
|
|
||||||
proc parseIdent*(s: string, ident: var string, start = 0): int =
|
proc parseIdent*(s: openArray[char], ident: var string): int =
|
||||||
## Parses an identifier and stores it in ``ident``. Returns
|
## Parses an identifier and stores it in ``ident``. Returns
|
||||||
## the number of the parsed characters or 0 in case of an error.
|
## the number of the parsed characters or 0 in case of an error.
|
||||||
## If error, the value of `ident` is not changed.
|
## If error, the value of `ident` is not changed.
|
||||||
|
|
@ -220,14 +219,14 @@ proc parseIdent*(s: string, ident: var string, start = 0): int =
|
||||||
doAssert res == "ello"
|
doAssert res == "ello"
|
||||||
doAssert parseIdent("Hello World", res, 6) == 5
|
doAssert parseIdent("Hello World", res, 6) == 5
|
||||||
doAssert res == "World"
|
doAssert res == "World"
|
||||||
var i = start
|
var i = 0
|
||||||
if i < s.len and s[i] in IdentStartChars:
|
if i < s.len and s[i] in IdentStartChars:
|
||||||
inc(i)
|
inc(i)
|
||||||
while i < s.len and s[i] in IdentChars: inc(i)
|
while i < s.len and s[i] in IdentChars: inc(i)
|
||||||
ident = substr(s, start, i-1)
|
ident = substr(s.toOpenArray(0, i-1))
|
||||||
result = i-start
|
result = i
|
||||||
|
|
||||||
proc parseIdent*(s: string, start = 0): string =
|
proc parseIdent*(s: openArray[char]): string =
|
||||||
## Parses an identifier and returns it or an empty string in
|
## Parses an identifier and returns it or an empty string in
|
||||||
## case of an error.
|
## case of an error.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
|
|
@ -236,13 +235,13 @@ proc parseIdent*(s: string, start = 0): string =
|
||||||
doAssert parseIdent("Hello World", 5) == ""
|
doAssert parseIdent("Hello World", 5) == ""
|
||||||
doAssert parseIdent("Hello World", 6) == "World"
|
doAssert parseIdent("Hello World", 6) == "World"
|
||||||
result = ""
|
result = ""
|
||||||
var i = start
|
var i = 0
|
||||||
if i < s.len and s[i] in IdentStartChars:
|
if i < s.len and s[i] in IdentStartChars:
|
||||||
inc(i)
|
inc(i)
|
||||||
while i < s.len and s[i] in IdentChars: inc(i)
|
while i < s.len and s[i] in IdentChars: inc(i)
|
||||||
result = substr(s, start, i-1)
|
result = substr(s.toOpenArray(0, i - 1))
|
||||||
|
|
||||||
proc parseChar*(s: string, c: var char, start = 0): int =
|
proc parseChar*(s: openArray[char], c: var char): int =
|
||||||
## Parses a single character, stores it in `c` and returns 1.
|
## Parses a single character, stores it in `c` and returns 1.
|
||||||
## In case of error (if start >= s.len) it returns 0
|
## In case of error (if start >= s.len) it returns 0
|
||||||
## and the value of `c` is unchanged.
|
## and the value of `c` is unchanged.
|
||||||
|
|
@ -252,11 +251,11 @@ proc parseChar*(s: string, c: var char, start = 0): int =
|
||||||
doAssert c == '\0'
|
doAssert c == '\0'
|
||||||
doAssert "nim".parseChar(c, 0) == 1
|
doAssert "nim".parseChar(c, 0) == 1
|
||||||
doAssert c == 'n'
|
doAssert c == 'n'
|
||||||
if start < s.len:
|
if s.len > 0:
|
||||||
c = s[start]
|
c = s[0]
|
||||||
result = 1
|
result = 1
|
||||||
|
|
||||||
proc skipWhitespace*(s: string, start = 0): int {.inline.} =
|
proc skipWhitespace*(s: openArray[char]): int {.inline.} =
|
||||||
## Skips the whitespace starting at ``s[start]``. Returns the number of
|
## Skips the whitespace starting at ``s[start]``. Returns the number of
|
||||||
## skipped characters.
|
## skipped characters.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
|
|
@ -265,9 +264,9 @@ proc skipWhitespace*(s: string, start = 0): int {.inline.} =
|
||||||
doAssert skipWhitespace("Hello World", 5) == 1
|
doAssert skipWhitespace("Hello World", 5) == 1
|
||||||
doAssert skipWhitespace("Hello World", 5) == 2
|
doAssert skipWhitespace("Hello World", 5) == 2
|
||||||
result = 0
|
result = 0
|
||||||
while start+result < s.len and s[start+result] in Whitespace: inc(result)
|
while result < s.len and s[result] in Whitespace: inc(result)
|
||||||
|
|
||||||
proc skip*(s, token: string, start = 0): int {.inline.} =
|
proc skip*(s, token: openArray[char]): int {.inline.} =
|
||||||
## Skips the `token` starting at ``s[start]``. Returns the length of `token`
|
## Skips the `token` starting at ``s[start]``. Returns the length of `token`
|
||||||
## or 0 if there was no `token` at ``s[start]``.
|
## or 0 if there was no `token` at ``s[start]``.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
|
|
@ -277,22 +276,22 @@ proc skip*(s, token: string, start = 0): int {.inline.} =
|
||||||
doAssert skip("CAPlow", "CAP", 0) == 3
|
doAssert skip("CAPlow", "CAP", 0) == 3
|
||||||
doAssert skip("CAPlow", "cap", 0) == 0
|
doAssert skip("CAPlow", "cap", 0) == 0
|
||||||
result = 0
|
result = 0
|
||||||
while start+result < s.len and result < token.len and
|
while result < s.len and result < token.len and
|
||||||
s[result+start] == token[result]:
|
s[result] == token[result]:
|
||||||
inc(result)
|
inc(result)
|
||||||
if result != token.len: result = 0
|
if result != token.len: result = 0
|
||||||
|
|
||||||
proc skipIgnoreCase*(s, token: string, start = 0): int =
|
proc skipIgnoreCase*(s, token: openArray[char]): int =
|
||||||
## Same as `skip` but case is ignored for token matching.
|
## Same as `skip` but case is ignored for token matching.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3
|
doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3
|
||||||
doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3
|
doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3
|
||||||
result = 0
|
result = 0
|
||||||
while start+result < s.len and result < token.len and
|
while result < s.len and result < token.len and
|
||||||
toLower(s[result+start]) == toLower(token[result]): inc(result)
|
toLower(s[result]) == toLower(token[result]): inc(result)
|
||||||
if result != token.len: result = 0
|
if result != token.len: result = 0
|
||||||
|
|
||||||
proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} =
|
proc skipUntil*(s: openArray[char], until: set[char]): int {.inline.} =
|
||||||
## Skips all characters until one char from the set `until` is found
|
## Skips all characters until one char from the set `until` is found
|
||||||
## or the end is reached.
|
## or the end is reached.
|
||||||
## Returns number of characters skipped.
|
## Returns number of characters skipped.
|
||||||
|
|
@ -301,9 +300,9 @@ proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} =
|
||||||
doAssert skipUntil("Hello World", {'W'}, 0) == 6
|
doAssert skipUntil("Hello World", {'W'}, 0) == 6
|
||||||
doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6
|
doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6
|
||||||
result = 0
|
result = 0
|
||||||
while start+result < s.len and s[result+start] notin until: inc(result)
|
while result < s.len and s[result] notin until: inc(result)
|
||||||
|
|
||||||
proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
|
proc skipUntil*(s: openArray[char], until: char): int {.inline.} =
|
||||||
## Skips all characters until the char `until` is found
|
## Skips all characters until the char `until` is found
|
||||||
## or the end is reached.
|
## or the end is reached.
|
||||||
## Returns number of characters skipped.
|
## Returns number of characters skipped.
|
||||||
|
|
@ -313,9 +312,9 @@ proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
|
||||||
doAssert skipUntil("Hello World", 'W', 0) == 6
|
doAssert skipUntil("Hello World", 'W', 0) == 6
|
||||||
doAssert skipUntil("Hello World", 'w', 0) == 11
|
doAssert skipUntil("Hello World", 'w', 0) == 11
|
||||||
result = 0
|
result = 0
|
||||||
while start+result < s.len and s[result+start] != until: inc(result)
|
while result < s.len and s[result] != until: inc(result)
|
||||||
|
|
||||||
proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
|
proc skipWhile*(s: openArray[char], toSkip: set[char]): int {.inline.} =
|
||||||
## Skips all characters while one char from the set `toSkip` is found.
|
## Skips all characters while one char from the set `toSkip` is found.
|
||||||
## Returns number of characters skipped.
|
## Returns number of characters skipped.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
|
|
@ -323,14 +322,13 @@ proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
|
||||||
doAssert skipWhile("Hello World", {'e'}) == 0
|
doAssert skipWhile("Hello World", {'e'}) == 0
|
||||||
doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3
|
doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3
|
||||||
result = 0
|
result = 0
|
||||||
while start+result < s.len and s[result+start] in toSkip: inc(result)
|
while result < s.len and s[result] in toSkip: inc(result)
|
||||||
|
|
||||||
proc fastSubstr(s: string; token: var string; start, length: int) =
|
proc fastSubstr(s: openArray[char]; token: var string; length: int) =
|
||||||
token.setLen length
|
token.setLen length
|
||||||
for i in 0 ..< length: token[i] = s[i+start]
|
for i in 0 ..< length: token[i] = s[i]
|
||||||
|
|
||||||
proc parseUntil*(s: string, token: var string, until: set[char],
|
proc parseUntil*(s: openArray[char], token: var string, until: set[char]): int {.inline.} =
|
||||||
start = 0): int {.inline.} =
|
|
||||||
## Parses a token and stores it in ``token``. Returns
|
## Parses a token and stores it in ``token``. Returns
|
||||||
## the number of the parsed characters or 0 in case of an error. A token
|
## the number of the parsed characters or 0 in case of an error. A token
|
||||||
## consists of the characters notin `until`.
|
## consists of the characters notin `until`.
|
||||||
|
|
@ -342,14 +340,13 @@ proc parseUntil*(s: string, token: var string, until: set[char],
|
||||||
doAssert myToken == "Hello "
|
doAssert myToken == "Hello "
|
||||||
doAssert parseUntil("Hello World", myToken, {'W', 'r'}, 3) == 3
|
doAssert parseUntil("Hello World", myToken, {'W', 'r'}, 3) == 3
|
||||||
doAssert myToken == "lo "
|
doAssert myToken == "lo "
|
||||||
var i = start
|
var i = 0
|
||||||
while i < s.len and s[i] notin until: inc(i)
|
while i < s.len and s[i] notin until: inc(i)
|
||||||
result = i-start
|
result = i
|
||||||
fastSubstr(s, token, start, result)
|
fastSubstr(s, token, result)
|
||||||
#token = substr(s, start, i-1)
|
#token = substr(s, start, i-1)
|
||||||
|
|
||||||
proc parseUntil*(s: string, token: var string, until: char,
|
proc parseUntil*(s: openArray[char], token: var string, until: char): int {.inline.} =
|
||||||
start = 0): int {.inline.} =
|
|
||||||
## Parses a token and stores it in ``token``. Returns
|
## Parses a token and stores it in ``token``. Returns
|
||||||
## the number of the parsed characters or 0 in case of an error. A token
|
## the number of the parsed characters or 0 in case of an error. A token
|
||||||
## consists of any character that is not the `until` character.
|
## consists of any character that is not the `until` character.
|
||||||
|
|
@ -361,14 +358,13 @@ proc parseUntil*(s: string, token: var string, until: char,
|
||||||
doAssert myToken == "Hell"
|
doAssert myToken == "Hell"
|
||||||
doAssert parseUntil("Hello World", myToken, 'o', 2) == 2
|
doAssert parseUntil("Hello World", myToken, 'o', 2) == 2
|
||||||
doAssert myToken == "ll"
|
doAssert myToken == "ll"
|
||||||
var i = start
|
var i = 0
|
||||||
while i < s.len and s[i] != until: inc(i)
|
while i < s.len and s[i] != until: inc(i)
|
||||||
result = i-start
|
result = i
|
||||||
fastSubstr(s, token, start, result)
|
fastSubstr(s, token, result)
|
||||||
#token = substr(s, start, i-1)
|
#token = substr(s, start, i-1)
|
||||||
|
|
||||||
proc parseUntil*(s: string, token: var string, until: string,
|
proc parseUntil*(s: openArray[char], token: var string, until: string): int {.inline.} =
|
||||||
start = 0): int {.inline.} =
|
|
||||||
## Parses a token and stores it in ``token``. Returns
|
## Parses a token and stores it in ``token``. Returns
|
||||||
## the number of the parsed characters or 0 in case of an error. A token
|
## the number of the parsed characters or 0 in case of an error. A token
|
||||||
## consists of any character that comes before the `until` token.
|
## consists of any character that comes before the `until` token.
|
||||||
|
|
@ -382,7 +378,7 @@ proc parseUntil*(s: string, token: var string, until: string,
|
||||||
if until.len == 0:
|
if until.len == 0:
|
||||||
token.setLen(0)
|
token.setLen(0)
|
||||||
return 0
|
return 0
|
||||||
var i = start
|
var i = 0
|
||||||
while i < s.len:
|
while i < s.len:
|
||||||
if until.len > 0 and s[i] == until[0]:
|
if until.len > 0 and s[i] == until[0]:
|
||||||
var u = 1
|
var u = 1
|
||||||
|
|
@ -390,12 +386,11 @@ proc parseUntil*(s: string, token: var string, until: string,
|
||||||
inc u
|
inc u
|
||||||
if u >= until.len: break
|
if u >= until.len: break
|
||||||
inc(i)
|
inc(i)
|
||||||
result = i-start
|
result = i
|
||||||
fastSubstr(s, token, start, result)
|
fastSubstr(s, token, result)
|
||||||
#token = substr(s, start, i-1)
|
#token = substr(s, start, i-1)
|
||||||
|
|
||||||
proc parseWhile*(s: string, token: var string, validChars: set[char],
|
proc parseWhile*(s: openArray[char], token: var string, validChars: set[char]): int {.inline.} =
|
||||||
start = 0): int {.inline.} =
|
|
||||||
## Parses a token and stores it in ``token``. Returns
|
## Parses a token and stores it in ``token``. Returns
|
||||||
## the number of the parsed characters or 0 in case of an error. A token
|
## the number of the parsed characters or 0 in case of an error. A token
|
||||||
## consists of the characters in `validChars`.
|
## consists of the characters in `validChars`.
|
||||||
|
|
@ -405,22 +400,22 @@ proc parseWhile*(s: string, token: var string, validChars: set[char],
|
||||||
doAssert myToken.len() == 0
|
doAssert myToken.len() == 0
|
||||||
doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 6) == 3
|
doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 6) == 3
|
||||||
doAssert myToken == "Wor"
|
doAssert myToken == "Wor"
|
||||||
var i = start
|
var i = 0
|
||||||
while i < s.len and s[i] in validChars: inc(i)
|
while i < s.len and s[i] in validChars: inc(i)
|
||||||
result = i-start
|
result = i
|
||||||
fastSubstr(s, token, start, result)
|
fastSubstr(s, token, result)
|
||||||
#token = substr(s, start, i-1)
|
#token = substr(s, start, i-1)
|
||||||
|
|
||||||
proc captureBetween*(s: string, first: char, second = '\0', start = 0): string =
|
proc captureBetween*(s: openArray[char], first: char, second = '\0'): string =
|
||||||
## Finds the first occurrence of ``first``, then returns everything from there
|
## Finds the first occurrence of ``first``, then returns everything from there
|
||||||
## up to ``second`` (if ``second`` is '\0', then ``first`` is used).
|
## up to ``second`` (if ``second`` is '\0', then ``first`` is used).
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssert captureBetween("Hello World", 'e') == "llo World"
|
doAssert captureBetween("Hello World", 'e') == "llo World"
|
||||||
doAssert captureBetween("Hello World", 'e', 'r') == "llo Wo"
|
doAssert captureBetween("Hello World", 'e', 'r') == "llo Wo"
|
||||||
doAssert captureBetween("Hello World", 'l', start = 6) == "d"
|
doAssert captureBetween("Hello World".toOpenArray(6, "Hello World".high), 'l') == "d"
|
||||||
var i = skipUntil(s, first, start)+1+start
|
var i = skipUntil(s, first) + 1
|
||||||
result = ""
|
result = ""
|
||||||
discard s.parseUntil(result, if second == '\0': first else: second, i)
|
discard parseUntil(s.toOpenArray(i, s.high), result, if second == '\0': first else: second)
|
||||||
|
|
||||||
proc integerOutOfRangeError() {.noinline.} =
|
proc integerOutOfRangeError() {.noinline.} =
|
||||||
raise newException(ValueError, "Parsed integer outside of valid range")
|
raise newException(ValueError, "Parsed integer outside of valid range")
|
||||||
|
|
@ -429,10 +424,10 @@ proc integerOutOfRangeError() {.noinline.} =
|
||||||
when defined(js):
|
when defined(js):
|
||||||
{.push overflowChecks: off.}
|
{.push overflowChecks: off.}
|
||||||
|
|
||||||
proc rawParseInt(s: string, b: var BiggestInt, start = 0): int =
|
proc rawParseInt(s: openArray[char], b: var BiggestInt): int =
|
||||||
var
|
var
|
||||||
sign: BiggestInt = -1
|
sign: BiggestInt = -1
|
||||||
i = start
|
i = 0
|
||||||
if i < s.len:
|
if i < s.len:
|
||||||
if s[i] == '+': inc(i)
|
if s[i] == '+': inc(i)
|
||||||
elif s[i] == '-':
|
elif s[i] == '-':
|
||||||
|
|
@ -452,30 +447,30 @@ proc rawParseInt(s: string, b: var BiggestInt, start = 0): int =
|
||||||
integerOutOfRangeError()
|
integerOutOfRangeError()
|
||||||
else:
|
else:
|
||||||
b = b * sign
|
b = b * sign
|
||||||
result = i - start
|
result = i
|
||||||
|
|
||||||
when defined(js):
|
when defined(js):
|
||||||
{.pop.} # overflowChecks: off
|
{.pop.} # overflowChecks: off
|
||||||
|
|
||||||
proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.
|
proc parseBiggestInt*(s: openArray[char], number: var BiggestInt): int {.
|
||||||
rtl, extern: "npuParseBiggestInt", noSideEffect, raises: [ValueError].} =
|
rtl, extern: "npuParseBiggestInt", noSideEffect, raises: [ValueError].} =
|
||||||
## Parses an integer starting at `start` and stores the value into `number`.
|
## Parses an integer and stores the value into `number`.
|
||||||
## Result is the number of processed chars or 0 if there is no integer.
|
## Result is the number of processed chars or 0 if there is no integer.
|
||||||
## `ValueError` is raised if the parsed integer is out of the valid range.
|
## `ValueError` is raised if the parsed integer is out of the valid range.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
var res: BiggestInt
|
var res: BiggestInt
|
||||||
doAssert parseBiggestInt("9223372036854775807", res, 0) == 19
|
doAssert parseBiggestInt("9223372036854775807", res) == 19
|
||||||
doAssert res == 9223372036854775807
|
doAssert res == 9223372036854775807
|
||||||
var res = BiggestInt(0)
|
var res = BiggestInt(0)
|
||||||
# use 'res' for exception safety (don't write to 'number' in case of an
|
# use 'res' for exception safety (don't write to 'number' in case of an
|
||||||
# overflow exception):
|
# overflow exception):
|
||||||
result = rawParseInt(s, res, start)
|
result = rawParseInt(s, res)
|
||||||
if result != 0:
|
if result != 0:
|
||||||
number = res
|
number = res
|
||||||
|
|
||||||
proc parseInt*(s: string, number: var int, start = 0): int {.
|
proc parseInt*(s: openArray[char], number: var int): int {.
|
||||||
rtl, extern: "npuParseInt", noSideEffect, raises: [ValueError].} =
|
rtl, extern: "npuParseInt", noSideEffect, raises: [ValueError].} =
|
||||||
## Parses an integer starting at `start` and stores the value into `number`.
|
## Parses an integer and stores the value into `number`.
|
||||||
## Result is the number of processed chars or 0 if there is no integer.
|
## Result is the number of processed chars or 0 if there is no integer.
|
||||||
## `ValueError` is raised if the parsed integer is out of the valid range.
|
## `ValueError` is raised if the parsed integer is out of the valid range.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
|
|
@ -485,14 +480,14 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
|
||||||
doAssert parseInt("2019", res, 2) == 2
|
doAssert parseInt("2019", res, 2) == 2
|
||||||
doAssert res == 19
|
doAssert res == 19
|
||||||
var res = BiggestInt(0)
|
var res = BiggestInt(0)
|
||||||
result = parseBiggestInt(s, res, start)
|
result = parseBiggestInt(s, res)
|
||||||
when sizeof(int) <= 4:
|
when sizeof(int) <= 4:
|
||||||
if res < low(int) or res > high(int):
|
if res < low(int) or res > high(int):
|
||||||
integerOutOfRangeError()
|
integerOutOfRangeError()
|
||||||
if result != 0:
|
if result != 0:
|
||||||
number = int(res)
|
number = int(res)
|
||||||
|
|
||||||
proc parseSaturatedNatural*(s: string, b: var int, start = 0): int {.
|
proc parseSaturatedNatural*(s: openArray[char], b: var int): int {.
|
||||||
raises: [].} =
|
raises: [].} =
|
||||||
## Parses a natural number into ``b``. This cannot raise an overflow
|
## Parses a natural number into ``b``. This cannot raise an overflow
|
||||||
## error. ``high(int)`` is returned for an overflow.
|
## error. ``high(int)`` is returned for an overflow.
|
||||||
|
|
@ -502,7 +497,7 @@ proc parseSaturatedNatural*(s: string, b: var int, start = 0): int {.
|
||||||
var res = 0
|
var res = 0
|
||||||
discard parseSaturatedNatural("848", res)
|
discard parseSaturatedNatural("848", res)
|
||||||
doAssert res == 848
|
doAssert res == 848
|
||||||
var i = start
|
var i = 0
|
||||||
if i < s.len and s[i] == '+': inc(i)
|
if i < s.len and s[i] == '+': inc(i)
|
||||||
if i < s.len and s[i] in {'0'..'9'}:
|
if i < s.len and s[i] in {'0'..'9'}:
|
||||||
b = 0
|
b = 0
|
||||||
|
|
@ -514,13 +509,13 @@ proc parseSaturatedNatural*(s: string, b: var int, start = 0): int {.
|
||||||
b = high(int)
|
b = high(int)
|
||||||
inc(i)
|
inc(i)
|
||||||
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||||
result = i - start
|
result = i
|
||||||
|
|
||||||
proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int =
|
proc rawParseUInt(s: openArray[char], b: var BiggestUInt): int =
|
||||||
var
|
var
|
||||||
res = 0.BiggestUInt
|
res = 0.BiggestUInt
|
||||||
prev = 0.BiggestUInt
|
prev = 0.BiggestUInt
|
||||||
i = start
|
i = 0
|
||||||
if i < s.len - 1 and s[i] == '-' and s[i + 1] in {'0'..'9'}:
|
if i < s.len - 1 and s[i] == '-' and s[i + 1] in {'0'..'9'}:
|
||||||
integerOutOfRangeError()
|
integerOutOfRangeError()
|
||||||
if i < s.len and s[i] == '+': inc(i) # Allow
|
if i < s.len and s[i] == '+': inc(i) # Allow
|
||||||
|
|
@ -534,11 +529,11 @@ proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int =
|
||||||
inc(i)
|
inc(i)
|
||||||
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||||
b = res
|
b = res
|
||||||
result = i - start
|
result = i
|
||||||
|
|
||||||
proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {.
|
proc parseBiggestUInt*(s: openArray[char], number: var BiggestUInt): int {.
|
||||||
rtl, extern: "npuParseBiggestUInt", noSideEffect, raises: [ValueError].} =
|
rtl, extern: "npuParseBiggestUInt", noSideEffect, raises: [ValueError].} =
|
||||||
## Parses an unsigned integer starting at `start` and stores the value
|
## Parses an unsigned integer and stores the value
|
||||||
## into `number`.
|
## into `number`.
|
||||||
## `ValueError` is raised if the parsed integer is out of the valid range.
|
## `ValueError` is raised if the parsed integer is out of the valid range.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
|
|
@ -550,13 +545,13 @@ proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {.
|
||||||
var res = BiggestUInt(0)
|
var res = BiggestUInt(0)
|
||||||
# use 'res' for exception safety (don't write to 'number' in case of an
|
# use 'res' for exception safety (don't write to 'number' in case of an
|
||||||
# overflow exception):
|
# overflow exception):
|
||||||
result = rawParseUInt(s, res, start)
|
result = rawParseUInt(s, res)
|
||||||
if result != 0:
|
if result != 0:
|
||||||
number = res
|
number = res
|
||||||
|
|
||||||
proc parseUInt*(s: string, number: var uint, start = 0): int {.
|
proc parseUInt*(s: openArray[char], number: var uint): int {.
|
||||||
rtl, extern: "npuParseUInt", noSideEffect, raises: [ValueError].} =
|
rtl, extern: "npuParseUInt", noSideEffect, raises: [ValueError].} =
|
||||||
## Parses an unsigned integer starting at `start` and stores the value
|
## Parses an unsigned integer and stores the value
|
||||||
## into `number`.
|
## into `number`.
|
||||||
## `ValueError` is raised if the parsed integer is out of the valid range.
|
## `ValueError` is raised if the parsed integer is out of the valid range.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
|
|
@ -566,22 +561,22 @@ proc parseUInt*(s: string, number: var uint, start = 0): int {.
|
||||||
doAssert parseUInt("3450", res, 2) == 2
|
doAssert parseUInt("3450", res, 2) == 2
|
||||||
doAssert res == 50
|
doAssert res == 50
|
||||||
var res = BiggestUInt(0)
|
var res = BiggestUInt(0)
|
||||||
result = parseBiggestUInt(s, res, start)
|
result = parseBiggestUInt(s, res)
|
||||||
when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4:
|
when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4:
|
||||||
if res > 0xFFFF_FFFF'u64:
|
if res > 0xFFFF_FFFF'u64:
|
||||||
integerOutOfRangeError()
|
integerOutOfRangeError()
|
||||||
if result != 0:
|
if result != 0:
|
||||||
number = uint(res)
|
number = uint(res)
|
||||||
|
|
||||||
proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.
|
proc parseBiggestFloat*(s: openArray[char], number: var BiggestFloat): int {.
|
||||||
magic: "ParseBiggestFloat", importc: "nimParseBiggestFloat", noSideEffect.}
|
magic: "ParseBiggestFloat", importc: "nimParseBiggestFloat", noSideEffect.}
|
||||||
## Parses a float starting at `start` and stores the value into `number`.
|
## Parses a float and stores the value into `number`.
|
||||||
## Result is the number of processed chars or 0 if a parsing error
|
## Result is the number of processed chars or 0 if a parsing error
|
||||||
## occurred.
|
## occurred.
|
||||||
|
|
||||||
proc parseFloat*(s: string, number: var float, start = 0): int {.
|
proc parseFloat*(s: openArray[char], number: var float): int {.
|
||||||
rtl, extern: "npuParseFloat", noSideEffect.} =
|
rtl, extern: "npuParseFloat", noSideEffect.} =
|
||||||
## Parses a float starting at `start` and stores the value into `number`.
|
## Parses a float and stores the value into `number`.
|
||||||
## Result is the number of processed chars or 0 if there occurred a parsing
|
## Result is the number of processed chars or 0 if there occurred a parsing
|
||||||
## error.
|
## error.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
|
|
@ -593,7 +588,7 @@ proc parseFloat*(s: string, number: var float, start = 0): int {.
|
||||||
doAssert parseFloat("32.57", res, 3) == 2
|
doAssert parseFloat("32.57", res, 3) == 2
|
||||||
doAssert res == 57.00
|
doAssert res == 57.00
|
||||||
var bf = BiggestFloat(0.0)
|
var bf = BiggestFloat(0.0)
|
||||||
result = parseBiggestFloat(s, bf, start)
|
result = parseBiggestFloat(s, bf)
|
||||||
if result != 0:
|
if result != 0:
|
||||||
number = bf
|
number = bf
|
||||||
|
|
||||||
|
|
@ -606,7 +601,7 @@ type
|
||||||
ikVar, ## ``var`` part of the interpolated string
|
ikVar, ## ``var`` part of the interpolated string
|
||||||
ikExpr ## ``expr`` part of the interpolated string
|
ikExpr ## ``expr`` part of the interpolated string
|
||||||
|
|
||||||
iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
|
iterator interpolatedFragments*(s: openArray[char]): tuple[kind: InterpolatedKind,
|
||||||
value: string] =
|
value: string] =
|
||||||
## Tokenizes the string `s` into substrings for interpolation purposes.
|
## Tokenizes the string `s` into substrings for interpolation purposes.
|
||||||
##
|
##
|
||||||
|
|
@ -641,7 +636,7 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
|
||||||
else: discard
|
else: discard
|
||||||
inc j
|
inc j
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Expected closing '}': " & substr(s, i, s.high))
|
"Expected closing '}': " & substr(s.toOpenArray(i, s.high)))
|
||||||
inc i, 2 # skip ${
|
inc i, 2 # skip ${
|
||||||
kind = ikExpr
|
kind = ikExpr
|
||||||
elif j+1 < s.len and s[j+1] in IdentStartChars:
|
elif j+1 < s.len and s[j+1] in IdentStartChars:
|
||||||
|
|
@ -655,15 +650,370 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
|
||||||
kind = ikDollar
|
kind = ikDollar
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Unable to parse a variable name at " & substr(s, i, s.high))
|
"Unable to parse a variable name at " & substr(s.toOpenArray(i, s.high)))
|
||||||
else:
|
else:
|
||||||
while j < s.len and s[j] != '$': inc j
|
while j < s.len and s[j] != '$': inc j
|
||||||
kind = ikStr
|
kind = ikStr
|
||||||
if j > i:
|
if j > i:
|
||||||
# do not copy the trailing } for ikExpr:
|
# do not copy the trailing } for ikExpr:
|
||||||
yield (kind, substr(s, i, j-1-ord(kind == ikExpr)))
|
yield (kind, substr(s.toOpenArray(i, j-1-ord(kind == ikExpr))))
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
i = j
|
i = j
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
|
||||||
|
proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
|
maxLen = 0): int {.noSideEffect.} =
|
||||||
|
## Parses a binary number and stores its value in ``number``.
|
||||||
|
##
|
||||||
|
## Returns the number of the parsed characters or 0 in case of an error.
|
||||||
|
## If error, the value of ``number`` is not changed.
|
||||||
|
##
|
||||||
|
## If ``maxLen == 0``, the parsing continues until the first non-bin character
|
||||||
|
## or to the end of the string. Otherwise, no more than ``maxLen`` characters
|
||||||
|
## are parsed starting from the ``start`` position.
|
||||||
|
##
|
||||||
|
## It does not check for overflow. If the value represented by the string is
|
||||||
|
## too big to fit into ``number``, only the value of last fitting characters
|
||||||
|
## will be stored in ``number`` without producing an error.
|
||||||
|
runnableExamples:
|
||||||
|
var num: int
|
||||||
|
doAssert parseBin("0100_1110_0110_1001_1110_1101", num) == 29
|
||||||
|
doAssert num == 5138925
|
||||||
|
doAssert parseBin("3", num) == 0
|
||||||
|
var num8: int8
|
||||||
|
doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8) == 32
|
||||||
|
doAssert num8 == 0b1110_1101'i8
|
||||||
|
doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8, 3, 9) == 9
|
||||||
|
doAssert num8 == 0b0100_1110'i8
|
||||||
|
var num8u: uint8
|
||||||
|
doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8u) == 32
|
||||||
|
doAssert num8u == 237
|
||||||
|
var num64: int64
|
||||||
|
doAssert parseBin("0100111001101001111011010100111001101001", num64) == 40
|
||||||
|
doAssert num64 == 336784608873
|
||||||
|
parseBin(s.toOpenArray(start, s.high), number, maxLen)
|
||||||
|
|
||||||
|
proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
|
maxLen = 0): int {.noSideEffect.} =
|
||||||
|
## Parses an octal number and stores its value in ``number``.
|
||||||
|
##
|
||||||
|
## Returns the number of the parsed characters or 0 in case of an error.
|
||||||
|
## If error, the value of ``number`` is not changed.
|
||||||
|
##
|
||||||
|
## If ``maxLen == 0``, the parsing continues until the first non-oct character
|
||||||
|
## or to the end of the string. Otherwise, no more than ``maxLen`` characters
|
||||||
|
## are parsed starting from the ``start`` position.
|
||||||
|
##
|
||||||
|
## It does not check for overflow. If the value represented by the string is
|
||||||
|
## too big to fit into ``number``, only the value of last fitting characters
|
||||||
|
## will be stored in ``number`` without producing an error.
|
||||||
|
runnableExamples:
|
||||||
|
var num: int
|
||||||
|
doAssert parseOct("0o23464755", num) == 10
|
||||||
|
doAssert num == 5138925
|
||||||
|
doAssert parseOct("8", num) == 0
|
||||||
|
var num8: int8
|
||||||
|
doAssert parseOct("0o_1464_755", num8) == 11
|
||||||
|
doAssert num8 == -19
|
||||||
|
doAssert parseOct("0o_1464_755", num8, 3, 3) == 3
|
||||||
|
doAssert num8 == 102
|
||||||
|
var num8u: uint8
|
||||||
|
doAssert parseOct("1464755", num8u) == 7
|
||||||
|
doAssert num8u == 237
|
||||||
|
var num64: int64
|
||||||
|
doAssert parseOct("2346475523464755", num64) == 16
|
||||||
|
doAssert num64 == 86216859871725
|
||||||
|
parseOct(s.toOpenArray(start, s.high), number, maxLen)
|
||||||
|
|
||||||
|
proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0,
|
||||||
|
maxLen = 0): int {.noSideEffect.} =
|
||||||
|
## Parses a hexadecimal number and stores its value in ``number``.
|
||||||
|
##
|
||||||
|
## Returns the number of the parsed characters or 0 in case of an error.
|
||||||
|
## If error, the value of ``number`` is not changed.
|
||||||
|
##
|
||||||
|
## If ``maxLen == 0``, the parsing continues until the first non-hex character
|
||||||
|
## or to the end of the string. Otherwise, no more than ``maxLen`` characters
|
||||||
|
## are parsed starting from the ``start`` position.
|
||||||
|
##
|
||||||
|
## It does not check for overflow. If the value represented by the string is
|
||||||
|
## too big to fit into ``number``, only the value of last fitting characters
|
||||||
|
## will be stored in ``number`` without producing an error.
|
||||||
|
runnableExamples:
|
||||||
|
var num: int
|
||||||
|
doAssert parseHex("4E_69_ED", num) == 8
|
||||||
|
doAssert num == 5138925
|
||||||
|
doAssert parseHex("X", num) == 0
|
||||||
|
doAssert parseHex("#ABC", num) == 4
|
||||||
|
var num8: int8
|
||||||
|
doAssert parseHex("0x_4E_69_ED", num8) == 11
|
||||||
|
doAssert num8 == 0xED'i8
|
||||||
|
doAssert parseHex("0x_4E_69_ED", num8, 3, 2) == 2
|
||||||
|
doAssert num8 == 0x4E'i8
|
||||||
|
var num8u: uint8
|
||||||
|
doAssert parseHex("0x_4E_69_ED", num8u) == 11
|
||||||
|
doAssert num8u == 237
|
||||||
|
var num64: int64
|
||||||
|
doAssert parseHex("4E69ED4E69ED", num64) == 12
|
||||||
|
doAssert num64 == 86216859871725
|
||||||
|
parseHex(s.toOpenArray(start, s.high), number, maxLen)
|
||||||
|
|
||||||
|
proc parseIdent*(s: string, ident: var string, start = 0): int =
|
||||||
|
## Parses an identifier and stores it in ``ident``. Returns
|
||||||
|
## the number of the parsed characters or 0 in case of an error.
|
||||||
|
## If error, the value of `ident` is not changed.
|
||||||
|
runnableExamples:
|
||||||
|
var res: string
|
||||||
|
doAssert parseIdent("Hello World", res, 0) == 5
|
||||||
|
doAssert res == "Hello"
|
||||||
|
doAssert parseIdent("Hello World", res, 1) == 4
|
||||||
|
doAssert res == "ello"
|
||||||
|
doAssert parseIdent("Hello World", res, 6) == 5
|
||||||
|
doAssert res == "World"
|
||||||
|
parseIdent(s.toOpenArray(start, s.high), ident)
|
||||||
|
|
||||||
|
proc parseIdent*(s: string, start = 0): string =
|
||||||
|
## Parses an identifier and returns it or an empty string in
|
||||||
|
## case of an error.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert parseIdent("Hello World", 0) == "Hello"
|
||||||
|
doAssert parseIdent("Hello World", 1) == "ello"
|
||||||
|
doAssert parseIdent("Hello World", 5) == ""
|
||||||
|
doAssert parseIdent("Hello World", 6) == "World"
|
||||||
|
parseIdent(s.toOpenArray(start, s.high))
|
||||||
|
|
||||||
|
proc parseChar*(s: string, c: var char, start = 0): int =
|
||||||
|
## Parses a single character, stores it in `c` and returns 1.
|
||||||
|
## In case of error (if start >= s.len) it returns 0
|
||||||
|
## and the value of `c` is unchanged.
|
||||||
|
runnableExamples:
|
||||||
|
var c: char
|
||||||
|
doAssert "nim".parseChar(c, 3) == 0
|
||||||
|
doAssert c == '\0'
|
||||||
|
doAssert "nim".parseChar(c, 0) == 1
|
||||||
|
doAssert c == 'n'
|
||||||
|
parseChar(s.toOpenArray(start, s.high), c)
|
||||||
|
|
||||||
|
proc skipWhitespace*(s: string, start = 0): int {.inline.} =
|
||||||
|
## Skips the whitespace starting at ``s[start]``. Returns the number of
|
||||||
|
## skipped characters.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert skipWhitespace("Hello World", 0) == 0
|
||||||
|
doAssert skipWhitespace(" Hello World", 0) == 1
|
||||||
|
doAssert skipWhitespace("Hello World", 5) == 1
|
||||||
|
doAssert skipWhitespace("Hello World", 5) == 2
|
||||||
|
skipWhitespace(s.toOpenArray(start, s.high))
|
||||||
|
|
||||||
|
proc skip*(s, token: string, start = 0): int {.inline.} =
|
||||||
|
## Skips the `token` starting at ``s[start]``. Returns the length of `token`
|
||||||
|
## or 0 if there was no `token` at ``s[start]``.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert skip("2019-01-22", "2019", 0) == 4
|
||||||
|
doAssert skip("2019-01-22", "19", 0) == 0
|
||||||
|
doAssert skip("2019-01-22", "19", 2) == 2
|
||||||
|
doAssert skip("CAPlow", "CAP", 0) == 3
|
||||||
|
doAssert skip("CAPlow", "cap", 0) == 0
|
||||||
|
skip(s.toOpenArray(start, s.high), token)
|
||||||
|
|
||||||
|
proc skipIgnoreCase*(s, token: string, start = 0): int =
|
||||||
|
## Same as `skip` but case is ignored for token matching.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3
|
||||||
|
doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3
|
||||||
|
skipIgnoreCase(s.toOpenArray(start, s.high), token)
|
||||||
|
|
||||||
|
proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} =
|
||||||
|
## Skips all characters until one char from the set `until` is found
|
||||||
|
## or the end is reached.
|
||||||
|
## Returns number of characters skipped.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert skipUntil("Hello World", {'W', 'e'}, 0) == 1
|
||||||
|
doAssert skipUntil("Hello World", {'W'}, 0) == 6
|
||||||
|
doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6
|
||||||
|
skipUntil(s.toOpenArray(start, s.high), until)
|
||||||
|
|
||||||
|
proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
|
||||||
|
## Skips all characters until the char `until` is found
|
||||||
|
## or the end is reached.
|
||||||
|
## Returns number of characters skipped.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert skipUntil("Hello World", 'o', 0) == 4
|
||||||
|
doAssert skipUntil("Hello World", 'o', 4) == 0
|
||||||
|
doAssert skipUntil("Hello World", 'W', 0) == 6
|
||||||
|
doAssert skipUntil("Hello World", 'w', 0) == 11
|
||||||
|
skipUntil(s.toOpenArray(start, s.high), until)
|
||||||
|
|
||||||
|
proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
|
||||||
|
## Skips all characters while one char from the set `toSkip` is found.
|
||||||
|
## Returns number of characters skipped.
|
||||||
|
runnableExamples:
|
||||||
|
doAssert skipWhile("Hello World", {'H', 'e'}) == 2
|
||||||
|
doAssert skipWhile("Hello World", {'e'}) == 0
|
||||||
|
doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3
|
||||||
|
skipWhile(s.toOpenArray(start, s.high), toSkip)
|
||||||
|
|
||||||
|
proc parseUntil*(s: string, token: var string, until: set[char],
|
||||||
|
start = 0): int {.inline.} =
|
||||||
|
## Parses a token and stores it in ``token``. Returns
|
||||||
|
## the number of the parsed characters or 0 in case of an error. A token
|
||||||
|
## consists of the characters notin `until`.
|
||||||
|
runnableExamples:
|
||||||
|
var myToken: string
|
||||||
|
doAssert parseUntil("Hello World", myToken, {'W', 'o', 'r'}) == 4
|
||||||
|
doAssert myToken == "Hell"
|
||||||
|
doAssert parseUntil("Hello World", myToken, {'W', 'r'}) == 6
|
||||||
|
doAssert myToken == "Hello "
|
||||||
|
doAssert parseUntil("Hello World", myToken, {'W', 'r'}, 3) == 3
|
||||||
|
doAssert myToken == "lo "
|
||||||
|
parseUntil(s.toOpenArray(start, s.high), token, until)
|
||||||
|
|
||||||
|
proc parseUntil*(s: string, token: var string, until: char,
|
||||||
|
start = 0): int {.inline.} =
|
||||||
|
## Parses a token and stores it in ``token``. Returns
|
||||||
|
## the number of the parsed characters or 0 in case of an error. A token
|
||||||
|
## consists of any character that is not the `until` character.
|
||||||
|
runnableExamples:
|
||||||
|
var myToken: string
|
||||||
|
doAssert parseUntil("Hello World", myToken, 'W') == 6
|
||||||
|
doAssert myToken == "Hello "
|
||||||
|
doAssert parseUntil("Hello World", myToken, 'o') == 4
|
||||||
|
doAssert myToken == "Hell"
|
||||||
|
doAssert parseUntil("Hello World", myToken, 'o', 2) == 2
|
||||||
|
doAssert myToken == "ll"
|
||||||
|
parseUntil(s.toOpenArray(start, s.high), token, until)
|
||||||
|
|
||||||
|
proc parseUntil*(s: string, token: var string, until: string,
|
||||||
|
start = 0): int {.inline.} =
|
||||||
|
## Parses a token and stores it in ``token``. Returns
|
||||||
|
## the number of the parsed characters or 0 in case of an error. A token
|
||||||
|
## consists of any character that comes before the `until` token.
|
||||||
|
runnableExamples:
|
||||||
|
var myToken: string
|
||||||
|
doAssert parseUntil("Hello World", myToken, "Wor") == 6
|
||||||
|
doAssert myToken == "Hello "
|
||||||
|
doAssert parseUntil("Hello World", myToken, "Wor", 2) == 4
|
||||||
|
doAssert myToken == "llo "
|
||||||
|
parseUntil(s.toOpenArray(start, s.high), token, until)
|
||||||
|
|
||||||
|
proc parseWhile*(s: string, token: var string, validChars: set[char],
|
||||||
|
start = 0): int {.inline.} =
|
||||||
|
## Parses a token and stores it in ``token``. Returns
|
||||||
|
## the number of the parsed characters or 0 in case of an error. A token
|
||||||
|
## consists of the characters in `validChars`.
|
||||||
|
runnableExamples:
|
||||||
|
var myToken: string
|
||||||
|
doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 0) == 0
|
||||||
|
doAssert myToken.len() == 0
|
||||||
|
doAssert parseWhile("Hello World", myToken, {'W', 'o', 'r'}, 6) == 3
|
||||||
|
doAssert myToken == "Wor"
|
||||||
|
parseWhile(s.toOpenArray(start, s.high), token, validChars)
|
||||||
|
|
||||||
|
proc captureBetween*(s: string, first: char, second = '\0', start = 0): string =
|
||||||
|
## Finds the first occurrence of ``first``, then returns everything from there
|
||||||
|
## up to ``second`` (if ``second`` is '\0', then ``first`` is used).
|
||||||
|
runnableExamples:
|
||||||
|
doAssert captureBetween("Hello World", 'e') == "llo World"
|
||||||
|
doAssert captureBetween("Hello World", 'e', 'r') == "llo Wo"
|
||||||
|
doAssert captureBetween("Hello World", 'l', start = 6) == "d"
|
||||||
|
captureBetween(s.toOpenArray(start, s.high), first, second)
|
||||||
|
|
||||||
|
proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.noSideEffect, raises: [ValueError].} =
|
||||||
|
## Parses an integer starting at `start` and stores the value into `number`.
|
||||||
|
## Result is the number of processed chars or 0 if there is no integer.
|
||||||
|
## `ValueError` is raised if the parsed integer is out of the valid range.
|
||||||
|
runnableExamples:
|
||||||
|
var res: BiggestInt
|
||||||
|
doAssert parseBiggestInt("9223372036854775807", res, 0) == 19
|
||||||
|
doAssert res == 9223372036854775807
|
||||||
|
parseBiggestInt(s.toOpenArray(start, s.high), number)
|
||||||
|
|
||||||
|
proc parseInt*(s: string, number: var int, start = 0): int {.noSideEffect, raises: [ValueError].} =
|
||||||
|
## Parses an integer starting at `start` and stores the value into `number`.
|
||||||
|
## Result is the number of processed chars or 0 if there is no integer.
|
||||||
|
## `ValueError` is raised if the parsed integer is out of the valid range.
|
||||||
|
runnableExamples:
|
||||||
|
var res: int
|
||||||
|
doAssert parseInt("2019", res, 0) == 4
|
||||||
|
doAssert res == 2019
|
||||||
|
doAssert parseInt("2019", res, 2) == 2
|
||||||
|
doAssert res == 19
|
||||||
|
parseInt(s.toOpenArray(start, s.high), number)
|
||||||
|
|
||||||
|
|
||||||
|
proc parseSaturatedNatural*(s: string, b: var int, start = 0): int {.
|
||||||
|
raises: [].} =
|
||||||
|
## Parses a natural number into ``b``. This cannot raise an overflow
|
||||||
|
## error. ``high(int)`` is returned for an overflow.
|
||||||
|
## The number of processed character is returned.
|
||||||
|
## This is usually what you really want to use instead of `parseInt`:idx:.
|
||||||
|
runnableExamples:
|
||||||
|
var res = 0
|
||||||
|
discard parseSaturatedNatural("848", res)
|
||||||
|
doAssert res == 848
|
||||||
|
parseSaturatedNatural(s.toOpenArray(start, s.high), b)
|
||||||
|
|
||||||
|
|
||||||
|
proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {.noSideEffect, raises: [ValueError].} =
|
||||||
|
## Parses an unsigned integer starting at `start` and stores the value
|
||||||
|
## into `number`.
|
||||||
|
## `ValueError` is raised if the parsed integer is out of the valid range.
|
||||||
|
runnableExamples:
|
||||||
|
var res: BiggestUInt
|
||||||
|
doAssert parseBiggestUInt("12", res, 0) == 2
|
||||||
|
doAssert res == 12
|
||||||
|
doAssert parseBiggestUInt("1111111111111111111", res, 0) == 19
|
||||||
|
doAssert res == 1111111111111111111'u64
|
||||||
|
parseBiggestUInt(s.toOpenArray(start, s.high), number)
|
||||||
|
|
||||||
|
proc parseUInt*(s: string, number: var uint, start = 0): int {.noSideEffect, raises: [ValueError].} =
|
||||||
|
## Parses an unsigned integer starting at `start` and stores the value
|
||||||
|
## into `number`.
|
||||||
|
## `ValueError` is raised if the parsed integer is out of the valid range.
|
||||||
|
runnableExamples:
|
||||||
|
var res: uint
|
||||||
|
doAssert parseUInt("3450", res) == 4
|
||||||
|
doAssert res == 3450
|
||||||
|
doAssert parseUInt("3450", res, 2) == 2
|
||||||
|
doAssert res == 50
|
||||||
|
parseUInt(s.toOpenArray(start, s.high), number)
|
||||||
|
|
||||||
|
proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.noSideEffect.} =
|
||||||
|
## Parses a float starting at `start` and stores the value into `number`.
|
||||||
|
## Result is the number of processed chars or 0 if a parsing error
|
||||||
|
## occurred.
|
||||||
|
parseFloat(s.toOpenArray(start, s.high), number)
|
||||||
|
|
||||||
|
proc parseFloat*(s: string, number: var float, start = 0): int {.noSideEffect.} =
|
||||||
|
## Parses a float starting at `start` and stores the value into `number`.
|
||||||
|
## Result is the number of processed chars or 0 if there occurred a parsing
|
||||||
|
## error.
|
||||||
|
runnableExamples:
|
||||||
|
var res: float
|
||||||
|
doAssert parseFloat("32", res, 0) == 2
|
||||||
|
doAssert res == 32.0
|
||||||
|
doAssert parseFloat("32.57", res, 0) == 5
|
||||||
|
doAssert res == 32.57
|
||||||
|
doAssert parseFloat("32.57", res, 3) == 2
|
||||||
|
doAssert res == 57.00
|
||||||
|
parseFloat(s.toOpenArray(start, s.high), number)
|
||||||
|
|
||||||
|
iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
|
||||||
|
value: string] =
|
||||||
|
## Tokenizes the string `s` into substrings for interpolation purposes.
|
||||||
|
##
|
||||||
|
runnableExamples:
|
||||||
|
var outp: seq[tuple[kind: InterpolatedKind, value: string]]
|
||||||
|
for k, v in interpolatedFragments(" $this is ${an example} $$"):
|
||||||
|
outp.add (k, v)
|
||||||
|
doAssert outp == @[(ikStr, " "),
|
||||||
|
(ikVar, "this"),
|
||||||
|
(ikStr, " is "),
|
||||||
|
(ikExpr, "an example"),
|
||||||
|
(ikStr, " "),
|
||||||
|
(ikDollar, "$")]
|
||||||
|
for x in s.toOa.interpolatedFragments:
|
||||||
|
yield x
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2580,7 +2580,19 @@ template once*(body: untyped): untyped =
|
||||||
|
|
||||||
{.pop.} # warning[GcMem]: off, warning[Uninit]: off
|
{.pop.} # warning[GcMem]: off, warning[Uninit]: off
|
||||||
|
|
||||||
proc substr*(s: string, first, last: int): string =
|
proc substr*(s: openArray[char]): string =
|
||||||
|
## Copies a slice of `s` into a new string and returns this new
|
||||||
|
## string.
|
||||||
|
runnableExamples:
|
||||||
|
let a = "abcdefgh"
|
||||||
|
assert a.substr(2, 5) == "cdef"
|
||||||
|
assert a.substr(2) == "cdefgh"
|
||||||
|
assert a.substr(5, 99) == "fgh"
|
||||||
|
result = newString(s.len)
|
||||||
|
for i, ch in s:
|
||||||
|
result[i] = ch
|
||||||
|
|
||||||
|
proc substr*(s: string, first, last: int): string = # A bug with `magic: Slice` requires this to exist this way
|
||||||
## Copies a slice of `s` into a new string and returns this new
|
## Copies a slice of `s` into a new string and returns this new
|
||||||
## string.
|
## string.
|
||||||
##
|
##
|
||||||
|
|
|
||||||
|
|
@ -725,15 +725,20 @@ const
|
||||||
IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
|
IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
|
||||||
|
|
||||||
|
|
||||||
proc parseFloatNative(a: string): float =
|
proc parseFloatNative(a: openarray[char]): float =
|
||||||
let a2 = a.cstring
|
var str = ""
|
||||||
|
for x in a:
|
||||||
|
str.add x
|
||||||
|
|
||||||
|
let cstr = cstring str
|
||||||
|
|
||||||
asm """
|
asm """
|
||||||
`result` = Number(`a2`);
|
`result` = Number(`cstr`);
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start: int): int {.compilerproc.} =
|
proc nimParseBiggestFloat(s: openarray[char], number: var BiggestFloat): int {.compilerproc.} =
|
||||||
var sign: bool
|
var sign: bool
|
||||||
var i = start
|
var i = 0
|
||||||
if s[i] == '+': inc(i)
|
if s[i] == '+': inc(i)
|
||||||
elif s[i] == '-':
|
elif s[i] == '-':
|
||||||
sign = true
|
sign = true
|
||||||
|
|
@ -743,14 +748,14 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start: int): int
|
||||||
if s[i+2] == 'N' or s[i+2] == 'n':
|
if s[i+2] == 'N' or s[i+2] == 'n':
|
||||||
if s[i+3] notin IdentChars:
|
if s[i+3] notin IdentChars:
|
||||||
number = NaN
|
number = NaN
|
||||||
return i+3 - start
|
return i+3
|
||||||
return 0
|
return 0
|
||||||
if s[i] == 'I' or s[i] == 'i':
|
if s[i] == 'I' or s[i] == 'i':
|
||||||
if s[i+1] == 'N' or s[i+1] == 'n':
|
if s[i+1] == 'N' or s[i+1] == 'n':
|
||||||
if s[i+2] == 'F' or s[i+2] == 'f':
|
if s[i+2] == 'F' or s[i+2] == 'f':
|
||||||
if s[i+3] notin IdentChars:
|
if s[i+3] notin IdentChars:
|
||||||
number = if sign: -Inf else: Inf
|
number = if sign: -Inf else: Inf
|
||||||
return i+3 - start
|
return i+3
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
var buf: string
|
var buf: string
|
||||||
|
|
@ -782,7 +787,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start: int): int
|
||||||
addInc()
|
addInc()
|
||||||
eatUnderscores()
|
eatUnderscores()
|
||||||
number = parseFloatNative(buf)
|
number = parseFloatNative(buf)
|
||||||
result = i - start
|
result = i
|
||||||
|
|
||||||
# Workaround for IE, IE up to version 11 lacks 'Math.trunc'. We produce
|
# Workaround for IE, IE up to version 11 lacks 'Math.trunc'. We produce
|
||||||
# 'Math.trunc' for Nim's ``div`` and ``mod`` operators:
|
# 'Math.trunc' for Nim's ``div`` and ``mod`` operators:
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,8 @@ const
|
||||||
when defined(nimHasInvariant):
|
when defined(nimHasInvariant):
|
||||||
{.push staticBoundChecks: off.}
|
{.push staticBoundChecks: off.}
|
||||||
|
|
||||||
proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
proc nimParseBiggestFloat(s: openArray[char], number: var BiggestFloat,
|
||||||
start = 0): int {.compilerproc.} =
|
): int {.compilerproc.} =
|
||||||
# This routine attempt to parse float that can parsed quickly.
|
# This routine attempt to parse float that can parsed quickly.
|
||||||
# i.e. whose integer part can fit inside a 53bits integer.
|
# i.e. whose integer part can fit inside a 53bits integer.
|
||||||
# their real exponent must also be <= 22. If the float doesn't follow
|
# their real exponent must also be <= 22. If the float doesn't follow
|
||||||
|
|
@ -88,7 +88,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||||
# This avoid the problems of decimal character portability.
|
# This avoid the problems of decimal character portability.
|
||||||
# see: http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
# see: http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||||
var
|
var
|
||||||
i = start
|
i = 0
|
||||||
sign = 1.0
|
sign = 1.0
|
||||||
kdigits, fdigits = 0
|
kdigits, fdigits = 0
|
||||||
exponent = 0
|
exponent = 0
|
||||||
|
|
@ -111,7 +111,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||||
if s[i+2] == 'N' or s[i+2] == 'n':
|
if s[i+2] == 'N' or s[i+2] == 'n':
|
||||||
if i+3 >= s.len or s[i+3] notin IdentChars:
|
if i+3 >= s.len or s[i+3] notin IdentChars:
|
||||||
number = NaN
|
number = NaN
|
||||||
return i+3 - start
|
return i+3
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Inf?
|
# Inf?
|
||||||
|
|
@ -120,7 +120,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||||
if s[i+2] == 'F' or s[i+2] == 'f':
|
if s[i+2] == 'F' or s[i+2] == 'f':
|
||||||
if i+3 >= s.len or s[i+3] notin IdentChars:
|
if i+3 >= s.len or s[i+3] notin IdentChars:
|
||||||
number = Inf*sign
|
number = Inf*sign
|
||||||
return i+3 - start
|
return i+3
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if i < s.len and s[i] in {'0'..'9'}:
|
if i < s.len and s[i] in {'0'..'9'}:
|
||||||
|
|
@ -154,8 +154,8 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||||
|
|
||||||
# if has no digits: return error
|
# if has no digits: return error
|
||||||
if kdigits + fdigits <= 0 and
|
if kdigits + fdigits <= 0 and
|
||||||
(i == start or # no char consumed (empty string).
|
(i == 0 or # no char consumed (empty string).
|
||||||
(i == start + 1 and hasSign)): # or only '+' or '-
|
(i == 1 and hasSign)): # or only '+' or '-
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if i+1 < s.len and s[i] in {'e', 'E'}:
|
if i+1 < s.len and s[i] in {'e', 'E'}:
|
||||||
|
|
@ -182,7 +182,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||||
number = 0.0*sign
|
number = 0.0*sign
|
||||||
else:
|
else:
|
||||||
number = Inf*sign
|
number = Inf*sign
|
||||||
return i - start
|
return i
|
||||||
|
|
||||||
# if integer is representable in 53 bits: fast path
|
# if integer is representable in 53 bits: fast path
|
||||||
# max fast path integer is 1<<53 - 1 or 8999999999999999 (16 digits)
|
# max fast path integer is 1<<53 - 1 or 8999999999999999 (16 digits)
|
||||||
|
|
@ -194,14 +194,14 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||||
number = sign * integer.float / powtens[absExponent]
|
number = sign * integer.float / powtens[absExponent]
|
||||||
else:
|
else:
|
||||||
number = sign * integer.float * powtens[absExponent]
|
number = sign * integer.float * powtens[absExponent]
|
||||||
return i - start
|
return i
|
||||||
|
|
||||||
# if exponent is greater try to fit extra exponent above 22 by multiplying
|
# if exponent is greater try to fit extra exponent above 22 by multiplying
|
||||||
# integer part is there is space left.
|
# integer part is there is space left.
|
||||||
let slop = 15 - kdigits - fdigits
|
let slop = 15 - kdigits - fdigits
|
||||||
if absExponent <= 22 + slop and not expNegative:
|
if absExponent <= 22 + slop and not expNegative:
|
||||||
number = sign * integer.float * powtens[slop] * powtens[absExponent-slop]
|
number = sign * integer.float * powtens[slop] * powtens[absExponent-slop]
|
||||||
return i - start
|
return i
|
||||||
|
|
||||||
# if failed: slow path with strtod.
|
# if failed: slow path with strtod.
|
||||||
var t: array[500, char] # flaviu says: 325 is the longest reasonable literal
|
var t: array[500, char] # flaviu says: 325 is the longest reasonable literal
|
||||||
|
|
@ -209,8 +209,8 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||||
let maxlen = t.high - "e+000".len # reserve enough space for exponent
|
let maxlen = t.high - "e+000".len # reserve enough space for exponent
|
||||||
|
|
||||||
let endPos = i
|
let endPos = i
|
||||||
result = endPos - start
|
result = endPos
|
||||||
i = start
|
i = 0
|
||||||
# re-parse without error checking, any error should be handled by the code above.
|
# re-parse without error checking, any error should be handled by the code above.
|
||||||
if i < endPos and s[i] == '.': i.inc
|
if i < endPos and s[i] == '.': i.inc
|
||||||
while i < endPos and s[i] in {'0'..'9','+','-'}:
|
while i < endPos and s[i] in {'0'..'9','+','-'}:
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,59 @@
|
||||||
|
discard """
|
||||||
|
targets: "c cpp"
|
||||||
|
"""
|
||||||
|
|
||||||
import std/[parseutils, sequtils, sugar, formatfloat]
|
import std/[parseutils, sequtils, sugar, formatfloat]
|
||||||
import std/assertions
|
import std/assertions
|
||||||
|
|
||||||
|
proc test() =
|
||||||
|
let input = "$test{} $this is ${an{ example}} "
|
||||||
|
let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"),
|
||||||
|
(ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")]
|
||||||
|
doAssert toSeq(interpolatedFragments(input)) == expected
|
||||||
|
|
||||||
let input = "$test{} $this is ${an{ example}} "
|
var value = 0
|
||||||
let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"),
|
discard parseHex("0x38", value)
|
||||||
(ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")]
|
doAssert value == 56
|
||||||
doAssert toSeq(interpolatedFragments(input)) == expected
|
|
||||||
|
|
||||||
var value = 0
|
value = -1
|
||||||
discard parseHex("0x38", value)
|
doAssert(parseSaturatedNatural("848", value) == 3)
|
||||||
doAssert value == 56
|
doAssert value == 848
|
||||||
|
|
||||||
value = -1
|
value = -1
|
||||||
doAssert(parseSaturatedNatural("848", value) == 3)
|
discard parseSaturatedNatural("84899999999999999999324234243143142342135435342532453", value)
|
||||||
doAssert value == 848
|
doAssert value == high(int)
|
||||||
|
|
||||||
value = -1
|
value = -1
|
||||||
discard parseSaturatedNatural("84899999999999999999324234243143142342135435342532453", value)
|
discard parseSaturatedNatural("9223372036854775808", value)
|
||||||
doAssert value == high(int)
|
doAssert value == high(int)
|
||||||
|
|
||||||
value = -1
|
value = -1
|
||||||
discard parseSaturatedNatural("9223372036854775808", value)
|
discard parseSaturatedNatural("9223372036854775807", value)
|
||||||
doAssert value == high(int)
|
doAssert value == high(int)
|
||||||
|
|
||||||
value = -1
|
value = -1
|
||||||
discard parseSaturatedNatural("9223372036854775807", value)
|
discard parseSaturatedNatural("18446744073709551616", value)
|
||||||
doAssert value == high(int)
|
doAssert value == high(int)
|
||||||
|
|
||||||
value = -1
|
value = -1
|
||||||
discard parseSaturatedNatural("18446744073709551616", value)
|
discard parseSaturatedNatural("18446744073709551615", value)
|
||||||
doAssert value == high(int)
|
doAssert value == high(int)
|
||||||
|
|
||||||
value = -1
|
value = -1
|
||||||
discard parseSaturatedNatural("18446744073709551615", value)
|
doAssert(parseSaturatedNatural("1_000_000", value) == 9)
|
||||||
doAssert value == high(int)
|
doAssert value == 1_000_000
|
||||||
|
|
||||||
value = -1
|
var i64Value: int64
|
||||||
doAssert(parseSaturatedNatural("1_000_000", value) == 9)
|
discard parseBiggestInt("9223372036854775807", i64Value)
|
||||||
doAssert value == 1_000_000
|
doAssert i64Value == 9223372036854775807
|
||||||
|
|
||||||
var i64Value: int64
|
block:
|
||||||
discard parseBiggestInt("9223372036854775807", i64Value)
|
var f: float
|
||||||
doAssert i64Value == 9223372036854775807
|
let res = collect:
|
||||||
|
for x in ["9.123456789012345+","11.123456789012345+","9.123456789012345-","8.123456789012345+","9.12345678901234-","9.123456789012345"]:
|
||||||
block:
|
(parseFloat(x, f, 0), $f)
|
||||||
var f: float
|
doAssert res == @[(17, "9.123456789012344"), (18, "11.123456789012344"),
|
||||||
let res = collect:
|
(17, "9.123456789012344"), (17, "8.123456789012344"),
|
||||||
for x in ["9.123456789012345+","11.123456789012345+","9.123456789012345-","8.123456789012345+","9.12345678901234-","9.123456789012345"]:
|
(16, "9.12345678901234"), (17, "9.123456789012344")]
|
||||||
(parseFloat(x, f, 0), $f)
|
test()
|
||||||
doAssert res == @[(17, "9.123456789012344"), (18, "11.123456789012344"),
|
static: test()
|
||||||
(17, "9.123456789012344"), (17, "8.123456789012344"),
|
|
||||||
(16, "9.12345678901234"), (17, "9.123456789012344")]
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue