Hey all! I'm trying to write a macro that given a seq[string], let's assume it's @["me", "location", "city"] for this example, would produce this output:
globalObject["me"].value["location"].value["city"]
I came up with this recursive macro:
macro getFieldLocation(fields: static[seq[string]]): untyped =
if fields.len() == 1:
result = quote do:
globalObject[`newLit(fields[0])`]
else:
let field = newLit(fields[^1])
let leftSide = getFieldLocation(fields[0..^1])
result = `leftSide`.value[`field`]
echo result.repr
The problem is when I try to recur, the compiler reports this error:
Error: type mismatch: got <seq[string]>
but expected one of:
macro getFieldLocation(fields: static[seq[string]]): untyped
first type mismatch at position: 1
required type for fields: static[seq[string]]
but expression 'fields[
0 .. BackwardsIndex(1)]' is of type: seq[string]
expression: getFieldLocation(fields[
0 .. BackwardsIndex(1)])
How can I preserve the "staticness" of the seq so I can recur with it safely? Is it possible at all?
Something liiike
import tables
type
Obj = ref object
children: Table[string, Obj]
value: string
proc newObj():Obj=
result = new Obj
result.children=initTable[string, Obj]()
proc newObj(key:string,kids:Obj=newObj()):Obj=
result = new Obj
result.children={key:kids}.toTable()
proc `[]=`(o:Obj,k:string,val:string)=
o.children[k].value=val
proc `[]`(o:Obj,k:string):Obj=
o.children[k]
var rootobj = newObj("me",newObj("location",newObj("city")))
rootobj["me"]["location"]["city"]="Toledo"
proc getField(parent:Obj,f:seq[string]):string=
if f.len==1:
return parent[f[0]].value
else:
return getField(parent[f[0]],f[1..^1])
echo getField(rootobj,@["me","location","city"])
Thank you all very much for replying! A slightly tweaked version of Shirley's second idea worked. I didn't figure I could use parseStmt() (or that it even existed :P). This is what I ended up with:
macro getField(s: static seq[string]): untyped =
var res = &"globalObject[\"{s[0]}\"]"
for i in 1..<s.len():
res &= ".value"
res &= "[\"" & s[i] & "\"]"
result = parseStmt(res)
Again, thanks for helping!