summary refs log tree commit diff stats
path: root/lib/pure/parseutils.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/parseutils.nim')
-rw-r--r--lib/pure/parseutils.nim79
1 files changed, 75 insertions, 4 deletions
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index b78e8d000..57387e62e 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -8,6 +8,8 @@
 #
 
 ## This module contains helpers for parsing tokens, numbers, identifiers, etc.
+##
+## To unpack raw bytes look at the `streams <streams.html>`_ module.
 
 {.deadCodeElim: on.}
 
@@ -85,6 +87,23 @@ proc parseOct*(s: string, number: var int, start = 0): int  {.
     inc(i)
   if foundDigit: result = i-start
 
+proc parseBin*(s: string, number: var int, start = 0): int  {.
+  rtl, extern: "npuParseBin", noSideEffect.} =
+  ## parses an binary number and stores its value in ``number``. Returns
+  ## the number of the parsed characters or 0 in case of an error.
+  var i = start
+  var foundDigit = false
+  if s[i] == '0' and (s[i+1] == 'b' or s[i+1] == 'B'): inc(i, 2)
+  while true:
+    case s[i]
+    of '_': discard
+    of '0'..'1':
+      number = number shl 1 or (ord(s[i]) - ord('0'))
+      foundDigit = true
+    else: break
+    inc(i)
+  if foundDigit: result = i-start
+
 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.
@@ -250,6 +269,31 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
   elif result != 0:
     number = int(res)
 
+proc parseSaturatedNatural*(s: string, b: var int, start = 0): int =
+  ## parses a natural number into ``b``. This cannot raise an overflow
+  ## error. Instead of an ``Overflow`` exception ``high(int)`` is returned.
+  ## The number of processed character is returned.
+  ## This is usually what you really want to use instead of `parseInt`:idx:.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var res = 0
+  ##   discard parseSaturatedNatural("848", res)
+  ##   doAssert res == 848
+  var i = start
+  if s[i] == '+': inc(i)
+  if s[i] in {'0'..'9'}:
+    b = 0
+    while s[i] in {'0'..'9'}:
+      let c = ord(s[i]) - ord('0')
+      if b <= (high(int) - c) div 10:
+        b = b * 10 + c
+      else:
+        b = high(int)
+      inc(i)
+      while s[i] == '_': inc(i) # underscores are allowed and ignored
+    result = i - start
+
 # overflowChecks doesn't work with BiggestUInt
 proc rawParseUInt(s: string, b: var BiggestUInt, start = 0): int =
   var
@@ -391,16 +435,43 @@ when isMainModule:
   let input = "$test{}  $this is ${an{  example}}  "
   let expected = @[(ikVar, "test"), (ikStr, "{}  "), (ikVar, "this"),
                    (ikStr, " is "), (ikExpr, "an{  example}"), (ikStr, "  ")]
-  assert toSeq(interpolatedFragments(input)) == expected
+  doAssert toSeq(interpolatedFragments(input)) == expected
 
   var value = 0
   discard parseHex("0x38", value)
-  assert value == 56
+  doAssert value == 56
   discard parseHex("0x34", value)
-  assert value == 56 * 256 + 52
+  doAssert value == 56 * 256 + 52
   value = -1
   discard parseHex("0x38", value)
-  assert value == -200
+  doAssert value == -200
+
+  value = -1
+  doAssert(parseSaturatedNatural("848", value) == 3)
+  doAssert value == 848
+
+  value = -1
+  discard parseSaturatedNatural("84899999999999999999324234243143142342135435342532453", value)
+  doAssert value == high(int)
 
+  value = -1
+  discard parseSaturatedNatural("9223372036854775808", value)
+  doAssert value == high(int)
+
+  value = -1
+  discard parseSaturatedNatural("9223372036854775807", value)
+  doAssert value == high(int)
+
+  value = -1
+  discard parseSaturatedNatural("18446744073709551616", value)
+  doAssert value == high(int)
+
+  value = -1
+  discard parseSaturatedNatural("18446744073709551615", value)
+  doAssert value == high(int)
+
+  value = -1
+  doAssert(parseSaturatedNatural("1_000_000", value) == 9)
+  doAssert value == 1_000_000
 
 {.pop.}