diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 36791b11e..dad71c9b0 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -43,8 +43,8 @@ Comment_Group :: struct { Node :: struct { pos: tokenizer.Pos, end: tokenizer.Pos, - derived: any, state_flags: Node_State_Flags, + derived: any, } @@ -266,11 +266,11 @@ Inline_Asm_Expr :: struct { tok: tokenizer.Token, param_types: []^Expr, return_type: ^Expr, - constraints_string: ^Expr, has_side_effects: bool, is_align_stack: bool, dialect: Inline_Asm_Dialect, open: tokenizer.Pos, + constraints_string: ^Expr, asm_string: ^Expr, close: tokenizer.Pos, } @@ -471,12 +471,12 @@ Foreign_Block_Decl :: struct { Foreign_Import_Decl :: struct { using node: Decl, docs: ^Comment_Group, + attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily foreign_tok: tokenizer.Token, import_tok: tokenizer.Token, name: ^Ident, collection_name: string, fullpaths: []string, - attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily comment: ^Comment_Group, } @@ -641,23 +641,23 @@ Struct_Type :: struct { tok_pos: tokenizer.Pos, poly_params: ^Field_List, align: ^Expr, - fields: ^Field_List, - name_count: int, where_token: tokenizer.Token, where_clauses: []^Expr, is_packed: bool, is_raw_union: bool, + fields: ^Field_List, + name_count: int, } Union_Type :: struct { using node: Expr, - tok_pos: tokenizer.Pos, - poly_params: ^Field_List, - align: ^Expr, - variants: []^Expr, - where_token: tokenizer.Token, + tok_pos: tokenizer.Pos, + poly_params: ^Field_List, + align: ^Expr, + is_maybe: bool, + where_token: tokenizer.Token, where_clauses: []^Expr, - is_maybe: bool, + variants: []^Expr, } Enum_Type :: struct { diff --git a/core/odin/ast/walk.odin b/core/odin/ast/walk.odin new file mode 100644 index 000000000..d86a2d2b0 --- /dev/null +++ b/core/odin/ast/walk.odin @@ -0,0 +1,369 @@ +package odin_ast + +import "core:fmt" + +Visitor :: struct { + visit: proc(visitor: ^Visitor, node: ^Node) -> ^Visitor, + data: rawptr, +} + +walk_ident_list :: proc(v: ^Visitor, list: []^Ident) { + for x in list { + walk(v, x); + } +} + +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_decl_list :: proc(v: ^Visitor, list: []^Decl) { + for x in list { + walk(v, x); + } +} +walk_attribute_list :: proc(v: ^Visitor, list: []^Attribute) { + for x in list { + walk(v, x); + } +} + + +walk :: proc(v: ^Visitor, node: ^Node) { + v := v; + if v = v->visit(node); v == nil { + return; + } + + switch n in &node.derived { + 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); + } + 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 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: + 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); + case Package_Decl: + case Import_Decl: + case Foreign_Block_Decl: + walk_attribute_list(v, n.attributes[:]); + if n.foreign_library != nil { + walk(v, n.foreign_library); + } + walk(v, n.body); + case Foreign_Import_Decl: + walk_attribute_list(v, n.attributes[:]); + walk(v, n.name); + + case Proc_Group: + walk_expr_list(v, n.args); + case Attribute: + walk_expr_list(v, n.elems); + case Field: + walk_expr_list(v, n.names); + if n.type != nil { + walk(v, n.type); + } + if n.default_value != nil { + walk(v, n.default_value); + } + 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 Opaque_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_Field_Type: + if n.align != nil { + walk(v, n.align); + } + for x in n.fields { + walk(v, x); + } + 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); +} + + + +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); +}