nim-stew/stew/evalonce.nim

43 lines
1.2 KiB
Nim

# stew
# Copyright 2024 Status Research & Development GmbH
# Licensed under either of
#
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import std/macros
macro evalOnceAs*(exp, alias: untyped): untyped =
## Ensure that `exp` is evaluated only once unless it is a symbol in which
## case it's used directly.
##
## A common case where this is useful is template parameters which, when
## an expression is passed in, get evaluated multiple times.
##
## Based on a similar macro in std/sequtils
expectKind(alias, nnkIdent)
let
body = nnkStmtList.newTree()
val =
if exp.kind == nnkSym:
# The symbol can be used directly
# TODO dot expressions? etc..
exp
else:
let val = genSym(ident = "evalOnce_" & $alias)
body.add newLetStmt(val, exp)
val
body.add(
newProc(
name = genSym(nskTemplate, $alias),
params = [getType(untyped)],
body = val,
procType = nnkTemplateDef,
)
)
body