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 <mark@spanbroek.net>
This commit is contained in:
Tomasz Bekas 2023-11-20 14:58:49 +01:00 committed by GitHub
parent 2dd6b6b220
commit 1f0afff48b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 12 deletions

View File

@ -1,16 +1,24 @@
import std/macros import std/macros
import std/options
macro `.?`*(expression: seq | string, brackets: untyped{nkBracket}): untyped = proc safeGet[T](expression: seq[T] | openArray[T], index: int): Option[T] =
# chain is of shape: (seq or string).?[index] if index >= expression.low and index <= expression.high:
let index = brackets[0] expression[index].some
quote do: else:
block: T.none
type T = typeof(`expression`[`index`])
let evaluated = `expression` proc safeGet(expression: string, index: int): Option[char] =
if `index` < evaluated.len: if index >= expression.low and index <= expression.high:
evaluated[`index`].some expression[index].some
else: else:
T.none 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 = macro `.?`*(expression: typed, brackets: untyped{nkBracket}): untyped =
# chain is of shape: expression.?[index] # chain is of shape: expression.?[index]

View File

@ -337,13 +337,28 @@ suite "optionals":
test ".?[] can be used for indexing strings without raising IndexDefect": test ".?[] can be used for indexing strings without raising IndexDefect":
let str = "a" let str = "a"
check str.?[0] == 'a'.some check str.?[0] == 'a'.some
check str.?[1] == char.none check str.?[1] == char.none
check str.?[-1] == char.none
test ".?[] can be used for indexing sequences without raising IndexDefect": test ".?[] can be used for indexing sequences without raising IndexDefect":
let sequence = @[1] let sequence = @[1]
check sequence.?[0] == 1.some check sequence.?[0] == 1.some
check sequence.?[1] == int.none 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": test ".?[] can be followed by calls, operators and indexing":
let table = @{"a": @[41, 42]}.toTable let table = @{"a": @[41, 42]}.toTable