Use `scope` instead of `block`
To avoid influencing `break` statements.
This commit is contained in:
parent
1dcef4b302
commit
d079162675
|
@ -4,6 +4,7 @@ description = "Elegant optional types"
|
|||
license = "MIT"
|
||||
|
||||
task test, "Runs the test suite":
|
||||
exec "nim c -r tests/testScope"
|
||||
for module in ["options", "result", "stew"]:
|
||||
withDir "testmodules/" & module:
|
||||
delEnv "NIMBLE_DIR" # use nimbledeps dir
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import std/options
|
||||
import std/macros
|
||||
import std/strformat
|
||||
import ./private/scope
|
||||
|
||||
func isSym(node: NimNode): bool =
|
||||
node.kind in {nnkSym, nnkOpenSymChoice, nnkClosedSymChoice}
|
||||
|
@ -70,6 +71,6 @@ template `.?`*(left: typed, right: untyped): untyped =
|
|||
## The `.?` chaining operator is used to safely access fields and call procs
|
||||
## on Options or Results. The expression is only evaluated when the preceding
|
||||
## Option or Result has a value.
|
||||
block:
|
||||
scope:
|
||||
let evaluated = left
|
||||
chain(evaluated, right)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import std/macros
|
||||
import ./private/scope
|
||||
|
||||
macro `.?`*(expression: typed, brackets: untyped{nkBracket}): untyped =
|
||||
# chain is of shape: expression.?[index]
|
||||
let index = brackets[0]
|
||||
quote do:
|
||||
block:
|
||||
scope:
|
||||
type T = typeof(`expression`[`index`])
|
||||
try:
|
||||
`expression`[`index`].some
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
import ./private/scope
|
||||
|
||||
template liftUnary*(T: type, operator: untyped) =
|
||||
|
||||
template `operator`*(a: T): untyped =
|
||||
block:
|
||||
scope:
|
||||
let evaluated = a
|
||||
evaluated ->? `operator`(evaluated.unsafeGet())
|
||||
|
||||
template liftBinary*(T: type, operator: untyped) =
|
||||
|
||||
template `operator`*(a: T, b: T): untyped =
|
||||
block:
|
||||
scope:
|
||||
let evalA = a
|
||||
let evalB = b
|
||||
(evalA, evalB) ->? `operator`(evalA.unsafeGet, evalB.unsafeGet)
|
||||
|
||||
template `operator`*(a: T, b: typed): untyped =
|
||||
block:
|
||||
scope:
|
||||
let evalA = a
|
||||
evalA ->? `operator`(evalA.unsafeGet(), b)
|
||||
|
|
|
@ -7,6 +7,7 @@ import ./operators
|
|||
import ./without
|
||||
|
||||
include ./private/errorban
|
||||
import ./private/scope
|
||||
|
||||
export options except get
|
||||
export binding
|
||||
|
@ -56,7 +57,7 @@ proc `|?`*[T](option: ?T, fallback: T): T =
|
|||
macro `.?`*[T](option: ?T, brackets: untyped{nkBracket}): untyped =
|
||||
let index = brackets[0]
|
||||
quote do:
|
||||
block:
|
||||
scope:
|
||||
let evaluated = `option`
|
||||
type U = typeof(evaluated.unsafeGet().?[`index`].unsafeGet())
|
||||
if evaluated.isSome:
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
proc neverhappens {.inline, noreturn.} =
|
||||
discard
|
||||
|
||||
template scope*(body): untyped =
|
||||
## Can be used instead of `block` to introduce a new scoped block of code,
|
||||
## without influencing any `break` statements in the code.
|
||||
##
|
||||
## See also: https://github.com/nim-lang/RFCs/issues/451
|
||||
if true:
|
||||
body
|
||||
else:
|
||||
# call {.noreturn.} proc here to ensure that the compiler uses `body` for
|
||||
# the result value of the if-statement
|
||||
neverhappens()
|
|
@ -0,0 +1,17 @@
|
|||
import ../questionable/private/scope
|
||||
import std/unittest
|
||||
|
||||
suite "Scope":
|
||||
|
||||
test "introduces variable scope":
|
||||
var x = 1
|
||||
scope:
|
||||
var x: string
|
||||
x = "some string"
|
||||
check x == "some string"
|
||||
check x == 1
|
||||
|
||||
test "returns value":
|
||||
let x = scope:
|
||||
3
|
||||
check x == 3
|
Loading…
Reference in New Issue