Hi y'all!

I wrote a macro for conveniently declaring widget types when using 
[traitor](https://github.com/beef331/traitor), it is used to create a type that 
conforms to the interface built with traitor with the corresponding member 
variables. The widget type is generic, where the parameter is the type of the 
display that is used, and with the display also comes the type of color that is 
used. In the type definition I use 
    
    
    fgcolor*: typeof(T.color)
    
    Run

which works fine when used directly in the code, but does cause `Error: no 
field symbol` when used within a macro.

Here is the reduced code with the macro:
    
    
    import std/macros
    import std/genasts
    import traitor
    
    
    type
        AnyDisplay*[T] = concept display
            display.color is T
        
        TestDisplay = ref object
            color: int
    
    
    type
        Widgetable* = distinct tuple[
            setPos: proc(a: Atom, x,y: int) {.nimcall.},
            getx: proc(a: Atom): int {.nimcall.},
        ]
    
    
    implTrait Widgetable
    
    
    macro implementWidget*(ast: untyped): untyped =
        
        var
            name = ast[0][0][0][1]
            self = newIdentNode("self")
        
        
        result = newNimNode(nnkStmtList)
        result.add(ast)
        
        var
            base = genAst(name, self) do:
                type
                    Widget*[T: AnyDisplay] = ref object
                        fgcolor*: typeof(T.color)
                        display*: T
                        x: int
                        y: int
        
        # add variables from base to resulting type
        if result[0][0].kind == nnkTypeSection:
            if result[0][0][0].kind == nnkTypeDef:
                if result[0][0][0][2].kind == nnkRefTy:
                    if result[0][0][0][2][0].kind == nnkObjectTy:
                        if result[0][0][0][2][0][2].kind == nnkRecList:
                            for rec in base[0][2][0][2]:
                                result[0][0][0][2][0][2].add(rec)
        
        var
            fg = newIdentNode("fg")
            bg = newIdentNode("bg")
            x = newIdentNode("x")
            y = newIdentNode("y")
        
        # add procs needed for beeing valid "Widgetable" trait
        result.add genAst(name, self, fg, x, y) do:
            proc setfgColor*[T](self: var name[T], fg: auto) =
                self.fgcolor = fg
            
            proc setPos*[T](self: var name[T], x,y: int) =
                self.x = x
                self.y = y
            
            proc getx*[T](self: name[T]): int =
                return self.x
        
        # call macro that generates trait converter
        result.add genAst(name) do:
            emitConverter name, Widgetable
        
        echo result.repr
    
    
    implementWidget:
        type
            Label*[T] = ref object
                text: string
    
    var
        disp: TestDisplay
        foo: Label[TestDisplay]
    
    
    Run

And here is the code without the macro, using the code that is printed with 
`echo result.repr` at the end of macro:
    
    
    import std/macros
    import std/genasts
    import traitor
    
    
    type
        AnyDisplay*[T] = concept display
            display.color is T
        
        TestDisplay = ref object
            color: int
    
    
    type
        Widgetable* = distinct tuple[
            setPos: proc(a: Atom, x,y: int) {.nimcall.},
            getx: proc(a: Atom): int {.nimcall.},
        ]
    
    
    implTrait Widgetable
    
    type
      Label*[T] = ref object
        text: string
        fgcolor*: typeof(T.color)
        display*: T
        x: int
        y: int
    proc setfgColor*[T](self: var Label[T]; fg: auto) =
      self.fgcolor = fg
    
    proc setPos*[T](self: var Label[T]; x, y: int) =
      self.x = x
      self.y = y
    
    proc getx*[T](self: Label[T]): int =
      return self.x
    
    emitConverter Label, Widgetable
    var
        disp: TestDisplay
        foo: Label[TestDisplay]
    
    
    Run

I don't understand why the code works when I just copy the output of the macro, 
but not when macro itself is used ...

Reply via email to