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"
|
license = "MIT"
|
||||||
|
|
||||||
task test, "Runs the test suite":
|
task test, "Runs the test suite":
|
||||||
|
exec "nim c -r tests/testScope"
|
||||||
for module in ["options", "result", "stew"]:
|
for module in ["options", "result", "stew"]:
|
||||||
withDir "testmodules/" & module:
|
withDir "testmodules/" & module:
|
||||||
delEnv "NIMBLE_DIR" # use nimbledeps dir
|
delEnv "NIMBLE_DIR" # use nimbledeps dir
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import std/options
|
import std/options
|
||||||
import std/macros
|
import std/macros
|
||||||
import std/strformat
|
import std/strformat
|
||||||
|
import ./private/scope
|
||||||
|
|
||||||
func isSym(node: NimNode): bool =
|
func isSym(node: NimNode): bool =
|
||||||
node.kind in {nnkSym, nnkOpenSymChoice, nnkClosedSymChoice}
|
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
|
## The `.?` chaining operator is used to safely access fields and call procs
|
||||||
## on Options or Results. The expression is only evaluated when the preceding
|
## on Options or Results. The expression is only evaluated when the preceding
|
||||||
## Option or Result has a value.
|
## Option or Result has a value.
|
||||||
block:
|
scope:
|
||||||
let evaluated = left
|
let evaluated = left
|
||||||
chain(evaluated, right)
|
chain(evaluated, right)
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import std/macros
|
import std/macros
|
||||||
|
import ./private/scope
|
||||||
|
|
||||||
macro `.?`*(expression: typed, brackets: untyped{nkBracket}): untyped =
|
macro `.?`*(expression: typed, brackets: untyped{nkBracket}): untyped =
|
||||||
# chain is of shape: expression.?[index]
|
# chain is of shape: expression.?[index]
|
||||||
let index = brackets[0]
|
let index = brackets[0]
|
||||||
quote do:
|
quote do:
|
||||||
block:
|
scope:
|
||||||
type T = typeof(`expression`[`index`])
|
type T = typeof(`expression`[`index`])
|
||||||
try:
|
try:
|
||||||
`expression`[`index`].some
|
`expression`[`index`].some
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
|
import ./private/scope
|
||||||
|
|
||||||
template liftUnary*(T: type, operator: untyped) =
|
template liftUnary*(T: type, operator: untyped) =
|
||||||
|
|
||||||
template `operator`*(a: T): untyped =
|
template `operator`*(a: T): untyped =
|
||||||
block:
|
scope:
|
||||||
let evaluated = a
|
let evaluated = a
|
||||||
evaluated ->? `operator`(evaluated.unsafeGet())
|
evaluated ->? `operator`(evaluated.unsafeGet())
|
||||||
|
|
||||||
template liftBinary*(T: type, operator: untyped) =
|
template liftBinary*(T: type, operator: untyped) =
|
||||||
|
|
||||||
template `operator`*(a: T, b: T): untyped =
|
template `operator`*(a: T, b: T): untyped =
|
||||||
block:
|
scope:
|
||||||
let evalA = a
|
let evalA = a
|
||||||
let evalB = b
|
let evalB = b
|
||||||
(evalA, evalB) ->? `operator`(evalA.unsafeGet, evalB.unsafeGet)
|
(evalA, evalB) ->? `operator`(evalA.unsafeGet, evalB.unsafeGet)
|
||||||
|
|
||||||
template `operator`*(a: T, b: typed): untyped =
|
template `operator`*(a: T, b: typed): untyped =
|
||||||
block:
|
scope:
|
||||||
let evalA = a
|
let evalA = a
|
||||||
evalA ->? `operator`(evalA.unsafeGet(), b)
|
evalA ->? `operator`(evalA.unsafeGet(), b)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import ./operators
|
||||||
import ./without
|
import ./without
|
||||||
|
|
||||||
include ./private/errorban
|
include ./private/errorban
|
||||||
|
import ./private/scope
|
||||||
|
|
||||||
export options except get
|
export options except get
|
||||||
export binding
|
export binding
|
||||||
|
@ -56,7 +57,7 @@ proc `|?`*[T](option: ?T, fallback: T): T =
|
||||||
macro `.?`*[T](option: ?T, brackets: untyped{nkBracket}): untyped =
|
macro `.?`*[T](option: ?T, brackets: untyped{nkBracket}): untyped =
|
||||||
let index = brackets[0]
|
let index = brackets[0]
|
||||||
quote do:
|
quote do:
|
||||||
block:
|
scope:
|
||||||
let evaluated = `option`
|
let evaluated = `option`
|
||||||
type U = typeof(evaluated.unsafeGet().?[`index`].unsafeGet())
|
type U = typeof(evaluated.unsafeGet().?[`index`].unsafeGet())
|
||||||
if evaluated.isSome:
|
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