Fixed some whitespace issues and added init variables.
This commit is contained in:
parent
2e48f48cd8
commit
f3e7bee8e7
1 changed files with 267 additions and 245 deletions
126
oop_macro.nim
126
oop_macro.nim
|
|
@ -4,30 +4,52 @@ import strutils
|
|||
{.hint[XDeclaredButNotUsed]: off.}
|
||||
|
||||
macro new*(obj: untyped): untyped {.immediate.}=
|
||||
## Creates a new instance of the class
|
||||
## and calls the init() method on it
|
||||
if obj.kind == nnkObjConstr:
|
||||
# Only if the node is an object constructor
|
||||
template init_object(obj)=
|
||||
var init_obj = obj
|
||||
when compiles(init_obj.init()):
|
||||
init_obj.init()
|
||||
init_obj
|
||||
result = getAst(init_object(obj))
|
||||
if obj.kind == nnkObjConstr or obj.kind == nnkCall:
|
||||
var args: seq[NimNode] = @[]
|
||||
var new_obj = copyNimTree(obj)
|
||||
|
||||
# delete the parameters from the object
|
||||
# since we are going to use init() instead
|
||||
new_obj.del(1, len(new_obj)-1)
|
||||
|
||||
# create a symbol that we can use
|
||||
var sym = genSym(nskVar, "init_obj")
|
||||
|
||||
# self = init_obj
|
||||
var self_eq = newNimNode(nnkExprEqExpr).add(ident"self", sym)
|
||||
|
||||
args.add(self_eq)
|
||||
|
||||
for ch in obj.children:
|
||||
if ch.kind == nnkExprColonExpr:
|
||||
# some_arg = some_val
|
||||
args.add(newNimNode(nnkExprEqExpr).add(ch[0], ch[1]))
|
||||
|
||||
# init(self=init_obj, some_arg=someval, ...)
|
||||
var init_call = newCall(ident"init", args)
|
||||
|
||||
template new_object(symbol, obj_node, init_func)=
|
||||
var symbol = obj_node
|
||||
when compiles(init_func):
|
||||
init_func
|
||||
symbol
|
||||
|
||||
result = getAst(new_object(sym, new_obj, init_call))
|
||||
else:
|
||||
# Otherwise, just revert to system.new
|
||||
template init_object(obj)=
|
||||
# otherwise, just call system.new on the object
|
||||
# since we don't care about it
|
||||
template new_object(obj)=
|
||||
var init_obj = obj
|
||||
system.new(init_obj)
|
||||
|
||||
result = getAst(init_object(obj))
|
||||
result = getAst(new_object(obj))
|
||||
|
||||
|
||||
macro class*(head: untyped, body: untyped): untyped=
|
||||
macro class*(head: untyped, body: untyped): untyped =
|
||||
|
||||
# object reference name inside methods.
|
||||
# ie: self, self
|
||||
let obj_reference = "self"
|
||||
var export_class: bool = false # whether or not to export the class to other modules
|
||||
var export_class: bool = false
|
||||
|
||||
var typeName, baseName: NimNode
|
||||
|
||||
|
|
@ -54,7 +76,7 @@ macro class*(head: untyped, body: untyped): untyped=
|
|||
# -----------
|
||||
# Infix
|
||||
# Ident !"*"
|
||||
# Ident !"Animal"
|
||||
# Ident !"Animal
|
||||
# Prefix
|
||||
# Ident !"of"
|
||||
# Ident !"RootObj"
|
||||
|
|
@ -116,6 +138,22 @@ macro class*(head: untyped, body: untyped): untyped=
|
|||
# return `baseName`(self)
|
||||
# result.add(super)
|
||||
|
||||
template set_node_name(n2, proc_name, type_name)=
|
||||
if n2.name.kind == nnkIdent:
|
||||
proc_name = $(n2.name.toStrLit())
|
||||
n2.name = ident(proc_name & type_name)
|
||||
elif n2.name.kind == nnkPostFix:
|
||||
if n2.name[1].kind == nnkIdent:
|
||||
proc_name = $(n2.name[1].toStrLit())
|
||||
n2.name[1] = ident(proc_name & type_name)
|
||||
elif n2.name[1].kind == nnkAccQuoted:
|
||||
proc_name = $(n2.name[1][0].toStrLit())
|
||||
n2.name[1][0] = ident(proc_name & type_name)
|
||||
elif n2.name.kind == nnkAccQuoted:
|
||||
proc_name = $(n2.name[0].toStrLit())
|
||||
n2.name[0] = ident(proc_name & type_name)
|
||||
result.add(n2)
|
||||
|
||||
# Make forward declarations so that function order
|
||||
# does not matter, just like in real OOP!
|
||||
for node in body.children:
|
||||
|
|
@ -134,20 +172,7 @@ macro class*(head: untyped, body: untyped): untyped=
|
|||
let type_name = $(typeName.toStrLit())
|
||||
var proc_name = ""
|
||||
|
||||
if n2.name.kind == nnkIdent:
|
||||
proc_name = $(n2.name.toStrLit())
|
||||
n2.name = ident(proc_name & type_name)
|
||||
elif n2.name.kind == nnkPostFix:
|
||||
if n2.name[1].kind == nnkIdent:
|
||||
proc_name = $(n2.name[1].toStrLit())
|
||||
n2.name[1] = ident(proc_name & type_name)
|
||||
elif n2.name[1].kind == nnkAccQuoted:
|
||||
proc_name = $(n2.name[1][0].toStrLit())
|
||||
n2.name[1][0] = ident(proc_name & type_name)
|
||||
elif n2.name.kind == nnkAccQuoted:
|
||||
proc_name = $(n2.name[0].toStrLit())
|
||||
n2.name[0] = ident(proc_name & type_name)
|
||||
result.add(n2)
|
||||
set_node_name(n2, proc_name, type_name)
|
||||
else:
|
||||
discard
|
||||
|
||||
|
|
@ -169,21 +194,7 @@ macro class*(head: untyped, body: untyped): untyped=
|
|||
var proc_name = $(n2.name.toStrLit())
|
||||
var is_assignment = proc_name.contains("=")
|
||||
|
||||
if n2.name.kind == nnkIdent:
|
||||
proc_name = $(n2.name.toStrLit())
|
||||
n2.name = ident(proc_name & type_name)
|
||||
elif n2.name.kind == nnkPostFix:
|
||||
if n2.name[1].kind == nnkIdent:
|
||||
proc_name = $(n2.name[1].toStrLit())
|
||||
n2.name[1] = ident(proc_name & type_name)
|
||||
elif n2.name[1].kind == nnkAccQuoted:
|
||||
proc_name = $(n2.name[1][0].toStrLit())
|
||||
n2.name[1][0] = ident(proc_name & type_name)
|
||||
elif n2.name.kind == nnkAccQuoted:
|
||||
proc_name = $(n2.name[0].toStrLit())
|
||||
n2.name[0] = ident(proc_name & type_name)
|
||||
|
||||
result.add(n2)
|
||||
set_node_name(n2, proc_name, type_name)
|
||||
|
||||
# simply call the class method from here
|
||||
# proc procName=
|
||||
|
|
@ -265,9 +276,16 @@ macro class*(head: untyped, body: untyped): untyped=
|
|||
result.insert(0, type_decl)
|
||||
|
||||
|
||||
class Animal* of RootObj: #exports the class. Need to use RootObj for exports
|
||||
var name: string
|
||||
var age: int
|
||||
class Animal of RootObj:
|
||||
var
|
||||
name: string
|
||||
age: int
|
||||
|
||||
method init*(name: string, age: int)=
|
||||
self.name = name
|
||||
self.age = age
|
||||
echo "I am a new Animal, ", self.name
|
||||
|
||||
method stuff(s:string): string = s
|
||||
method vocalize: string = "..."
|
||||
method age_human_yrs: int = self.age # `self` is injected
|
||||
|
|
@ -282,11 +300,12 @@ class Cat of Animal:
|
|||
self.vocalize_animal() & "meow"
|
||||
|
||||
class Tiger of Cat:
|
||||
method init()=
|
||||
method init(name: string="Bob", age: int)=
|
||||
self.init_animal(name, age)
|
||||
echo "I am a new tiger"
|
||||
method vocalize: string =
|
||||
# no need for super.super!
|
||||
self.vocalize_animal() & "Rawr!" & self.vocalize_cat()
|
||||
self.vocalize_animal() & "Rawr!"
|
||||
|
||||
if isMainModule:
|
||||
var animals: seq[Animal] = @[]
|
||||
|
|
@ -299,10 +318,13 @@ if isMainModule:
|
|||
echo a.age_human_yrs()
|
||||
|
||||
# prints:
|
||||
# I am a new Animal, Sparky
|
||||
# I am a new Animal, Mitten
|
||||
# I am a new Animal, Jean
|
||||
# I am a new tiger
|
||||
# Sparky says woof
|
||||
# 70
|
||||
# Mitten says ...meow
|
||||
# 10
|
||||
# Jean says ...Rawr!...meow
|
||||
# Jean says ...Rawr!
|
||||
# 2
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue