Skip to content

Commit

Permalink
address comments
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Jul 25, 2019
1 parent a67bbab commit e662217
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 40 deletions.
40 changes: 0 additions & 40 deletions lib/core/macros.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1611,43 +1611,3 @@ when defined(nimMacrosSizealignof):
## from a field of a type. Therefore it only requires one argument
## instead of two. Returns a negative value if the Nim compiler
## does not know the offset.

proc splitDefinition*(def: NimNode): tuple[lhs: NimNode, rhs: NimNode] =
## allows library constructs such as: `byRef: a2 = expr`
doAssert def.kind == nnkStmtList and def.len == 1
let def2 = def[0]
doAssert def2.kind == nnkAsgn
let lhs = def2[0]
let rhs = def2[1]
expectKind(lhs, nnkIdent)
return (lhs, rhs)

macro byRef*(def: untyped): untyped =
## Defines a ref alias for lvalue expressions. The expression is evaluated
## only once, and any side effects will only be evaluated once, at declaration
## time.
runnableExamples:
var count = 0
proc identity(a: int): auto =
block: count.inc; a
var x = @[1,2,3]
byRef: x1=x[identity(1)] # the ref-alias is evaluated only here
doAssert count == 1
x1 += 10
doAssert type(x1) is int # use x1 just like a normal variable
doAssert x == @[1,12,3]
doAssert count == 1 # count has not changed

let (name, exp) = splitDefinition(def)
result = quote do:
let myAddr = addr `exp`
template `name`: untyped = myAddr[]

macro byPtr*(def: untyped): untyped =
## Defines a ptr alias for expressions. Caution: this uses `unsafeAddr`, so
## is unsafe to use in general, and `byRef` should be preferred when possible.
## This can for example be used on `let` variables.
let (name, exp) = splitDefinition(def)
result = quote do:
let myAddr = unsafeAddr `exp`
template `name`: untyped = myAddr[]
34 changes: 34 additions & 0 deletions lib/pure/sugar.nim
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,37 @@ macro distinctBase*(T: typedesc): untyped =
while typeSym.typeKind == ntyDistinct:
typeSym = getTypeImpl(typeSym)[0]
typeSym.freshIdentNodes

proc splitDefinition*(def: NimNode): tuple[lhs: NimNode, rhs: NimNode] =
## allows library constructs such as: `byRef: a2 = expr`
doAssert def.kind == nnkStmtList and def.len == 1
let def2 = def[0]
doAssert def2.kind == nnkAsgn
let lhs = def2[0]
let rhs = def2[1]
expectKind(lhs, nnkIdent)
return (lhs, rhs)

macro byRef*(def: untyped): untyped =
## Defines a ref alias for lvalue expressions. The expression is evaluated
## only once, and any side effects will only be evaluated once, at declaration
## time.
runnableExamples:
var x = @[1,2,3]
byRef: x1=x[1]
x1+=10
doAssert type(x1) is int and x == @[1,12,3]

let (name, exp) = splitDefinition(def)
result = quote do:
let myAddr = addr `exp`
template `name`: untyped = myAddr[]

macro byPtr*(def: untyped): untyped =
## Defines a ptr alias for expressions. Caution: this uses `unsafeAddr`, so
## is unsafe to use in general, and `byRef` should be preferred when possible.
## This can for example be used on `let` variables.
let (name, exp) = splitDefinition(def)
result = quote do:
let myAddr = unsafeAddr `exp`
template `name`: untyped = myAddr[]
26 changes: 26 additions & 0 deletions tests/stdlib/tsugar.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ block distinctBase:

doAssert Uint[128].distinctBase is UintImpl[uint64]

block byRefBlock:
var count = 0
proc identity(a: int): auto =
block: count.inc; a
var x = @[1,2,3]
byRef: x1=x[identity(1)] # the lvalue expression is evaluated only here
doAssert count == 1
x1 += 10
doAssert type(x1) is int # use x1 just like a normal variable
doAssert x == @[1,12,3]
doAssert count == 1 # count has not changed
doAssert compiles (block: byRef: x2=x[0])
doAssert not compiles (block: byRef: x2=y[0])
# correctly does not compile when using invalid lvalue expression

block byPtrfBlock:
type Foo = object
x: string
proc fun(a: Foo): auto =
doAssert not compiles (block: byRef: x=a.x)
byPtr: x=a.x
x[0]='X'
let foo = Foo(x: "asdf")
fun(foo)
doAssert foo.x == "Xsdf"

# bug #7816
import sequtils

Expand Down

0 comments on commit e662217

Please sign in to comment.