From 1f0afff48bf80ab1149a0957f9743f345bc14b71 Mon Sep 17 00:00:00 2001 From: Tomasz Bekas Date: Mon, 20 Nov 2023 14:58:49 +0100 Subject: [PATCH] Support for .?[] operator on openArrays (#52) * Support for .?[] operator on openArrays * Operator .?[] evaluates openArray expression only once * Fix for Nim 1.2.x --------- Co-authored-by: Mark Spanbroek --- questionable/indexing.nim | 30 +++++++++++++++++++----------- testmodules/options/test.nim | 17 ++++++++++++++++- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/questionable/indexing.nim b/questionable/indexing.nim index b794b7a..5b80f2d 100644 --- a/questionable/indexing.nim +++ b/questionable/indexing.nim @@ -1,16 +1,24 @@ import std/macros +import std/options -macro `.?`*(expression: seq | string, brackets: untyped{nkBracket}): untyped = - # chain is of shape: (seq or string).?[index] - let index = brackets[0] - quote do: - block: - type T = typeof(`expression`[`index`]) - let evaluated = `expression` - if `index` < evaluated.len: - evaluated[`index`].some - else: - T.none +proc safeGet[T](expression: seq[T] | openArray[T], index: int): Option[T] = + if index >= expression.low and index <= expression.high: + expression[index].some + else: + T.none + +proc safeGet(expression: string, index: int): Option[char] = + if index >= expression.low and index <= expression.high: + expression[index].some + else: + char.none + +macro `.?`*(expression: seq | string | openArray, brackets: untyped{nkBracket}): untyped = + # chain is of shape: (seq or string or openArray).?[index] + let index = brackets[0] + quote do: + block: + safeGet(`expression`, `index`) macro `.?`*(expression: typed, brackets: untyped{nkBracket}): untyped = # chain is of shape: expression.?[index] diff --git a/testmodules/options/test.nim b/testmodules/options/test.nim index 3293e42..a6c0e18 100644 --- a/testmodules/options/test.nim +++ b/testmodules/options/test.nim @@ -337,13 +337,28 @@ suite "optionals": test ".?[] can be used for indexing strings without raising IndexDefect": let str = "a" - check str.?[0] == 'a'.some + check str.?[0] == 'a'.some check str.?[1] == char.none + check str.?[-1] == char.none test ".?[] can be used for indexing sequences without raising IndexDefect": let sequence = @[1] check sequence.?[0] == 1.some check sequence.?[1] == int.none + check sequence.?[-1] == int.none + + test ".?[] can be used for indexing openArrays without raising IndexDefect": + proc checkOpenArray(oa: openArray[int]): void = + check oa.?[0] == 1.some + check oa.?[1] == int.none + check oa.?[-1] == int.none + + checkOpenArray(@[1]) + + test ".?[] evaluates openArray expression only once": + var count = 0 + discard (inc count; @[1].toOpenArray(0, 0)).?[0] + check count == 1 test ".?[] can be followed by calls, operators and indexing": let table = @{"a": @[41, 42]}.toTable