@@ -1611,3 +1611,43 @@ when defined(nimMacrosSizealignof):
1611
1611
# # from a field of a type. Therefore it only requires one argument
1612
1612
# # instead of two. Returns a negative value if the Nim compiler
1613
1613
# # 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