123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- package odin_ast
- import "core:fmt"
- // A Visitor's visit procedure is invoked for each node encountered by walk
- // If the result visitor is not nil, walk visits each of the children of node with the new visitor,
- // followed by a call of v.visit(v, nil)
- Visitor :: struct {
- visit: proc(visitor: ^Visitor, node: ^Node) -> ^Visitor,
- data: rawptr,
- }
- // inspect traverses an AST in depth-first order
- // It starts by calling f(node), and node must be non-nil
- // If f returns true, inspect invokes f recursively for each of the non-nil children of node,
- // followed by a call of f(nil)
- inspect :: proc(node: ^Node, f: proc(^Node) -> bool) {
- v := &Visitor{
- visit = proc(v: ^Visitor, node: ^Node) -> ^Visitor {
- f := (proc(^Node) -> bool)(v.data);
- if f(node) {
- return v;
- }
- return nil;
- },
- data = rawptr(f),
- };
- walk(v, node);
- }
- // walk traverses an AST in depth-first order: It starts by calling v.visit(v, node), and node must not be nil
- // If the visitor returned by v.visit(v, node) is not nil, walk is invoked recursively with the new visitor for
- // each of the non-nil children of node, followed by a call of the new visit procedure
- walk :: proc(v: ^Visitor, node: ^Node) {
- walk_expr_list :: proc(v: ^Visitor, list: []^Expr) {
- for x in list {
- walk(v, x);
- }
- }
- walk_stmt_list :: proc(v: ^Visitor, list: []^Stmt) {
- for x in list {
- walk(v, x);
- }
- }
- walk_attribute_list :: proc(v: ^Visitor, list: []^Attribute) {
- for x in list {
- walk(v, x);
- }
- }
- v := v;
- if v = v->visit(node); v == nil {
- return;
- }
- switch n in &node.derived {
- case File:
- if n.docs != nil {
- walk(v, n.docs);
- }
- walk_stmt_list(v, n.decls[:]);
- case Package:
- for _, f in n.files {
- walk(v, f);
- }
- case Comment_Group:
- // empty
- case Bad_Expr:
- case Ident:
- case Implicit:
- case Undef:
- case Basic_Lit:
- case Basic_Directive:
- case Ellipsis:
- if n.expr != nil {
- walk(v, n.expr);
- }
- case Proc_Lit:
- walk(v, n.type);
- walk(v, n.body);
- walk_expr_list(v, n.where_clauses);
- case Comp_Lit:
- if n.type != nil {
- walk(v, n.type);
- }
- walk_expr_list(v, n.elems);
- case Tag_Expr:
- walk(v, n.expr);
- case Unary_Expr:
- walk(v, n.expr);
- case Binary_Expr:
- walk(v, n.left);
- walk(v, n.right);
- case Paren_Expr:
- walk(v, n.expr);
- case Selector_Expr:
- walk(v, n.expr);
- walk(v, n.field);
- case Implicit_Selector_Expr:
- walk(v, n.field);
- case Selector_Call_Expr:
- walk(v, n.expr);
- walk(v, n.call);
- case Index_Expr:
- walk(v, n.expr);
- walk(v, n.index);
- case Deref_Expr:
- walk(v, n.expr);
- case Slice_Expr:
- walk(v, n.expr);
- if n.low != nil {
- walk(v, n.low);
- }
- if n.high != nil {
- walk(v, n.high);
- }
- case Call_Expr:
- walk(v, n.expr);
- walk_expr_list(v, n.args);
- case Field_Value:
- walk(v, n.field);
- walk(v, n.value);
- case Ternary_Expr:
- walk(v, n.cond);
- walk(v, n.x);
- walk(v, n.y);
- case Ternary_If_Expr:
- walk(v, n.x);
- walk(v, n.cond);
- walk(v, n.y);
- case Ternary_When_Expr:
- walk(v, n.x);
- walk(v, n.cond);
- walk(v, n.y);
- case Type_Assertion:
- walk(v, n.expr);
- if n.type != nil {
- walk(v, n.type);
- }
- case Type_Cast:
- walk(v, n.type);
- walk(v, n.expr);
- case Auto_Cast:
- walk(v, n.expr);
- case Inline_Asm_Expr:
- walk_expr_list(v, n.param_types);
- walk(v, n.return_type);
- walk(v, n.constraints_string);
- walk(v, n.asm_string);
- case Bad_Stmt:
- case Empty_Stmt:
- case Expr_Stmt:
- walk(v, n.expr);
- case Tag_Stmt:
- walk(v, n.stmt);
- case Assign_Stmt:
- walk_expr_list(v, n.lhs);
- walk_expr_list(v, n.rhs);
- case Block_Stmt:
- if n.label != nil {
- walk(v, n.label);
- }
- walk_stmt_list(v, n.stmts);
- case If_Stmt:
- if n.label != nil {
- walk(v, n.label);
- }
- if n.init != nil {
- walk(v, n.init);
- }
- walk(v, n.cond);
- walk(v, n.body);
- if n.else_stmt != nil {
- walk(v, n.else_stmt);
- }
- case When_Stmt:
- walk(v, n.cond);
- walk(v, n.body);
- if n.else_stmt != nil {
- walk(v, n.else_stmt);
- }
- case Return_Stmt:
- walk_expr_list(v, n.results);
- case Defer_Stmt:
- walk(v, n.stmt);
- case For_Stmt:
- if n.label != nil {
- walk(v, n.label);
- }
- if n.init != nil {
- walk(v, n.init);
- }
- if n.cond != nil {
- walk(v, n.cond);
- }
- if n.post != nil {
- walk(v, n.post);
- }
- walk(v, n.body);
- case Range_Stmt:
- if n.label != nil {
- walk(v, n.label);
- }
- for val in n.vals {
- if val != nil {
- walk(v, val);
- }
- }
- walk(v, n.expr);
- walk(v, n.body);
- case Inline_Range_Stmt:
- if n.label != nil {
- walk(v, n.label);
- }
- if n.val0 != nil {
- walk(v, n.val0);
- }
- if n.val1 != nil {
- walk(v, n.val1);
- }
- walk(v, n.expr);
- walk(v, n.body);
- case Case_Clause:
- walk_expr_list(v, n.list);
- walk_stmt_list(v, n.body);
- case Switch_Stmt:
- if n.label != nil {
- walk(v, n.label);
- }
- if n.init != nil {
- walk(v, n.init);
- }
- if n.cond != nil {
- walk(v, n.cond);
- }
- walk(v, n.body);
- case Type_Switch_Stmt:
- if n.label != nil {
- walk(v, n.label);
- }
- if n.tag != nil {
- walk(v, n.tag);
- }
- if n.expr != nil {
- walk(v, n.expr);
- }
- walk(v, n.body);
- case Branch_Stmt:
- if n.label != nil {
- walk(v, n.label);
- }
- case Using_Stmt:
- walk_expr_list(v, n.list);
- case Bad_Decl:
- case Value_Decl:
- if n.docs != nil {
- walk(v, n.docs);
- }
- walk_attribute_list(v, n.attributes[:]);
- walk_expr_list(v, n.names);
- if n.type != nil {
- walk(v, n.type);
- }
- walk_expr_list(v, n.values);
- if n.comment != nil {
- walk(v, n.comment);
- }
- case Package_Decl:
- if n.docs != nil {
- walk(v, n.docs);
- }
- if n.comment != nil {
- walk(v, n.comment);
- }
- case Import_Decl:
- if n.docs != nil {
- walk(v, n.docs);
- }
- if n.comment != nil {
- walk(v, n.comment);
- }
- case Foreign_Block_Decl:
- if n.docs != nil {
- walk(v, n.docs);
- }
- walk_attribute_list(v, n.attributes[:]);
- if n.foreign_library != nil {
- walk(v, n.foreign_library);
- }
- walk(v, n.body);
- case Foreign_Import_Decl:
- if n.docs != nil {
- walk(v, n.docs);
- }
- walk_attribute_list(v, n.attributes[:]);
- walk(v, n.name);
- if n.comment != nil {
- walk(v, n.comment);
- }
- case Proc_Group:
- walk_expr_list(v, n.args);
- case Attribute:
- walk_expr_list(v, n.elems);
- case Field:
- if n.docs != nil {
- walk(v, n.docs);
- }
- walk_expr_list(v, n.names);
- if n.type != nil {
- walk(v, n.type);
- }
- if n.default_value != nil {
- walk(v, n.default_value);
- }
- if n.comment != nil {
- walk(v, n.comment);
- }
- case Field_List:
- for x in n.list {
- walk(v, x);
- }
- case Typeid_Type:
- if n.specialization != nil {
- walk(v, n.specialization);
- }
- case Helper_Type:
- walk(v, n.type);
- case Distinct_Type:
- walk(v, n.type);
- case Poly_Type:
- walk(v, n.type);
- if n.specialization != nil {
- walk(v, n.specialization);
- }
- case Proc_Type:
- walk(v, n.params);
- walk(v, n.results);
- case Pointer_Type:
- walk(v, n.elem);
- case Array_Type:
- if n.tag != nil {
- walk(v, n.tag);
- }
- if n.len != nil {
- walk(v, n.len);
- }
- walk(v, n.elem);
- case Dynamic_Array_Type:
- if n.tag != nil {
- walk(v, n.tag);
- }
- walk(v, n.elem);
- case Struct_Type:
- if n.poly_params != nil {
- walk(v, n.poly_params);
- }
- if n.align != nil {
- walk(v, n.align);
- }
- walk_expr_list(v, n.where_clauses);
- walk(v, n.fields);
- case Union_Type:
- if n.poly_params != nil {
- walk(v, n.poly_params);
- }
- if n.align != nil {
- walk(v, n.align);
- }
- walk_expr_list(v, n.where_clauses);
- walk_expr_list(v, n.variants);
- case Enum_Type:
- if n.base_type != nil {
- walk(v, n.base_type);
- }
- walk_expr_list(v, n.fields);
- case Bit_Set_Type:
- walk(v, n.elem);
- if n.underlying != nil {
- walk(v, n.underlying);
- }
- case Map_Type:
- walk(v, n.key);
- walk(v, n.value);
- case Relative_Type:
- walk(v, n.tag);
- walk(v, n.type);
- case:
- fmt.panicf("ast.walk: unexpected node type %T", n);
- }
- v->visit(nil);
- }
|