Created
November 28, 2017 01:54
-
-
Save Araq/67c7701f78fc527330d1875b5fa3a1cf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
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
The macro can make templates that shadow the proc's arguments, this way there is no need to process the body and would be simpler. Any reason it doesn't do that instead?
Edit:
Error: template instantiation too nested
nvm