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.

Reply via email to