Port the class macro from deprecated: stmt, expr (#42)

* Port the class macro from deprecated: stmt, expr

* Made changes

* Address comments

* Update oop_macro.md
This commit is contained in:
konqoro 2016-11-07 18:18:23 +02:00 • committed by Flaviu Tamas
commit 0cd37a40ef

View file

@ -43,9 +43,9 @@ To get that nice notation, we can use a macro:
```nimrod ```nimrod
import macros import macros
macro class*(head: expr, body: stmt): stmt {.immediate.} = macro class*(head, body: untyped): untyped =
# The macro is immediate so that it doesn't # The macro is immediate, since all its parameters are untyped.
# resolve identifiers passed to it # This means, it doesn't resolve identifiers passed to it.
var typeName, baseName: NimNode var typeName, baseName: NimNode
@ -55,6 +55,7 @@ macro class*(head: expr, body: stmt): stmt {.immediate.} =
# -------------------- # --------------------
# Ident !"Animal" # Ident !"Animal"
typeName = head typeName = head
baseName = ident("RootObj")
elif head.kind == nnkInfix and $head[0] == "of": elif head.kind == nnkInfix and $head[0] == "of":
# `head` is expression `typeName of baseClass` # `head` is expression `typeName of baseClass`
@ -70,6 +71,34 @@ macro class*(head: expr, body: stmt): stmt {.immediate.} =
else: else:
quit "Invalid node: " & head.lispRepr quit "Invalid node: " & head.lispRepr
# The following prints out the AST structure:
#
# import macros
# dumptree:
# type X = ref object of Y
# z: int
# --------------------
# StmtList
# TypeSection
# TypeDef
# Ident !"X"
# Empty
# RefTy
# ObjectTy
# Empty
# OfInherit
# Ident !"Y"
# RecList
# IdentDefs
# Ident !"z"
# Ident !"int"
# Empty
# create a type section in the result
result =
quote do:
type `typeName` = ref object of `baseName`
# echo treeRepr(body) # echo treeRepr(body)
# -------------------- # --------------------
# StmtList # StmtList
@ -105,9 +134,6 @@ macro class*(head: expr, body: stmt): stmt {.immediate.} =
# Ident !"this" # Ident !"this"
# Ident !"age" # Ident !"age"
# create a new stmtList for the result
result = newStmtList()
# var declarations will be turned into object fields # var declarations will be turned into object fields
var recList = newNimNode(nnkRecList) var recList = newNimNode(nnkRecList)
@ -119,7 +145,7 @@ macro class*(head: expr, body: stmt): stmt {.immediate.} =
of nnkMethodDef, nnkProcDef: of nnkMethodDef, nnkProcDef:
# inject `this: T` into the arguments # inject `this: T` into the arguments
let p = copyNimTree(node.params) let p = copyNimTree(node.params)
p.insert(1, newIdentDefs(ident"this", typeName)) p.insert(1, newIdentDefs(ident("this"), typeName))
node.params = p node.params = p
result.add(node) result.add(node)
@ -131,42 +157,11 @@ macro class*(head: expr, body: stmt): stmt {.immediate.} =
else: else:
result.add(node) result.add(node)
# The following prints out the AST structure:
#
# import macros
# dumptree:
# type X = ref object of Y
# z: int
# --------------------
# TypeSection
# TypeDef
# Ident !"X"
# Empty
# RefTy
# ObjectTy
# Empty
# OfInherit
# Ident !"Y"
# RecList
# IdentDefs
# Ident !"z"
# Ident !"int"
# Empty
result.insert(0,
if baseName == nil:
quote do:
type `typeName` = ref object of RootObj
else:
quote do:
type `typeName` = ref object of `baseName`
)
# Inspect the tree structure: # Inspect the tree structure:
# #
# echo result.treeRepr # echo result.treeRepr
# -------------------- # --------------------
# StmtList # StmtList
# StmtList
# TypeSection # TypeSection
# TypeDef # TypeDef
# Ident !"Animal" # Ident !"Animal"
@ -180,7 +175,7 @@ macro class*(head: expr, body: stmt): stmt {.immediate.} =
# MethodDef # MethodDef
# ... # ...
result[0][0][0][2][0][2] = recList result[0][0][2][0][2] = recList
# Lets inspect the human-readable version of the output # Lets inspect the human-readable version of the output
# echo repr(result) # echo repr(result)
@ -190,10 +185,10 @@ macro class*(head: expr, body: stmt): stmt {.immediate.} =
# name: string # name: string
# age: int # age: int
# #
# method vocalize(this: Animal): string = # method vocalize(this: Animal): string {.base.} =
# "..." # "..."
# #
# method age_human_yrs(this: Animal): int = # method age_human_yrs(this: Animal): int {.base.} =
# this.age # this.age
# --- # ---
@ -201,8 +196,8 @@ macro class*(head: expr, body: stmt): stmt {.immediate.} =
class Animal of RootObj: class Animal of RootObj:
var name: string var name: string
var age: int var age: int
method vocalize: string = "..." method vocalize: string {.base.} = "..." # use `base` pragma to annonate base methods
method age_human_yrs: int = this.age # `this` is injected method age_human_yrs: int {.base.} = this.age # `this` is injected
class Dog of Animal: class Dog of Animal:
method vocalize: string = "woof" method vocalize: string = "woof"