diff options
author | Jason Beetham <beefers331@gmail.com> | 2020-12-12 15:29:20 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-12 23:29:20 +0100 |
commit | 5a58440ebe4ba794f0127ebb6ad33824a92dfb58 (patch) | |
tree | f5eaa0476d456b6efd81c57c65b5adc784a5819a /lib/pure/strscans.nim | |
parent | d15f63a0f2d431a516601530196ac01c26e00f53 (diff) | |
download | Nim-5a58440ebe4ba794f0127ebb6ad33824a92dfb58.tar.gz |
Added strscans.scanTuple (#16300)
* Added since and changelog
Diffstat (limited to 'lib/pure/strscans.nim')
-rw-r--r-- | lib/pure/strscans.nim | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim index 347dbc2ef..9c55bf3e3 100644 --- a/lib/pure/strscans.nim +++ b/lib/pure/strscans.nim @@ -284,6 +284,7 @@ efficiency and perform different checks. import macros, parseutils +import std/private/since proc conditionsToIfChain(n, idx, res: NimNode; start: int): NimNode = assert n.kind == nnkStmtList @@ -465,6 +466,54 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b else: result.add res +macro scanTuple*(input: untyped; pattern: static[string]; matcherTypes: varargs[untyped]): untyped {.since: (1, 5).}= + ## Works identically as scanf, but instead of predeclaring variables it returns a tuple. + ## Tuple is started with a bool which indicates if the scan was successful + ## followed by the requested data. + ## If using a user defined matcher, provide the types in order they appear after pattern: + ## `line.scanTuple("${yourMatcher()}", int)` + runnableExamples: + let (success, year, month, day, time) = scanTuple("1000-01-01 00:00:00", "$i-$i-$i$s$+") + if success: + assert year == 1000 + assert month == 1 + assert day == 1 + assert time == "00:00:00" + var + p = 0 + userMatches = 0 + arguments: seq[NimNode] + result = newStmtList() + template addVar(typ: string) = + let varIdent = ident("temp" & $arguments.len) + result.add(newNimNode(nnkVarSection).add(newIdentDefs(varIdent, ident(typ), newEmptyNode()))) + arguments.add(varIdent) + while p < pattern.len: + if pattern[p] == '$': + inc p + case pattern[p] + of 'w', '*', '+': + addVar("string") + of 'c': + addVar("char") + of 'b', 'o', 'i', 'h': + addVar("int") + of 'f': + addVar("float") + of '{': + if userMatches < matcherTypes.len: + let varIdent = ident("temp" & $arguments.len) + result.add(newNimNode(nnkVarSection).add(newIdentDefs(varIdent, matcherTypes[userMatches], newEmptyNode()))) + arguments.add(varIdent) + inc userMatches + else: discard + inc p + result.add newPar(newCall(ident("scanf"), input, newStrLitNode(pattern))) + for arg in arguments: + result[^1][0].add arg + result[^1].add arg + result = newBlockStmt(result) + template atom*(input: string; idx: int; c: char): bool = ## Used in scanp for the matching of atoms (usually chars). ## EOF is matched as ``'\0'``. @@ -639,4 +688,4 @@ macro scanp*(input, idx: typed; pattern: varargs[untyped]): bool = result.add toIfChain(conds, idx, res, 0) result.add res when defined(debugScanp): - echo repr result + echo repr result \ No newline at end of file |