From 1f3e1fe758f99f15f547b1dccddf878d58dab0fa Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Sat, 21 Oct 2017 20:55:15 +0100 Subject: Add link to streams module --- lib/pure/parseutils.nim | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/pure/parseutils.nim') diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index b78e8d000..3c790512f 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 `_ module. {.deadCodeElim: on.} -- cgit 1.4.1-2-gfad0 From 55cdaaef6fd9ba3ad039466f7e02407930324404 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 19 Nov 2017 02:57:40 +0100 Subject: added parseutils.parseSaturatedNatural --- changelog.md | 1 + lib/pure/parseutils.nim | 60 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 4 deletions(-) (limited to 'lib/pure/parseutils.nim') diff --git a/changelog.md b/changelog.md index 2e0780220..1b2785a62 100644 --- a/changelog.md +++ b/changelog.md @@ -81,6 +81,7 @@ This now needs to be written as: - Added ``sequtils.mapLiterals`` for easier construction of array and tuple literals. - Added ``macros.isAtomicLit`` predicate. +- Added ``parseutils.parseSaturatedNatural``. - Moved from stdlib into Nimble packages: - [``basic2d``](https://github.com/nim-lang/basic2d) _deprecated: use ``glm``, ``arraymancer``, ``neo``, or another package instead_ diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 3c790512f..a602b0e1b 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -252,6 +252,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 @@ -393,16 +418,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.} -- cgit 1.4.1-2-gfad0 From 6ca563dd2e6380e4e2062b9129f582a4910baf68 Mon Sep 17 00:00:00 2001 From: Dmitry Atamanov Date: Fri, 5 Jan 2018 19:36:56 +0300 Subject: Add a more number parsers to the scanf macro (#6985) --- lib/pure/parseutils.nim | 17 +++++++++++++++++ lib/pure/strscans.nim | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) (limited to 'lib/pure/parseutils.nim') diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index a602b0e1b..57387e62e 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -87,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. diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index f33e7451f..42bb281eb 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -31,7 +31,10 @@ As can be seen from the examples, strings are matched verbatim except for substrings starting with ``$``. These constructions are available: ================= ======================================================== -``$i`` Matches an integer. This uses ``parseutils.parseInt``. +``$b`` Matches an decimal integer. This uses ``parseutils.parseBin``. +``$o`` Matches an octal integer. This uses ``parseutils.parseOct``. +``$i`` Matches an decimal integer. This uses ``parseutils.parseInt``. +``$h`` Matches an hex integer. This uses ``parseutils.parseHex``. ``$f`` Matches a floating pointer number. Uses ``parseFloat``. ``$w`` Matches an ASCII identifier: ``[A-Z-a-z_][A-Za-z_0-9]*``. ``$s`` Skips optional whitespace. @@ -335,11 +338,29 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b else: error("no string var given for $w") inc i + of 'b': + if i < results.len or getType(results[i]).typeKind != ntyInt: + matchBind "parseBin" + else: + error("no int var given for $b") + inc i + of 'o': + if i < results.len or getType(results[i]).typeKind != ntyInt: + matchBind "parseOct" + else: + error("no int var given for $o") + inc i of 'i': if i < results.len or getType(results[i]).typeKind != ntyInt: matchBind "parseInt" else: - error("no int var given for $d") + error("no int var given for $i") + inc i + of 'h': + if i < results.len or getType(results[i]).typeKind != ntyInt: + matchBind "parseHex" + else: + error("no int var given for $h") inc i of 'f': if i < results.len or getType(results[i]).typeKind != ntyFloat: @@ -645,6 +666,14 @@ when isMainModule: doAssert intval == 89 doAssert floatVal == 33.25 + var binval: int + var octval: int + var hexval: int + doAssert scanf("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binval, octval, hexval) + doAssert binval == 0b0101 + doAssert octval == 0o1234 + doAssert hexval == 0xabcd + let xx = scanf("$abc", "$$$i", intval) doAssert xx == false -- cgit 1.4.1-2-gfad0