I need to convert a type section with object definitions that utilize custom attribute pragmas into a type section with the same object definitions, but with the pragmas stripped out and converted to setter procedures.
So, this:
dbSchema:
type
Person* = ref object
name {.required, maxLength: 10}: string
should become this:
type
Person* = ref object
name: string
proc `name=`*(self: var Person, value: string) {.maxLength: 10,
required.} =
name = value
proc name*(self: Person): string = name
It can be done with brute force, by breaking the original type section into primitives and constructing the new section from them.
My question is, is there an easier way to do that? In other words, how would a seasoned Nim developer approach such task?
dumpTree is what you are looking for.
import macros
dumpTree:
type
Person* = ref object
name: string
proc `name=`*(self: var Person, value: string) {.maxLength: 10,
required.} =
name = value
proc name*(self: Person): string = name
AFAIU dumpTree will let me get the AST of the code block passed to it. But the question is, how do I effectively iterate over the AST without hardcoded indices and a ton of nested loops.
I probably should have formulated the question more clearly. I have a generic type section which differs from a regular one only by having custom pragmas for attributes. I need a generic way—a programming pattern, idiom, or Nim construct—to extract these pragmas and strip them out of the type section.
As I'm thinking about it now, it seems like there's no easy way out: you just have to parse the AST manually and them manually rebuild it. I was just thinking maybe there was a convenient tool for that I have overlooked.
Something to inspire you:
import macros
template recursive(node, action): untyped {.dirty.} =
proc helper(n: NimNode): NimNode {.gensym.} =
action
result = copyNimNode(n)
for i in 0 ..< n.len:
result.add helper(n[i])
helper(node)
template match(n, x): untyped =
template arg: untyped = x
n == getAst(arg())[0]
macro replace90by100(n: untyped): untyped =
recursive(n):
if match(n, 90):
return newLit(100)
echo replace90by100(@[90, 100, 90])