From 4046ff57f67dbca3a58ed2c9dedfff741f4db1f2 Mon Sep 17 00:00:00 2001 From: Miran Date: Thu, 3 Dec 2020 17:34:30 +0100 Subject: [PATCH] add support for parsing chars in `scanf` macro (#16240) --- changelog.md | 4 ++++ lib/pure/parseutils.nim | 4 ++++ lib/pure/strscans.nim | 7 +++++++ tests/stdlib/tstrscans.nim | 19 ++++++++++++++++++- 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 5b22a174b5d77..05958118bcb1f 100644 --- a/changelog.md +++ b/changelog.md @@ -52,6 +52,9 @@ - `writeStackTrace` is available in JS backend now. +- `strscans.scanf` now supports parsing single characters. + + ## Language changes - `nimscript` now handles `except Exception as e`. @@ -60,6 +63,7 @@ - nil dereference is not allowed at compile time. `cast[ptr int](nil)[]` is rejected at compile time. + ## Compiler changes - Added `--declaredlocs` to show symbol declaration location in messages. diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 29159816d9184..ccfac2a7e820f 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -241,6 +241,10 @@ proc parseIdent*(s: string, start = 0): string = while i < s.len and s[i] in IdentChars: inc(i) result = substr(s, start, i-1) +proc parseChar*(s: string, ident: var char, start = 0): int = + ident = s[start] + result = 1 + proc skipWhitespace*(s: string, start = 0): int {.inline.} = ## Skips the whitespace starting at ``s[start]``. Returns the number of ## skipped characters. diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index f7032f428fba8..347dbc2efb781 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -37,6 +37,7 @@ substrings starting with ``$``. These constructions are available: ``$h`` Matches a hex integer. This uses ``parseutils.parseHex``. ``$f`` Matches a floating pointer number. Uses ``parseFloat``. ``$w`` Matches an ASCII identifier: ``[A-Za-z_][A-Za-z_0-9]*``. +``$c`` Matches a single ASCII character. ``$s`` Skips optional whitespace. ``$$`` Matches a single dollar sign. ``$.`` Matches if the end of the input string has been reached. @@ -345,6 +346,12 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b else: matchError inc i + of 'c': + if i < results.len and getType(results[i]).typeKind == ntyChar: + matchBind "parseChar" + else: + matchError + inc i of 'b': if i < results.len and getType(results[i]).typeKind == ntyInt: matchBind "parseBin" diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim index 9d6f51025d6ec..8ca167837e3ca 100644 --- a/tests/stdlib/tstrscans.nim +++ b/tests/stdlib/tstrscans.nim @@ -2,7 +2,7 @@ discard """ output: "" """ -import strscans +import strscans, strutils block ParsePasswd: proc parsePasswd(content: string): seq[string] = @@ -210,3 +210,20 @@ block: var a: int discard scanf(test(), ",$i", a) doAssert count == 1 + + +block: + let input = """1-3 s: abc +15-18 9: def +15-18 A: ghi +15-18 _: jkl +""" + var + lo, hi: int + w: string + c: char + res: int + for line in input.splitLines: + if line.scanf("$i-$i $c: $w", lo, hi, c, w): + inc res + doAssert res == 4