diff --git a/questionable/indexing.nim b/questionable/indexing.nim index 72e30b7..b170430 100644 --- a/questionable/indexing.nim +++ b/questionable/indexing.nim @@ -1,23 +1,29 @@ import std/macros -macro `.?`*(expression: seq | string | openArray, brackets: untyped{nkBracket}): untyped = +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`]) - - when typeof(`expression`) is openArray: - if `index` >= `expression`.low and `index` <= `expression`.high: - `expression`[`index`].some - else: - T.none + let evaluated = `expression` + if `index` >= evaluated.low and `index` <= evaluated.high: + evaluated[`index`].some else: - let evaluated = `expression` - if `index` >= evaluated.low and `index` <= evaluated.high: - evaluated[`index`].some + T.none + +macro `.?`*(expression: openArray, brackets: untyped{nkBracket}): untyped = + # chain is of shape: openArray.?[index] + let index = brackets[0] + quote do: + block: + type T = typeof(`expression`[`index`]) + proc safeGet(arr: openArray[T], i: int): ?T {.gensym.} = + if i >= arr.low and i <= arr.high: + arr[i].some else: T.none + 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 26d52ff..a6c0e18 100644 --- a/testmodules/options/test.nim +++ b/testmodules/options/test.nim @@ -355,6 +355,11 @@ suite "optionals": 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 check table.?["a"].isSome