Add documentation comments

This commit is contained in:
Mark Spanbroek 2021-06-04 17:34:48 +02:00
parent a2ded4f01a
commit 4a1783c472
6 changed files with 69 additions and 1 deletions

View File

@ -63,7 +63,7 @@ else:
# this is reached, and y is not defined
```
The `without` statement can be used to place guards that ensure that an optional
The `without` statement can be used to place guards that ensure that an Option
contains a value:
```nim

View File

@ -18,6 +18,10 @@ template bindVar(name, expression): bool =
option.isSome
macro `=?`*(name, expression): bool =
## The `=?` operator lets you bind the value inside an Option or Result to a
## new variable. It can be used inside of a conditional expression, for
## instance in an `if` statement.
name.expectKind({nnkIdent, nnkVarTy})
if name.kind == nnkIdent:
quote do: bindLet(`name`, `expression`)

View File

@ -8,30 +8,50 @@ func expectSym(node: NimNode) =
node.expectKind({nnkSym, nnkOpenSymChoice, nnkClosedSymChoice})
template `.?`*(option: typed, identifier: untyped{nkIdent}): 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.
# chain is of shape: option.?identifier
when not compiles(typeof(option.unsafeGet.identifier)):
{.error: ".? chain cannot return void".}
option ->? option.unsafeGet.identifier
macro `.?`*(option: typed, infix: untyped{nkInfix}): 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.
# chain is of shape: option.?left `operator` right
let left = infix[1]
infix[1] = quote do: `option`.?`left`
infix
macro `.?`*(option: typed, bracket: untyped{nkBracketExpr}): 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.
# chain is of shape: option.?left[right]
let left = bracket[0]
bracket[0] = quote do: `option`.?`left`
bracket
macro `.?`*(option: typed, dot: untyped{nkDotExpr}): 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.
# chain is of shape: option.?left.right
let left = dot[0]
dot[0] = quote do: `option`.?`left`
dot
macro `.?`*(option: typed, call: untyped{nkCall}): 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.
let procedure = call[0]
if call.len == 1:
# chain is of shape: option.?procedure()
@ -53,6 +73,10 @@ macro `.?`*(option: typed, call: untyped{nkCall}): untyped =
quote do: `option` ->? `call`
macro `.?`*(option: typed, symbol: 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.
symbol.expectSym()
let expression = ident($symbol)
quote do: `option`.?`expression`

View File

@ -15,9 +15,15 @@ export indexing
export without
template `?`*(T: typed): type Option[T] =
## Use `?` to make a type optional. For example the type `?int` is short for
## `Option[int]`.
Option[T]
template `!`*[T](option: ?T): T =
## Returns the value of an Option when you're absolutely sure that it
## contains value. Using `!` on an Option without a value raises a Defect.
option.get
template `->?`*[T,U](option: ?T, expression: ?U): ?U =
@ -39,6 +45,9 @@ template `->?`*[T,U,V](options: (?T, ?U), expression: V): ?V =
options ->? expression.some
template `|?`*[T](option: ?T, fallback: T): T =
## Use the `|?` operator to supply a fallback value when an Option does not
## hold a value.
if option.isSome:
option.unsafeGet()
else:

View File

@ -18,33 +18,57 @@ export without
type ResultFailure* = object of CatchableError
template `?!`*(T: typed): type Result[T, ref CatchableError] =
## Use `?!` make a Result type. These Result types either hold a value or
## an error. For example the type `?!int` is short for
## `Result[int, ref CatchableError]`.
Result[T, ref CatchableError]
template `!`*[T](value: ?!T): T =
## Returns the value of a Result when you're absolutely sure that it
## contains value. Using `!` on a Result without a value raises a Defect.
value.get
proc success*[T](value: T): ?!T =
## Creates a successfull Result containing the value.
##
ok(?!T, value)
proc success*: ?!void =
## Creates a successfull Result without a value.
ok(?!void)
proc failure*(T: type, error: ref CatchableError): ?!T =
## Creates a failed Result containing the error.
err(?!T, error)
proc failure*(T: type, message: string): ?!T =
## Creates a failed Result containing a `ResultFailure` with the specified
## error message.
T.failure newException(ResultFailure, message)
template failure*(error: ref CatchableError): auto =
## Creates a failed Result containing the error.
err error
template failure*(message: string): auto =
## Creates a failed Result containing the error.
failure newException(ResultFailure, message)
proc isSuccess*[T](value: ?!T): bool =
## Returns true when the Result contains a value.
value.isOk
proc isFailure*[T](value: ?!T): bool =
## Returns true when the Result contains an error.
value.isErr
template `->?`*[T,U](value: ?!T, expression: ?!U): ?!U =
@ -68,9 +92,14 @@ template `->?`*[T,U,V](values: (?!T, ?!U), expression: V): ?!V =
values ->? expression.success
template `|?`*[T,E](value: Result[T,E], fallback: T): T =
## Use the `|?` operator to supply a fallback value when a Result does not
## hold a value.
value.valueOr(fallback)
proc option*[T,E](value: Result[T,E]): ?T =
## Converts a Result into an Option.
if value.isOk:
try: # workaround for erroneouos exception tracking when T is a closure
value.unsafeGet.some

View File

@ -1,4 +1,6 @@
template without*(expression, body) =
## Used to place guards that ensure that an Option or Result contains a value.
let ok = expression
if not ok:
body