Last active
August 29, 2015 14:10
-
-
Save jovial/1f3a6fbace89c4a2cf66 to your computer and use it in GitHub Desktop.
This file contains 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 tables | |
import typetraits | |
import macros | |
proc newTemplate*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()]; | |
body: PNimrodNode = newStmtList()): PNimrodNode {.compileTime.} = | |
## shortcut for creating a new template | |
## | |
## The ``params`` array must start with the return type of the template, | |
## followed by a list of IdentDefs which specify the params. | |
result = newNimNode(nnkTemplateDef).add( | |
name, | |
newEmptyNode(), | |
newEmptyNode(), | |
newNimNode(nnkFormalParams).add(params), ##params | |
newEmptyNode(), ## pragmas | |
newEmptyNode(), | |
body) | |
proc getFieldIndex(typ: typedesc): Table[int, string] {.compileTime.} = | |
# this didn't work in the template, so moved to helper proc | |
var dummy: typ | |
var index = 0 | |
result = initTable[int, string]() | |
when compiles(dummy[]): | |
for name, value in dummy[].fieldPairs(): | |
result[index] = name | |
index.inc | |
else: | |
for name, value in dummy.fieldPairs(): | |
result[index] = name | |
index.inc | |
template indexFields*(typ: typedesc): stmt = | |
static: | |
var index = getFieldIndex(typ) | |
macro genFieldIndex(): stmt {.genSym.} = | |
# generate something like: | |
# template `[]`(obj: Foo, index: int): expr = | |
# when index == 0: | |
# obj.a | |
# elif index == 1: | |
# obj.b | |
# elif index == 2: | |
# obj.c | |
result = newStmtList() | |
let templateName = newNimNode(nnkAccQuoted) | |
.add ident("[]") | |
# idents for param's | |
let returnIdent = ident "expr" | |
let objIdent = ident "obj" | |
let objIdentDefs = newIdentDefs(objIdent, ident typ.name) | |
let indexIdent = ident "index" | |
let indexIdentDefs = newIdentDefs(indexIdent, ident "int") | |
var whenStmt = newNimNode(nnkWhenStmt) | |
for index, fieldName in index.pairs(): | |
var elifBranch = newNimNode(nnkElifBranch) | |
let predicate = infix(indexIdent, "==", newLit index) | |
let body = newStmtList() | |
.add newDotExpr(objIdent, ident fieldName) | |
elifBranch.add predicate | |
elifBranch.add body | |
whenStmt.add elifBranch | |
let body = newStmtList().add whenStmt | |
result.add newTemplate( | |
templateName, | |
[returnIdent, objIdentDefs, indexIdentDefs], | |
body) | |
genFieldIndex() | |
type Foo = object | |
a: int | |
b: string | |
c: seq[int] | |
indexFields(Foo) | |
let test = Foo(a: 0, b: "hello", c: @[1,2,3]) | |
echo repr test[0] | |
echo repr test[1] | |
echo repr test[2] | |
#TODO: bounds checking |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment