Skip to content

Instantly share code, notes, and snippets.

@Araq
Created November 28, 2017 01:54
Show Gist options
  • Save Araq/67c7701f78fc527330d1875b5fa3a1cf to your computer and use it in GitHub Desktop.
Save Araq/67c7701f78fc527330d1875b5fa3a1cf to your computer and use it in GitHub Desktop.
import macros, sets, strutils
type
Elem = object
x, y: int
Elems = seq[Elem]
ElemId = distinct uint16 # as ptr
Obj = object
p: ptr Elem
# UnitId = distinct int32
# p.fieldname
# a[i].fieldname
template `@`(a, i): untyped = addr(a[int(i)])
proc mutate(e: var seq[Elem]) =
for i in 0..<100:
e.add Elem(x: 12, y: 88)
proc h(n, firstParam: NimNode; interesting: HashSet[string]): NimNode =
if n.kind == nnkDotExpr and repr(n[0]) in interesting:
result = newTree(nnkDotExpr, newTree(nnkBracketExpr, firstParam, newCall(bindSym"int", n[0])), n[1])
else:
result = copyNimNode(n)
for x in n: result.add h(x, firstParam, interesting)
proc ptrsOnSeq(n: NimNode): NimNode =
# - Collect the parameter names we want to "transform" into pointers.
# - Process the body of the proc, replace 'param.field' with 'firstParam[param].field'
let params = params(n)
var interesting = initSet[string]()
for i in 1..<params.len:
let it = params[i]
expectKind(it, nnkIdentDefs) # one, two: TypeHere = default
if repr(it[it.len-2]).endsWith"Id":
for j in 0..it.len-3:
interesting.incl repr(it[j])
result = copyNimTree(n)
result.body = h(n.body, params[1][0], interesting)
template derivedPtrName(x): untyped = x & "DerivedPtr"
proc h2(n: NimNode; interesting: HashSet[string]): NimNode =
if n.kind == nnkDotExpr and repr(n[0]) in interesting:
result = newTree(nnkDotExpr, ident(derivedPtrName repr(n[0])), n[1])
else:
result = copyNimNode(n)
for x in n: result.add h2(x, interesting)
proc ptrsOnOpenArray(n: NimNode): NimNode =
# - Collect the parameter names we want to "transform" into pointers.
# - Add statements like let paramIdDerivedPtr = addr(firstParam[paramId.int])
# - Process the body of the proc, replace
# with 'derivedPtr(firstParam[param]).field'
let params = params(n)
var interesting = initSet[string]()
let initSection = newStmtList()
let theArray = params[1][0]
for i in 1..<params.len:
let it = params[i]
expectKind(it, nnkIdentDefs) # one, two: TypeHere = default
if repr(it[it.len-2]).endsWith"Id":
for j in 0..it.len-3:
interesting.incl repr(it[j])
template addrOf(a, i): untyped = addr(a[int(i)])
initSection.add newLetStmt(ident(derivedPtrName repr(it[j])),
getAst(addrOf(theArray, it[j])))
result = copyNimTree(n)
initSection.add h2(n.body, interesting)
result.body = initSection
proc isOpenArray(n: NimNode): bool =
var n = n
if n.kind == nnkVarTy: n = n[^1]
if n.kind == nnkBracketExpr:
result = eqIdent(n[0], "openArray")
macro borrowPtrs(n: untyped): untyped =
let params = params(n)
expectKind(params[1], nnkIdentDefs)
let theArray = params[1][^2]
if isOpenArray(theArray):
result = ptrsOnOpenArray(n)
else:
result = ptrsOnSeq(n)
when defined(debugPtrsDsl):
echo repr result
proc output(e: var openArray[Elem]; idA, idB: ElemId) {.borrowPtrs.} =
echo idA.x, " ", idB.y
var testdata = @[Elem(x: 5, y: 15)]
output(testdata, ElemId 0, ElemId 0)
@Araq
Copy link
Author

Araq commented May 27, 2020

I wrote it 3 years ago, feel free to take it and create a Nimble package for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment