As a way to learn about writing complex macros, I want to write a memoize macro that's able support recursion. Basically, the following code:
@Memoize
func something(foo: Int) -> Int {
if foo > 0 {
return something(foo: foo - 1)
}
return foo
}
should produce a new function like this:
func memoizeSomething(foo: Int) -> Int {
var cache: [Int: Int] = [:]
func something(cache: inout [Int: Int], foo: Int) -> Int {
if let cached = cache[foo] {
return cached
}
if foo > 0 {
let result = something(cache: &cache, foo: foo - 1)
cache[foo] = result
return result
}
cache[foo] = foo
return foo
}
return something(cache: &cache, foo: foo)
}
The part I'm struggling with is patching a copy of the source function's body in expansion(of:providingPeersOf:in:)
. For starters, I want to walk the tree, find all function calls, and if it's a call to itself (recursion), inject a new argument to the list.
I can walk the tree, successfully find the function calls, and modify it… but I don't understand how to replace the old expression in the tree, or modify directly the existing one.
// How to implement this?
parent.replace(oldFuncCall, with: newFuncCall)
How can you walk an arbitrary syntax tree and modify it (replace some nodes with modified versions of said node, or insert new nodes)?