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:
parent
62aa71babf
commit
0cd37a40ef
1 changed files with 50 additions and 55 deletions
|
|
@ -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"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue