Operator .?[] evaluates openArray expression only once

This commit is contained in:
Mark Spanbroek 2023-11-20 14:26:32 +01:00
parent b4d8327329
commit 48e8fe845f
2 changed files with 21 additions and 10 deletions

View File

@ -1,24 +1,30 @@
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
else:
let evaluated = `expression`
if `index` >= evaluated.low and `index` <= evaluated.high:
evaluated[`index`].some
else:
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]
let index = brackets[0]

View File

@ -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