From 0895a9c065800285095a70f9e9ea10449adba56a Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Mon, 20 Jun 2022 17:36:24 +0200 Subject: [PATCH] Fix: `without` statement with error works in generic code --- questionable/binding.nim | 21 +++++++++++++------ questionable/private/binderror.nim | 19 +++++++++++++++++ questionable/withoutresult.nim | 33 +++--------------------------- testmodules/result/test.nim | 31 ++++++++++++++++++++++++---- 4 files changed, 64 insertions(+), 40 deletions(-) create mode 100644 questionable/private/binderror.nim diff --git a/questionable/binding.nim b/questionable/binding.nim index da01187..488caa2 100644 --- a/questionable/binding.nim +++ b/questionable/binding.nim @@ -1,5 +1,6 @@ import std/options import std/macros +import ./private/binderror proc option[T](option: Option[T]): Option[T] = option @@ -8,17 +9,25 @@ proc placeholder(T: type): T = discard template bindLet(name, expression): bool = - let option = expression.option + let evaluated = expression + let option = evaluated.option type T = typeof(option.unsafeGet()) - let name {.used.} = if option.isSome: option.unsafeGet() else: placeholder(T) + let name {.used.} = if option.isSome: + option.unsafeGet() + else: + bindFailed(evaluated) + placeholder(T) option.isSome template bindVar(name, expression): bool = - let option = expression.option + let evaluated = expression + let option = evaluated.option type T = typeof(option.unsafeGet()) - var name {.used.} : T = placeholder(T) - if option.isSome: - name = option.unsafeGet() + var name {.used.} = if option.isSome: + option.unsafeGet() + else: + bindFailed(evaluated) + placeholder(T) option.isSome macro `=?`*(name, expression): bool = diff --git a/questionable/private/binderror.nim b/questionable/private/binderror.nim new file mode 100644 index 0000000..bf23195 --- /dev/null +++ b/questionable/private/binderror.nim @@ -0,0 +1,19 @@ +import std/options + +var captureEnabled {.global, compiletime.}: bool +var errorVariable: ptr ref CatchableError + +template captureBindError*(error: var ref CatchableError, expression): auto = + static: captureEnabled = true + errorVariable = addr error + let evaluated = expression + static: captureEnabled = false + evaluated + +func error[T](option: Option[T]): ref CatchableError = + newException(ValueError, "Option is set to `none`") + +template bindFailed*(expression) = + when captureEnabled: + mixin error + errorVariable[] = expression.error diff --git a/questionable/withoutresult.nim b/questionable/withoutresult.nim index 1188db2..7872a80 100644 --- a/questionable/withoutresult.nim +++ b/questionable/withoutresult.nim @@ -1,39 +1,12 @@ -import std/macros -import ./binding import ./without +import ./private/binderror -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..