Would something like the following work?
    
    
    # Free Public License 1.0.0
    #
    # Permission to use, copy, modify, and/or distribute this software for
    # any purpose with or without fee is hereby granted.
    #
    # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
    # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
    # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
    # AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
    # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
    # PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
    # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
    # PERFORMANCE OF THIS SOFTWARE.
    
    import macros
    
    macro make*(e: untyped): auto =
      var tp, call: NimNode
      let sym = genSym(nskVar)
      case e.kind
      of nnkCall:
        case e[0].kind
        of nnkDotExpr:
          tp = e[0][0]
          call = newCall(e[0][1])
          add(call, sym)
          for i in 1..len(e)-1:
            add(call, e[i])
        of nnkIdent:
          tp = e[0]
          call = newCall(!"init", sym)
        else:
          error("not a constructor call")
      of nnkDotExpr:
        tp = e[0]
        call = newCall(e[1], sym)
      else:
        error("not a constructor call")
      expectKind(tp, nnkIdent)
      result = quote do:
        var `sym` = `tp`()
        `call`
        `sym`
    
    when isMainModule:
      import strutils
      
      type Obj = ref object {.inheritable.}
        x: int
      
      type Obj2 = ref object of Obj
        y: int
      
      proc init(ob: Obj) =
        ob.x = 1
      
      proc init(ob: Obj, z: int) =
        ob.x = z
      
      proc fromString(ob: Obj, s: string) =
        ob.x = s.parseInt
      
      proc fromMin(ob: Obj, a, b: int) =
        ob.x = min(a, b)
      
      proc fromPair(ob: Obj2, pair: (int, int)) =
        ob.x = pair[0]
        ob.y = pair[1]
      
      proc `$`(ob: Obj): string = "Obj(x: " & $ob.x & ")"
      proc `$`(ob: Obj2): string = "Obj2(x: " & $ob.x & ", y: " & $ob.y & ")"
      
      var a1 = make Obj.init
      var a2 = make Obj.init(2)
      var a3 = make Obj.init()
      var a4 = make Obj.fromString("99")
      var a5 = make Obj.fromMin(314, 2718)
      var a6 = make Obj()
      var a7 = make Obj2.init()
      var a8 = make Obj2.fromString("314")
      var a9 = make Obj2.fromPair((10, 20))
      
      echo a1
      echo a2
      echo a3
      echo a4
      echo a5
      echo a6
      echo a7
      echo a8
      echo a9
    

Note that you can use methods in lieu of procs, too, if you want type-specific 
initialization. The macro simply is turned into a constructor call, followed by 
a call to the initialization proc/method, followed by the expression returning 
the created object.

Reply via email to