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.