| 1 | module walker |
| 2 | |
| 3 | import v.ast |
| 4 | |
| 5 | // Visitor defines a visit method which is invoked by the walker in each node it encounters. |
| 6 | pub interface Visitor { |
| 7 | mut: |
| 8 | visit(node &ast.Node) ! |
| 9 | } |
| 10 | |
| 11 | pub type InspectorFn = fn (node &ast.Node, data voidptr) bool |
| 12 | |
| 13 | fn empty_callback(node &ast.Node, data voidptr) bool { |
| 14 | panic('empty ast.walker, node: ${voidptr(node)}, data: ${voidptr(data)}') |
| 15 | } |
| 16 | |
| 17 | struct Inspector { |
| 18 | inspector_callback InspectorFn = empty_callback |
| 19 | mut: |
| 20 | data voidptr |
| 21 | } |
| 22 | |
| 23 | pub fn (i &Inspector) visit(node &ast.Node) ! { |
| 24 | if i.inspector_callback(node, i.data) { |
| 25 | return |
| 26 | } |
| 27 | return error('') |
| 28 | } |
| 29 | |
| 30 | // inspect traverses and checks the AST node on a depth-first order and based on the data given |
| 31 | pub fn inspect(node &ast.Node, data voidptr, inspector_callback InspectorFn) { |
| 32 | mut inspector := Inspector{inspector_callback, data} |
| 33 | walk(mut inspector, node) |
| 34 | } |
| 35 | |
| 36 | // walk traverses the AST using the given visitor |
| 37 | pub fn walk(mut visitor Visitor, node &ast.Node) { |
| 38 | visitor.visit(node) or { return } |
| 39 | children := node.children() |
| 40 | for child_node in children { |
| 41 | walk(mut visitor, &child_node) |
| 42 | } |
| 43 | } |
| 44 | |