Skip to content

Commit 7d99e47

Browse files
committed
nim now has ref-alias and ptr-alias for lvalue expressions
1 parent 44aadd5 commit 7d99e47

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

lib/core/macros.nim

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,3 +1611,43 @@ when defined(nimMacrosSizealignof):
16111611
## from a field of a type. Therefore it only requires one argument
16121612
## instead of two. Returns a negative value if the Nim compiler
16131613
## does not know the offset.
1614+
1615+
proc splitDefinition*(def: NimNode): tuple[lhs: NimNode, rhs: NimNode] =
1616+
## allows library constructs such as: `byRef: a2 = expr`
1617+
doAssert def.kind == nnkStmtList and def.len == 1
1618+
let def2 = def[0]
1619+
doAssert def2.kind == nnkAsgn
1620+
let lhs = def2[0]
1621+
let rhs = def2[1]
1622+
expectKind(lhs, nnkIdent)
1623+
return (lhs, rhs)
1624+
1625+
macro byRef*(def: untyped): untyped =
1626+
## Defines a ref alias for lvalue expressions. The expression is evaluated
1627+
## only once, and any side effects will only be evaluated once, at declaration
1628+
## time.
1629+
runnableExamples:
1630+
var count = 0
1631+
proc identity(a: int): auto =
1632+
block: count.inc; a
1633+
var x = @[1,2,3]
1634+
byRef: x1=x[identity(1)] # the ref-alias is evaluated only here
1635+
doAssert count == 1
1636+
x1 += 10
1637+
doAssert type(x1) is int # use x1 just like a normal variable
1638+
doAssert x == @[1,12,3]
1639+
doAssert count == 1 # count has not changed
1640+
1641+
let (name, exp) = splitDefinition(def)
1642+
result = quote do:
1643+
let myAddr = addr `exp`
1644+
template `name`: untyped = myAddr[]
1645+
1646+
macro byPtr*(def: untyped): untyped =
1647+
## Defines a ptr alias for expressions. Caution: this uses `unsafeAddr`, so
1648+
## is unsafe to use in general, and `byRef` should be preferred when possible.
1649+
## This can for example be used on `let` variables.
1650+
let (name, exp) = splitDefinition(def)
1651+
result = quote do:
1652+
let myAddr = unsafeAddr `exp`
1653+
template `name`: untyped = myAddr[]

0 commit comments

Comments
 (0)