summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMiran <narimiran@disroot.org>2020-12-03 17:34:30 +0100
committerGitHub <noreply@github.com>2020-12-03 17:34:30 +0100
commit2220aaeaef74cb6018f4689af8f280db22cb30dd (patch)
treede6d959299fff78f435a082f4ce3c0b3a5e2a6b5
parent545c406cbeb9d312e29f7363727c0eb9b37b7da7 (diff)
downloadNim-2220aaeaef74cb6018f4689af8f280db22cb30dd.tar.gz
add support for parsing chars in `scanf` macro (#16240)
-rw-r--r--changelog.md4
-rw-r--r--lib/pure/parseutils.nim4
-rw-r--r--lib/pure/strscans.nim7
-rw-r--r--tests/stdlib/tstrscans.nim19
4 files changed, 33 insertions, 1 deletions
diff --git a/changelog.md b/changelog.md
index 5b22a174b..05958118b 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 29159816d..ccfac2a7e 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 f7032f428..347dbc2ef 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 9d6f51025..8ca167837 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