This is not possible with a macro. Macros are limited to compile time only, and
what you want to do is access the fields at run time.
Here is the code inline for reference:
import macros
macro assignField*(obj, fieldName, value: typed) =
let fieldSym = newIdentNode($`fieldName`)
result = quote do:
`obj`.`fieldSym`=`value`
type
SomeObj* = object
a*: int
b*: int
c*: int
var
foo = SomeObj()
for field in @["a", "c"]:
# this doesn't work
assignField(foo, field, 50)
# /usercode/in.nim(19, 14) template/generic instantiation of `assignField`
from here
# /usercode/in.nim(5, 12) Error: attempting to call undeclared routine:
'field='
# this works
assignField(foo, "a", 100)
assignField(foo, "c", 200)
block:
# this works
assignField(foo, "b", 300)
echo foo
Run
In `assignField(foo, field, 50)` above in the for loop, the compiler can only
infer the name you passed directly to the macro, which is `field`. So what the
compiler is doing is trying to call `foo.field = 50`, but field doesn't exist.
Since you are trying to use a seq to loop through (`for field in @["a",
"c"]:`), the compiler can't use that information since at run time a seq may
change. In theory, you could use a constant array, but I was unable to get it
to work since it seems that for loops always execute at runtime from the
compiler's point of view.