Untitled

Run Settings
LanguageNim
Language Version
Run Command
import macros import strutils macro ctor(none: untyped): auto {.immediate.} = let args = callsite() var prc: NimNode var allocator: NimNode var destructor: NimNode if args.len == 3: if args[1].kind != nnkBracket: error("Usage: {.ctor: [allocator: prc, destructor: dtor_prc]}") if args[2].kind != nnkProcDef: error("ctor pragma is used only with procedures") prc = args[2] var margs = args[1] for i in 0 ..< margs.len: if $margs[i][0] == "allocator": allocator = margs[i][1] elif $margs[i][0] == "destructor": destructor = margs[i][1] else: error("Unknown {.ctor.} paramater " & $margs[i][0]) else: if args[1].kind != nnkProcDef: error("ctor pragma is used only with procedures") prc = args[1] allocator = new_ident_node("new") if prc[3][1][1].kind != nnkVarTy: error("Constructor must have var non-ref type as first parameter") if prc[3][0].kind != nnkEmpty: error("Constructor must not have return type") var proc_name = $prc[0] if proc_name notin ["init", "init*"]: error("Constructor name must be `init` but is `" & proc_name & "`") var export_proc = proc_name.ends_with("*") var type_identifier = prc[3][1][1][0] var ctor = quote do: proc init(_: typedesc[`type_identifier`]): `type_identifier` = init(result) ctor = ctor[0] ctor[2] = prc[2] if export_proc: ctor[0] = new_nim_node(nnkPostfix).add( new_ident_node("*"), ctor[0] ) # Extend ctor with parameters of constructor for i in 2 ..< prc[3].len: ctor[3].add(prc[3][i]) # Passes ctor params to main init proc ctor[6][0][1] = new_ident_node("result") # otherwise result is taken from macro context. weird! for i in 2 ..< prc[3].len: ctor[6][0].add(prc[3][i][0]) var allc = quote do: proc new(_: typedesc[`type_identifier`]): ref `type_identifier` = var res: ref `type_identifier` `allocator`(res) init(res[]) return res allc = allc[0] allc[2] = prc[2] if destructor != nil: allc[6][1].add(destructor) if export_proc: allc[0] = new_nim_node(nnkPostfix).add( new_ident_node("*"), allc[0] ) # Extend allc with parameters of constructor for i in 2 ..< prc[3].len: allc[3].add(prc[3][i]) # Passes allc params to main init proc #allc[6][1][1] = new_ident_node("result") # otherwise result is taken from macro context. weird! #allc[6][2][1] = new_ident_node("result") for i in 2 ..< prc[3].len: allc[6][2].add(prc[3][i][0]) echo tree_repr(allc) result = new_stmt_list(prc, ctor, allc) when is_main_module: type Foo = object a: int Bar = object a: int proc destroy(self: ref Foo) = echo "done" proc custom_new(res: var ref Foo, dtor: proc (x: ref Foo) {.nimcall.}) = echo "allocating with custom allocator" var x: ref Foo new(x, dtor) res = x # proc init(self: var Foo, n: int) = # self.a = n # proc init(_: typedesc[Foo], n: int): Foo = # init(result, n) # proc new(_: typedesc[Foo], n: int): ref Foo = # custom_new(result, destroy) # init(result[], n) proc init(self: var Foo, n: int) {.ctor: [allocator: custom_new, destructor: destroy].} = self.a = n proc init(self: var Bar, n: int) {.ctor.} = self.a = n var f: Foo f.init(1) echo f.repr #echo Foo.init(2).repr echo Foo.new(3).repr
Editor Settings
Theme
Key bindings
Full width
Lines