mirror of
https://github.com/logos-storage/questionable.git
synced 2026-01-05 23:33:12 +00:00
Allow indexing of tables with ?[]
This commit is contained in:
parent
91f97c73ef
commit
40f5b4f1b8
41
questionable/indexing.nim
Normal file
41
questionable/indexing.nim
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import std/macros
|
||||||
|
|
||||||
|
macro `?`*(expression: typed, brackets: untyped{nkBracket}): untyped =
|
||||||
|
# chain is of shape: expression?[index]
|
||||||
|
let index = brackets[0]
|
||||||
|
quote do:
|
||||||
|
type T = typeof(`expression`[`index`])
|
||||||
|
try:
|
||||||
|
`expression`[`index`].some
|
||||||
|
except KeyError:
|
||||||
|
T.none
|
||||||
|
|
||||||
|
macro `?`*(expression: typed, infix: untyped{nkInfix}): untyped =
|
||||||
|
# chain is of shape: expression?left `operator` right
|
||||||
|
let left = infix[1]
|
||||||
|
infix[1] = quote do: `expression`?`left`
|
||||||
|
infix
|
||||||
|
|
||||||
|
macro `?`*(expression: typed, bracket: untyped{nkBracketExpr}): untyped =
|
||||||
|
# chain is of shape: expression?left[right]
|
||||||
|
let left = bracket[0]
|
||||||
|
bracket[0] = quote do: `expression`?`left`
|
||||||
|
bracket
|
||||||
|
|
||||||
|
macro `?`*(expression: typed, dot: untyped{nkDotExpr}): untyped =
|
||||||
|
# chain is of shape: expression?left.right
|
||||||
|
let left = dot[0]
|
||||||
|
dot[0] = quote do: `expression`?`left`
|
||||||
|
dot
|
||||||
|
|
||||||
|
macro `?`*(expression: typed, call: untyped{nkCall}): untyped =
|
||||||
|
let procedure = call[0]
|
||||||
|
if procedure.kind == nnkDotExpr:
|
||||||
|
# chain is of shape: expression?left.right(arguments)
|
||||||
|
let (left, right) = (procedure[0], procedure[1])
|
||||||
|
call[0] = right
|
||||||
|
call.insert(1, quote do: `expression`?`left`)
|
||||||
|
call
|
||||||
|
else:
|
||||||
|
call.expectKind(nnkBracketExpr)
|
||||||
|
nil
|
||||||
@ -1,12 +1,14 @@
|
|||||||
import std/options
|
import std/options
|
||||||
import std/macros
|
import std/macros
|
||||||
import ./chaining
|
import ./chaining
|
||||||
|
import ./indexing
|
||||||
import ./operators
|
import ./operators
|
||||||
|
|
||||||
include ./errorban
|
include ./errorban
|
||||||
|
|
||||||
export options
|
export options
|
||||||
export chaining
|
export chaining
|
||||||
|
export indexing
|
||||||
|
|
||||||
template `?`*(T: typed): type Option[T] =
|
template `?`*(T: typed): type Option[T] =
|
||||||
Option[T]
|
Option[T]
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import std/unittest
|
import std/unittest
|
||||||
import std/sequtils
|
import std/sequtils
|
||||||
|
import std/tables
|
||||||
import std/sugar
|
import std/sugar
|
||||||
import pkg/questionable
|
import pkg/questionable
|
||||||
|
|
||||||
@ -87,6 +88,25 @@ suite "optionals":
|
|||||||
if var a =? int.none:
|
if var a =? int.none:
|
||||||
fail
|
fail
|
||||||
|
|
||||||
|
test "?[] can be used for indexing tables without raising KeyError":
|
||||||
|
let table = @{"a": 1, "b": 2}.toTable
|
||||||
|
check table?["a"] == 1.some
|
||||||
|
check table?["c"] == int.none
|
||||||
|
|
||||||
|
test "?[] can be followed by calls, operators and indexing":
|
||||||
|
let table = @{"a": @[41, 42]}.toTable
|
||||||
|
check table?["a"].isSome
|
||||||
|
check table?["a"].isSome()
|
||||||
|
check table?["a"][0] == 41.some
|
||||||
|
check table?["a"]?.len.get == 2
|
||||||
|
check table?["a"]?.len.get.uint8.uint64 == 2'u64
|
||||||
|
check table?["a"]?.len.get() == 2
|
||||||
|
check table?["a"]?.len.get().uint8.uint64 == 2'u64
|
||||||
|
check table?["a"]?.deduplicate()[0]?.uint8?.uint64 == 41'u64.some
|
||||||
|
check table?["a"]?.len + 1 == 3.some
|
||||||
|
check table?["a"]?.deduplicate()[0] + 1 == 42.some
|
||||||
|
check table?["a"]?.deduplicate.map(x => x) == @[41, 42].some
|
||||||
|
|
||||||
test "=? evaluates optional expression only once":
|
test "=? evaluates optional expression only once":
|
||||||
var count = 0
|
var count = 0
|
||||||
if a =? (inc count; 42.some):
|
if a =? (inc count; 42.some):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user