Hi,
In the template I am trying to evaluate the boolean expression that is defined in terms tuple variable names. With one variable it is clear, we have a number of examples in the standard library: mapIt, allIt, filterIt and etc. But I am struggling to extend this approach for multiple variables where variable names come from tuple definition.
Basically, what I am trying to achieve is the following, but it doesn't compile. The injected variables get out of scope before they can be used.
type DataTable = tuple
id : seq[int]
name : seq[string]
age: seq[Natural]
proc len(dt: DataTable) : Natural =
for f in fields(dt):
return f.len
return 0
template mask(dt : DataTable, expr : untyped) : seq[bool] =
var result = newSeq[bool](dt.len)
for i in 0 ..< dt.len:
for name, value in fieldPairs(t):
let `name` {.inject.} = value[i]
result[i] = expr
result
echo mask(x, age >= 15 and isAlphaNumeric(name))
Thank you
I know it doesn't exactly meet your desired syntax but mimicking the standard library reads well and is consistent:
template maskIt(dt : DataTable, expr : untyped) : seq[bool] =
var result = newSeq[bool](dt.len)
for i in 0 ..< dt.len:
let it {.inject.} = (id:dt.id[i], name:dt.name[i], age:dt.age[i])
result[i] = expr
result
var x: DataTable
x = (id: @[1,2], name: @["john", "jeff"], age: @[30, 40])
echo maskIt(x, it.age >= 15 and isAlphaNumeric(it.name) )
echo maskIt(x, it.id == 1 )
Managed to write a suitable macro, posting solution for completeness:
type DataTable = tuple
id : seq[int]
name : seq[string]
age: seq[Natural]
proc len(dt: DataTable) : Natural =
for f in fields(dt):
return f.len
return 0
macro injectTupleOrObject(t: typed, index:typed): typed =
var tType = t.getTypeImpl
case tType.typeKind:
of ntyTuple: discard
of ntyObject: tType = tType[2]
else: error "Not a tuple or object"
result = newNimNode(nnkLetSection)
for field in tType:
let dotExpr = newDotExpr(t, newIdentNode($field[0]))
let brkExpr = newNimNode(nnkBracketExpr).add(dotExpr, index)
result.add(newIdentDefs(ident($field[0]), newEmptyNode(), brkExpr))
template mask(dt : DataTable, expr : untyped) : seq[bool] =
var result = newSeq[bool](dt.len)
for i in 0 ..< dt.len:
injectTupleOrObject(dt, i)
result[i] = expr
result
echo mask(x, age >= 15 and isAlphaNumeric(name))