Macros
macro applicate(body): untyped
-
syntax for applicates with no parameters, or for applicates made with do notation
Example:
const defineX = applicate: let x {.inject.} = 3 defineX.apply() doAssert x == 3 # this is how do notation works, which we unfortunately can't show # as an example because runnableexamples breaks do notation: # const incr = applicate do (x: int) -> int: x + 1 # doAssert incr.apply(x) == 4 # named: # applicate named do (a, b; c: int): # let a = b(c) # named.apply(upperA, char, 65) # doAssert upperA == 'A'
Source Edit macro applicate(params, body): untyped
-
generates a template based on the params and body and registers it as a typed applicate. when anonymous, returns applicate id literal (compatible with ApplicateArg/Applicate). when a name is specified (using call/object constructor syntax), defines that name as a constant with the value being the applicate id.
param syntax: p: T, or p is T if Nim doesn't like colons, and paramList -> T for return type or paramsList: T for return type if paramsList is in parentheses. type annotations that are grouped together like a, b: int resolve to a: int, b: int.
the param syntax might be removed in the future given that do directly replicates regular routine parameters
note: the return type is untyped by default unlike templates, where it is void
Example:
applicate foo(name: untyped, val: int): let name = val foo.apply(x, 5) doAssert x == 5 template double(appl: ApplicateArg) = appl.apply() appl.apply() var c = 0 when false: # runnableExamples does not handle do: correctly, this works otherwise double(applicate do: double(applicate do: double(applicate do: inc c))) else: double applicate( double applicate( double applicate(inc(c)))) doAssert c == 8
Source Edit macro apply(appl: ApplicateArg; args: varargs[untyped]): untyped
-
applies the applicate by injecting the applicate routine (if not in scope already) then calling it with the given arguments
Example:
const incr = toApplicate(system.succ) doAssert incr.apply(1) == 2
Source Edit macro forceApply(appl: ApplicateArg; args: varargs[untyped]): untyped
-
applies the applicate by injecting the applicate routine, even if already in scope, then calling it with the given arguments
realistically, the applicate routine is never in scope, but if you really come across a case where it is then you can use this
Source Edit macro forceToSymbol(appl: ApplicateArg): untyped
- retrieves the symbol of the applicate, also instantiates routine definitions, without reusing definitions in scope Source Edit
macro instantiateAs(appl: ApplicateArg; name: untyped): untyped
-
instantiates the applicate in the scope with the given name
helps where apply syntax isn't enough (for example generics and overloading)
Example:
instantiateAs(toApplicate(system.succ), incr) doAssert incr(1) == 2 proc foo[T](x, y: T): T {.makeApplicate.} = x + y proc bar(x, y: string): string {.makeApplicate.} = x & y instantiateAs(foo, baz) instantiateAs(bar, baz) doAssert baz(1.0, 2.0) == 3.0 doAssert baz[uint8](1, 2) == 3u8 doAssert baz("a", "b") == "ab" # also works but less efficient as new template is generated: instantiateAs(toApplicate(`-`), minus) doAssert minus(4) == -4 doAssert minus(5, 2) == 3
Source Edit macro makeApplicate(body): untyped
-
Registers given routine definitions as applicates and assigns each applicate to a constant with the name of its routine.
Example:
proc foo: auto {.makeApplicate.} = x block: let x = 5 doAssert foo.apply() == 5 block: let x = "abc" doAssert foo.apply() == "abc"
Source Edit macro makeApplicateFromTyped(body: typed): untyped
-
Registers applicate with given routine(s), but forces it to be type checked first. This lets it use symbols that are accessible during the registering, but if the routine is not a template then only local symbols are accessible.
Works best for templates and macros, so applicate uses this.
Note: This will generate an unused warning for the given routine, makeTypedApplicate automatically generates a used pragma but only on untyped routine expressions.
Source Edit macro makeTypedApplicate(body: untyped): untyped
-
Calls makeApplicateFromTyped without giving an unused warning.
Accomplishes this by injecting {.used.}.
Example:
makeTypedApplicate: template useIt = doAssert it == realIt let realIt = 5 block: let it = realIt useIt.apply()
Source Edit macro toApplicate(sym: untyped): Applicate
-
directly registers sym as an applicate node. might be more efficient than toCallerApplicate for most cases, and accepts varying arities
Example:
const plus = toApplicate(`+`) doAssert plus.apply(1, 2) == 3
Source Edit macro toCallerApplicate(sym: typed): Applicate
-
infers the arity of sym from its symbol then calls toCallerApplicate(sym, arity)
if sym is a symbol choice, then the common arity of the choices is used. if the symbol choices do not share an arity, it will give an error
Example:
const newstr = toCallerApplicate(newString) var s: string s.setLen(4) doAssert newstr.apply(4) == s const leq = toCallerApplicate(`<=`) doAssert leq.apply(1, 2) doAssert leq.apply(2.0, 2.0)
Source Edit macro toCallerApplicate(sym: untyped; arity: static int): Applicate
-
creates an applicate of a template with n = arity untyped parameters that calls the given symbol sym
Example:
const adder = toCallerApplicate(`+`, 2) doAssert adder.apply(1, 2) == 3
Source Edit macro toSymbol(appl: ApplicateArg): untyped
-
retrieves the symbol of the applicate, also instantiates routine definitions
Example:
template foo(x: int): int = x + 1 const incr = toApplicate(foo) doAssert toSymbol(incr)(1) == 2
Source Edit