Evaluate =? expressions only once

This commit is contained in:
Mark Spanbroek 2021-03-18 16:59:55 +01:00
parent 4f0010638b
commit 91f97c73ef
4 changed files with 38 additions and 12 deletions

View File

@ -23,17 +23,19 @@ template `->?`*[T,U,V](options: (?T, ?U), expression: V): ?V =
else:
V.none
template `=?`*[T](name: untyped{nkIdent}, option: ?T): bool =
template `=?`*[T](name: untyped{nkIdent}, expression: ?T): bool =
let option = expression
template name: T {.used.} = option.unsafeGet()
option.isSome
macro `=?`*[T](variable: untyped{nkVarTy}, option: ?T): bool =
macro `=?`*[T](variable: untyped{nkVarTy}, expression: ?T): bool =
let name = variable[0]
quote do:
var `name` : typeof(`option`.unsafeGet())
if `option`.isSome:
`name` = `option`.unsafeGet()
`option`.isSome
let option = `expression`
var `name` : typeof(option.unsafeGet())
if option.isSome:
`name` = option.unsafeGet()
option.isSome
template `|?`*[T](option: ?T, fallback: T): T =
if option.isSome:

View File

@ -38,17 +38,19 @@ template `->?`*[T,U,V](values: (?!T, ?!U), expression: V): ?!V =
template `|?`*[T](value: ?!T, fallback: T): T =
value.valueOr(fallback)
template `=?`*[T](name: untyped{nkIdent}, value: ?!T): bool =
template `=?`*[T](name: untyped{nkIdent}, expression: ?!T): bool =
let value = expression
template name: T {.used.} = value.unsafeGet()
value.isOk
macro `=?`*[T](variable: untyped{nkVarTy}, option: ?!T): bool =
macro `=?`*[T](variable: untyped{nkVarTy}, expression: ?!T): bool =
let name = variable[0]
quote do:
var `name` : typeof(`option`.unsafeGet())
if `option`.isOk:
`name` = `option`.unsafeGet()
`option`.isOk
let value = `expression`
var `name` : typeof(value.unsafeGet())
if value.isOk:
`name` = value.unsafeGet()
value.isOk
proc option*[T,E](value: Result[T,E]): ?T =
if value.isOk:

View File

@ -87,6 +87,17 @@ suite "optionals":
if var a =? int.none:
fail
test "=? evaluates optional expression only once":
var count = 0
if a =? (inc count; 42.some):
let b {.used.} = a
check count == 1
count = 0
if var a =? (inc count; 42.some):
let b {.used.} = a
check count == 1
test "unary operator `-` works for options":
check -(-42.some) == 42.some
check -(int.none) == int.none

View File

@ -91,6 +91,17 @@ suite "result":
if var a =? int.failure(error):
fail
test "=? evaluates optional expression only once":
var count = 0
if a =? (inc count; 42.success):
let b {.used.} = a
check count == 1
count = 0
if var a =? (inc count; 42.success):
let b {.used.} = a
check count == 1
test "catch can be used to convert exceptions to results":
check parseInt("42").catch == 42.success
check parseInt("foo").catch.error of ValueError