mirror of
https://github.com/logos-storage/questionable.git
synced 2026-01-02 13:53:11 +00:00
Fix: ensure that overridden =? operator does not remain in scope
This commit is contained in:
parent
ef29000f94
commit
a748d22350
@ -1,22 +1,39 @@
|
||||
import std/macros
|
||||
import ./binding
|
||||
import ./without
|
||||
|
||||
template without*(expression, errorname, body) =
|
||||
macro replaceInfix(expression, operator, replacement): untyped =
|
||||
## Replaces an infix operator in an expression. The AST of the expression is
|
||||
## traversed to find and replace all instances of the operator.
|
||||
|
||||
proc replace(expression, operator, replacement: NimNode): NimNode =
|
||||
if expression.kind == nnkInfix and eqIdent(expression[0], operator):
|
||||
expression[0] = replacement
|
||||
expression[2] = replace(expression[2], operator, replacement)
|
||||
else:
|
||||
for i in 0..<expression.len:
|
||||
expression[i] = replace(expression[i], operator, replacement)
|
||||
expression
|
||||
|
||||
replace(expression, operator, replacement)
|
||||
|
||||
template without*(condition, errorname, body) =
|
||||
## Used to place guards that ensure that a Result contains a value.
|
||||
## Exposes error when Result does not contain a value.
|
||||
|
||||
var error: ref CatchableError
|
||||
|
||||
# override =? operator such that it stores the error if there is one
|
||||
template `=?`(name, result): bool =
|
||||
when result is Result:
|
||||
if result.isFailure:
|
||||
error = result.error
|
||||
when result is Option:
|
||||
if result.isNone:
|
||||
template `override=?`(name, expression): bool {.gensym, used.} =
|
||||
let optional = expression
|
||||
when optional is Result:
|
||||
if optional.isFailure:
|
||||
error = optional.error
|
||||
when optional is Option:
|
||||
if optional.isNone:
|
||||
error = newException(ValueError, "Option is set to `none`")
|
||||
binding.`=?`(name, result)
|
||||
name =? optional
|
||||
|
||||
without expression:
|
||||
without replaceInfix(condition, `=?`, `override=?`):
|
||||
template errorname: ref CatchableError = error
|
||||
body
|
||||
|
||||
@ -243,6 +243,28 @@ suite "result":
|
||||
test1()
|
||||
test2()
|
||||
|
||||
test "without statement with error can be used more than once":
|
||||
proc test =
|
||||
without a =? 42.success, error:
|
||||
discard error
|
||||
fail
|
||||
without b =? 42.success, error:
|
||||
discard error
|
||||
fail
|
||||
|
||||
test()
|
||||
|
||||
test "without statement with error works with deeply nested =? operators":
|
||||
proc test =
|
||||
let fail1 = int.failure "error 1"
|
||||
let fail2 = int.failure "error 2"
|
||||
without (block: a =? (if b =? fail1: b.success else: fail2)), error:
|
||||
check error.msg == "error 2"
|
||||
return
|
||||
fail
|
||||
|
||||
test()
|
||||
|
||||
test "catch can be used to convert exceptions to results":
|
||||
check parseInt("42").catch == 42.success
|
||||
check parseInt("foo").catch.error of ValueError
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user