Attempt to fix #11

This commit is contained in:
Tanguy 2022-06-16 17:58:20 +02:00
parent d7e9f0bf7f
commit ba353b27e4
No known key found for this signature in database
GPG Key ID: 7DD8EC6B6CE6C45E
4 changed files with 38 additions and 29 deletions

View File

@ -7,19 +7,11 @@ proc option[T](option: Option[T]): Option[T] =
proc placeholder(T: type): T =
discard
template bindLet(name, expression): bool =
let option = expression.option
template unpack*(expression: Option): untyped =
let option = expression
type T = typeof(option.unsafeGet())
let name {.used.} = if option.isSome: option.unsafeGet() else: placeholder(T)
option.isSome
template bindVar(name, expression): bool =
let option = expression.option
type T = typeof(option.unsafeGet())
var name {.used.} : T = placeholder(T)
if option.isSome:
name = option.unsafeGet()
option.isSome
let res = if option.isSome: option.unsafeGet() else: placeholder(T)
(res, option.isSome)
macro `=?`*(name, expression): bool =
## The `=?` operator lets you bind the value inside an Option or Result to a
@ -28,7 +20,14 @@ macro `=?`*(name, expression): bool =
name.expectKind({nnkIdent, nnkVarTy})
if name.kind == nnkIdent:
quote do: bindLet(`name`, `expression`)
quote do:
mixin unpack
let (`name`, isOk) = unpack(`expression`)
isOk
else:
let name = name[0]
quote do: bindVar(`name`, `expression`)
quote do:
mixin unpack
var (`name`, isOk) = unpack(`expression`)
isOk

View File

@ -99,6 +99,13 @@ template `|?`*[T,E](value: Result[T,E], fallback: T): T =
value.valueOr(fallback)
template unpack*(expression: Result): untyped =
let res = expression
when declaredInScope(internalWithoutError):
if res.isFailure:
internalWithoutError = res.error
unpack(res.option)
proc option*[T,E](value: Result[T,E]): ?T =
## Converts a Result into an Option.

View File

@ -21,19 +21,13 @@ 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 `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`")
name =? optional
without replaceInfix(condition, `=?`, `override=?`):
template errorname: ref CatchableError = error
when not declaredInScope(internalWithoutError):
var internalWithoutError {.inject.}: ref CatchableError
else:
internalWithoutError = nil
without condition:
template errorname: ref CatchableError = internalWithoutError
if isNil(errorname):
errorname = newException(ValueError, "Option is set to `none`")
body

View File

@ -265,6 +265,15 @@ suite "result":
test()
test "without statement works in generic code":
proc test(_: type) =
without a =? int.failure "error", e:
check e.msg == "error"
return
fail
test(int)
test "catch can be used to convert exceptions to results":
check parseInt("42").catch == 42.success
check parseInt("foo").catch.error of ValueError