From ad6ea3d6aa564ad228cf8883a8fd858135a16030 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Feb 2022 13:31:16 +0000 Subject: [PATCH 1/5] Replace `any` with `union` for subtyping in `core:odin/ast` --- core/odin/ast/ast.odin | 177 ++++++++++++++++++++++++++- core/odin/ast/clone.odin | 187 +++++++++++++++++------------ core/odin/ast/walk.odin | 154 ++++++++++++------------ core/odin/parser/parser.odin | 180 ++++++++++++++-------------- core/odin/printer/visit.odin | 226 ++++++++++++++++++++--------------- 5 files changed, 581 insertions(+), 343 deletions(-) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 8eb0def44..740299539 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -34,7 +34,7 @@ Node :: struct { pos: tokenizer.Pos, end: tokenizer.Pos, state_flags: Node_State_Flags, - derived: any, + derived: Any_Node, } Comment_Group :: struct { @@ -88,9 +88,11 @@ File :: struct { Expr :: struct { using expr_base: Node, + derived_expr: Any_Expr, } Stmt :: struct { using stmt_base: Node, + derived_stmt: Any_Stmt, } Decl :: struct { using decl_base: Stmt, @@ -541,7 +543,7 @@ unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) { return } for { - e, ok := val.derived.(Paren_Expr) + e, ok := val.derived.(^Paren_Expr) if !ok || e.expr == nil { break } @@ -758,4 +760,173 @@ Matrix_Type :: struct { row_count: ^Expr, column_count: ^Expr, elem: ^Expr, -} \ No newline at end of file +} + + +Any_Node :: union { + ^Package, + ^File, + ^Comment_Group, + + ^Bad_Expr, + ^Ident, + ^Implicit, + ^Undef, + ^Basic_Lit, + ^Basic_Directive, + ^Ellipsis, + ^Proc_Lit, + ^Comp_Lit, + ^Tag_Expr, + ^Unary_Expr, + ^Binary_Expr, + ^Paren_Expr, + ^Selector_Expr, + ^Implicit_Selector_Expr, + ^Selector_Call_Expr, + ^Index_Expr, + ^Deref_Expr, + ^Slice_Expr, + ^Matrix_Index_Expr, + ^Call_Expr, + ^Field_Value, + ^Ternary_If_Expr, + ^Ternary_When_Expr, + ^Or_Else_Expr, + ^Or_Return_Expr, + ^Type_Assertion, + ^Type_Cast, + ^Auto_Cast, + ^Inline_Asm_Expr, + + ^Proc_Group, + + ^Typeid_Type, + ^Helper_Type, + ^Distinct_Type, + ^Poly_Type, + ^Proc_Type, + ^Pointer_Type, + ^Multi_Pointer_Type, + ^Array_Type, + ^Dynamic_Array_Type, + ^Struct_Type, + ^Union_Type, + ^Enum_Type, + ^Bit_Set_Type, + ^Map_Type, + ^Relative_Type, + ^Matrix_Type, + + ^Bad_Stmt, + ^Empty_Stmt, + ^Expr_Stmt, + ^Tag_Stmt, + ^Assign_Stmt, + ^Block_Stmt, + ^If_Stmt, + ^When_Stmt, + ^Return_Stmt, + ^Defer_Stmt, + ^For_Stmt, + ^Range_Stmt, + ^Inline_Range_Stmt, + ^Case_Clause, + ^Switch_Stmt, + ^Type_Switch_Stmt, + ^Branch_Stmt, + ^Using_Stmt, + + ^Bad_Decl, + ^Value_Decl, + ^Package_Decl, + ^Import_Decl, + ^Foreign_Block_Decl, + ^Foreign_Import_Decl, + + ^Attribute, + ^Field, + ^Field_List, +} + + +Any_Expr :: union { + ^Bad_Expr, + ^Ident, + ^Implicit, + ^Undef, + ^Basic_Lit, + ^Basic_Directive, + ^Ellipsis, + ^Proc_Lit, + ^Comp_Lit, + ^Tag_Expr, + ^Unary_Expr, + ^Binary_Expr, + ^Paren_Expr, + ^Selector_Expr, + ^Implicit_Selector_Expr, + ^Selector_Call_Expr, + ^Index_Expr, + ^Deref_Expr, + ^Slice_Expr, + ^Matrix_Index_Expr, + ^Call_Expr, + ^Field_Value, + ^Ternary_If_Expr, + ^Ternary_When_Expr, + ^Or_Else_Expr, + ^Or_Return_Expr, + ^Type_Assertion, + ^Type_Cast, + ^Auto_Cast, + ^Inline_Asm_Expr, + + ^Proc_Group, + + ^Typeid_Type, + ^Helper_Type, + ^Distinct_Type, + ^Poly_Type, + ^Proc_Type, + ^Pointer_Type, + ^Multi_Pointer_Type, + ^Array_Type, + ^Dynamic_Array_Type, + ^Struct_Type, + ^Union_Type, + ^Enum_Type, + ^Bit_Set_Type, + ^Map_Type, + ^Relative_Type, + ^Matrix_Type, +} + + +Any_Stmt :: union { + ^Bad_Stmt, + ^Empty_Stmt, + ^Expr_Stmt, + ^Tag_Stmt, + ^Assign_Stmt, + ^Block_Stmt, + ^If_Stmt, + ^When_Stmt, + ^Return_Stmt, + ^Defer_Stmt, + ^For_Stmt, + ^Range_Stmt, + ^Inline_Range_Stmt, + ^Case_Clause, + ^Switch_Stmt, + ^Type_Switch_Stmt, + ^Branch_Stmt, + ^Using_Stmt, + + ^Bad_Decl, + ^Value_Decl, + ^Package_Decl, + ^Import_Decl, + ^Foreign_Block_Decl, + ^Foreign_Import_Decl, +} diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 1e3058678..723f7b90d 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -1,16 +1,25 @@ package odin_ast +import "core:intrinsics" import "core:mem" import "core:fmt" +import "core:reflect" import "core:odin/tokenizer" +_ :: intrinsics new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T { n, _ := mem.new(T) n.pos = pos n.end = end - n.derived = n^ + n.derived = n base: ^Node = n // dummy check _ = base // "Use" type to make -vet happy + when intrinsics.type_has_field(T, "derived_expr") { + n.derived_expr = n + } + when intrinsics.type_has_field(T, "derived_stmt") { + n.derived_stmt = n + } return n } @@ -61,228 +70,248 @@ clone_node :: proc(node: ^Node) -> ^Node { size := size_of(Node) align := align_of(Node) - ti := type_info_of(node.derived.id) + ti := reflect.union_variant_type_info(node.derived) if ti != nil { size = ti.size align = ti.align } - switch in node.derived { - case Package, File: + #partial switch in node.derived { + case ^Package, ^File: panic("Cannot clone this node type") } res := cast(^Node)mem.alloc(size, align) src: rawptr = node if node.derived != nil { - src = node.derived.data + src = (^rawptr)(&node.derived)^ } mem.copy(res, src, size) - res.derived.data = rawptr(res) - res.derived.id = node.derived.id + res_any: any + res_any.data = res + res_any.id = ti.id - switch r in &res.derived { - case Bad_Expr: - case Ident: - case Implicit: - case Undef: - case Basic_Lit: + reflect.set_union_value(res.derived, res_any) - case Ellipsis: + derived_expr := reflect.struct_field_value_by_name(res_any, "derived_expr", true) + derived_stmt := reflect.struct_field_value_by_name(res_any, "derived_stmt", true) + reflect.set_union_value(res.derived, derived_expr) + reflect.set_union_value(res.derived, derived_stmt) + + switch r in res.derived { + case ^Package, ^File: + case ^Bad_Expr: + case ^Ident: + case ^Implicit: + case ^Undef: + case ^Basic_Lit: + case ^Basic_Directive: + case ^Comment_Group: + + case ^Ellipsis: r.expr = clone(r.expr) - case Proc_Lit: + case ^Proc_Lit: r.type = auto_cast clone(r.type) r.body = clone(r.body) - case Comp_Lit: + case ^Comp_Lit: r.type = clone(r.type) r.elems = clone(r.elems) - case Tag_Expr: + case ^Tag_Expr: r.expr = clone(r.expr) - case Unary_Expr: + case ^Unary_Expr: r.expr = clone(r.expr) - case Binary_Expr: + case ^Binary_Expr: r.left = clone(r.left) r.right = clone(r.right) - case Paren_Expr: + case ^Paren_Expr: r.expr = clone(r.expr) - case Selector_Expr: + case ^Selector_Expr: r.expr = clone(r.expr) r.field = auto_cast clone(r.field) - case Implicit_Selector_Expr: + case ^Implicit_Selector_Expr: r.field = auto_cast clone(r.field) - case Selector_Call_Expr: + case ^Selector_Call_Expr: r.expr = clone(r.expr) r.call = auto_cast clone(r.call) - case Index_Expr: + case ^Index_Expr: r.expr = clone(r.expr) r.index = clone(r.index) - case Matrix_Index_Expr: + case ^Matrix_Index_Expr: r.expr = clone(r.expr) r.row_index = clone(r.row_index) r.column_index = clone(r.column_index) - case Deref_Expr: + case ^Deref_Expr: r.expr = clone(r.expr) - case Slice_Expr: + case ^Slice_Expr: r.expr = clone(r.expr) r.low = clone(r.low) r.high = clone(r.high) - case Call_Expr: + case ^Call_Expr: r.expr = clone(r.expr) r.args = clone(r.args) - case Field_Value: + case ^Field_Value: r.field = clone(r.field) r.value = clone(r.value) - case Ternary_If_Expr: + case ^Ternary_If_Expr: r.x = clone(r.x) r.cond = clone(r.cond) r.y = clone(r.y) - case Ternary_When_Expr: + case ^Ternary_When_Expr: r.x = clone(r.x) r.cond = clone(r.cond) r.y = clone(r.y) - case Or_Else_Expr: + case ^Or_Else_Expr: r.x = clone(r.x) r.y = clone(r.y) - case Or_Return_Expr: + case ^Or_Return_Expr: r.expr = clone(r.expr) - case Type_Assertion: + case ^Type_Assertion: r.expr = clone(r.expr) r.type = clone(r.type) - case Type_Cast: + case ^Type_Cast: r.type = clone(r.type) r.expr = clone(r.expr) - case Auto_Cast: + case ^Auto_Cast: r.expr = clone(r.expr) - case Inline_Asm_Expr: + case ^Inline_Asm_Expr: r.param_types = clone(r.param_types) r.return_type = clone(r.return_type) r.constraints_string = clone(r.constraints_string) r.asm_string = clone(r.asm_string) - case Bad_Stmt: + case ^Bad_Stmt: // empty - case Empty_Stmt: + case ^Empty_Stmt: // empty - case Expr_Stmt: + case ^Expr_Stmt: r.expr = clone(r.expr) - case Tag_Stmt: + case ^Tag_Stmt: r.stmt = clone(r.stmt) - case Assign_Stmt: + case ^Assign_Stmt: r.lhs = clone(r.lhs) r.rhs = clone(r.rhs) - case Block_Stmt: + case ^Block_Stmt: r.label = clone(r.label) r.stmts = clone(r.stmts) - case If_Stmt: + case ^If_Stmt: r.label = clone(r.label) r.init = clone(r.init) r.cond = clone(r.cond) r.body = clone(r.body) r.else_stmt = clone(r.else_stmt) - case When_Stmt: + case ^When_Stmt: r.cond = clone(r.cond) r.body = clone(r.body) r.else_stmt = clone(r.else_stmt) - case Return_Stmt: + case ^Return_Stmt: r.results = clone(r.results) - case Defer_Stmt: + case ^Defer_Stmt: r.stmt = clone(r.stmt) - case For_Stmt: + case ^For_Stmt: r.label = clone(r.label) r.init = clone(r.init) r.cond = clone(r.cond) r.post = clone(r.post) r.body = clone(r.body) - case Range_Stmt: + case ^Range_Stmt: r.label = clone(r.label) r.vals = clone(r.vals) r.expr = clone(r.expr) r.body = clone(r.body) - case Case_Clause: + case ^Inline_Range_Stmt: + r.label = clone(r.label) + r.val0 = clone(r.val0) + r.val1 = clone(r.val1) + r.expr = clone(r.expr) + r.body = clone(r.body) + case ^Case_Clause: r.list = clone(r.list) r.body = clone(r.body) - case Switch_Stmt: + case ^Switch_Stmt: r.label = clone(r.label) r.init = clone(r.init) r.cond = clone(r.cond) r.body = clone(r.body) - case Type_Switch_Stmt: + case ^Type_Switch_Stmt: r.label = clone(r.label) r.tag = clone(r.tag) r.expr = clone(r.expr) r.body = clone(r.body) - case Branch_Stmt: + case ^Branch_Stmt: r.label = auto_cast clone(r.label) - case Using_Stmt: + case ^Using_Stmt: r.list = clone(r.list) - case Bad_Decl: - case Value_Decl: + case ^Bad_Decl: + case ^Value_Decl: r.attributes = clone(r.attributes) r.names = clone(r.names) r.type = clone(r.type) r.values = clone(r.values) - case Package_Decl: - case Import_Decl: - case Foreign_Block_Decl: + case ^Package_Decl: + case ^Import_Decl: + case ^Foreign_Block_Decl: r.attributes = clone(r.attributes) r.foreign_library = clone(r.foreign_library) r.body = clone(r.body) - case Foreign_Import_Decl: + case ^Foreign_Import_Decl: r.name = auto_cast clone(r.name) - case Proc_Group: + case ^Proc_Group: r.args = clone(r.args) - case Attribute: + case ^Attribute: r.elems = clone(r.elems) - case Field: + case ^Field: r.names = clone(r.names) r.type = clone(r.type) r.default_value = clone(r.default_value) - case Field_List: + case ^Field_List: r.list = clone(r.list) - case Typeid_Type: + case ^Typeid_Type: r.specialization = clone(r.specialization) - case Helper_Type: + case ^Helper_Type: r.type = clone(r.type) - case Distinct_Type: + case ^Distinct_Type: r.type = clone(r.type) - case Poly_Type: + case ^Poly_Type: r.type = auto_cast clone(r.type) r.specialization = clone(r.specialization) - case Proc_Type: + case ^Proc_Type: r.params = auto_cast clone(r.params) r.results = auto_cast clone(r.results) - case Pointer_Type: + case ^Pointer_Type: r.elem = clone(r.elem) - case Multi_Pointer_Type: + case ^Multi_Pointer_Type: r.elem = clone(r.elem) - case Array_Type: + case ^Array_Type: r.len = clone(r.len) r.elem = clone(r.elem) - case Dynamic_Array_Type: + case ^Dynamic_Array_Type: r.elem = clone(r.elem) - case Struct_Type: + case ^Struct_Type: r.poly_params = auto_cast clone(r.poly_params) r.align = clone(r.align) r.fields = auto_cast clone(r.fields) - case Union_Type: + case ^Union_Type: r.poly_params = auto_cast clone(r.poly_params) r.align = clone(r.align) r.variants = clone(r.variants) - case Enum_Type: + case ^Enum_Type: r.base_type = clone(r.base_type) r.fields = clone(r.fields) - case Bit_Set_Type: + case ^Bit_Set_Type: r.elem = clone(r.elem) r.underlying = clone(r.underlying) - case Map_Type: + case ^Map_Type: r.key = clone(r.key) r.value = clone(r.value) - case Matrix_Type: + case ^Matrix_Type: r.row_count = clone(r.row_count) r.column_count = clone(r.column_count) r.elem = clone(r.elem) + case ^Relative_Type: + r.tag = clone(r.tag) + r.type = clone(r.type) case: fmt.panicf("Unhandled node kind: %T", r) } diff --git a/core/odin/ast/walk.odin b/core/odin/ast/walk.odin index d0d17cc9e..7241d283f 100644 --- a/core/odin/ast/walk.odin +++ b/core/odin/ast/walk.odin @@ -59,64 +59,64 @@ walk :: proc(v: ^Visitor, node: ^Node) { } switch n in &node.derived { - case File: + case ^File: if n.docs != nil { walk(v, n.docs) } walk_stmt_list(v, n.decls[:]) - case Package: + case ^Package: for _, f in n.files { walk(v, f) } - case Comment_Group: + case ^Comment_Group: // empty - case Bad_Expr: - case Ident: - case Implicit: - case Undef: - case Basic_Lit: - case Basic_Directive: - case Ellipsis: + 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: + case ^Proc_Lit: walk(v, n.type) walk(v, n.body) walk_expr_list(v, n.where_clauses) - case Comp_Lit: + case ^Comp_Lit: if n.type != nil { walk(v, n.type) } walk_expr_list(v, n.elems) - case Tag_Expr: + case ^Tag_Expr: walk(v, n.expr) - case Unary_Expr: + case ^Unary_Expr: walk(v, n.expr) - case Binary_Expr: + case ^Binary_Expr: walk(v, n.left) walk(v, n.right) - case Paren_Expr: + case ^Paren_Expr: walk(v, n.expr) - case Selector_Expr: + case ^Selector_Expr: walk(v, n.expr) walk(v, n.field) - case Implicit_Selector_Expr: + case ^Implicit_Selector_Expr: walk(v, n.field) - case Selector_Call_Expr: + case ^Selector_Call_Expr: walk(v, n.expr) walk(v, n.call) - case Index_Expr: + case ^Index_Expr: walk(v, n.expr) walk(v, n.index) - case Matrix_Index_Expr: + case ^Matrix_Index_Expr: walk(v, n.expr) walk(v, n.row_index) walk(v, n.column_index) - case Deref_Expr: + case ^Deref_Expr: walk(v, n.expr) - case Slice_Expr: + case ^Slice_Expr: walk(v, n.expr) if n.low != nil { walk(v, n.low) @@ -124,57 +124,57 @@ walk :: proc(v: ^Visitor, node: ^Node) { if n.high != nil { walk(v, n.high) } - case Call_Expr: + case ^Call_Expr: walk(v, n.expr) walk_expr_list(v, n.args) - case Field_Value: + case ^Field_Value: walk(v, n.field) walk(v, n.value) - case Ternary_If_Expr: + case ^Ternary_If_Expr: walk(v, n.x) walk(v, n.cond) walk(v, n.y) - case Ternary_When_Expr: + case ^Ternary_When_Expr: walk(v, n.x) walk(v, n.cond) walk(v, n.y) - case Or_Else_Expr: + case ^Or_Else_Expr: walk(v, n.x) walk(v, n.y) - case Or_Return_Expr: + case ^Or_Return_Expr: walk(v, n.expr) - case Type_Assertion: + case ^Type_Assertion: walk(v, n.expr) if n.type != nil { walk(v, n.type) } - case Type_Cast: + case ^Type_Cast: walk(v, n.type) walk(v, n.expr) - case Auto_Cast: + case ^Auto_Cast: walk(v, n.expr) - case Inline_Asm_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: + case ^Bad_Stmt: + case ^Empty_Stmt: + case ^Expr_Stmt: walk(v, n.expr) - case Tag_Stmt: + case ^Tag_Stmt: walk(v, n.stmt) - case Assign_Stmt: + case ^Assign_Stmt: walk_expr_list(v, n.lhs) walk_expr_list(v, n.rhs) - case Block_Stmt: + case ^Block_Stmt: if n.label != nil { walk(v, n.label) } walk_stmt_list(v, n.stmts) - case If_Stmt: + case ^If_Stmt: if n.label != nil { walk(v, n.label) } @@ -186,17 +186,17 @@ walk :: proc(v: ^Visitor, node: ^Node) { if n.else_stmt != nil { walk(v, n.else_stmt) } - case When_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: + case ^Return_Stmt: walk_expr_list(v, n.results) - case Defer_Stmt: + case ^Defer_Stmt: walk(v, n.stmt) - case For_Stmt: + case ^For_Stmt: if n.label != nil { walk(v, n.label) } @@ -210,7 +210,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.post) } walk(v, n.body) - case Range_Stmt: + case ^Range_Stmt: if n.label != nil { walk(v, n.label) } @@ -221,7 +221,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { } walk(v, n.expr) walk(v, n.body) - case Inline_Range_Stmt: + case ^Inline_Range_Stmt: if n.label != nil { walk(v, n.label) } @@ -233,10 +233,10 @@ walk :: proc(v: ^Visitor, node: ^Node) { } walk(v, n.expr) walk(v, n.body) - case Case_Clause: + case ^Case_Clause: walk_expr_list(v, n.list) walk_stmt_list(v, n.body) - case Switch_Stmt: + case ^Switch_Stmt: if n.label != nil { walk(v, n.label) } @@ -247,7 +247,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.cond) } walk(v, n.body) - case Type_Switch_Stmt: + case ^Type_Switch_Stmt: if n.label != nil { walk(v, n.label) } @@ -258,16 +258,16 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.expr) } walk(v, n.body) - case Branch_Stmt: + case ^Branch_Stmt: if n.label != nil { walk(v, n.label) } - case Using_Stmt: + case ^Using_Stmt: walk_expr_list(v, n.list) - case Bad_Decl: - case Value_Decl: + case ^Bad_Decl: + case ^Value_Decl: if n.docs != nil { walk(v, n.docs) } @@ -280,21 +280,21 @@ walk :: proc(v: ^Visitor, node: ^Node) { if n.comment != nil { walk(v, n.comment) } - case Package_Decl: + case ^Package_Decl: if n.docs != nil { walk(v, n.docs) } if n.comment != nil { walk(v, n.comment) } - case Import_Decl: + case ^Import_Decl: if n.docs != nil { walk(v, n.docs) } if n.comment != nil { walk(v, n.comment) } - case Foreign_Block_Decl: + case ^Foreign_Block_Decl: if n.docs != nil { walk(v, n.docs) } @@ -303,7 +303,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.foreign_library) } walk(v, n.body) - case Foreign_Import_Decl: + case ^Foreign_Import_Decl: if n.docs != nil { walk(v, n.docs) } @@ -313,11 +313,11 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.comment) } - case Proc_Group: + case ^Proc_Group: walk_expr_list(v, n.args) - case Attribute: + case ^Attribute: walk_expr_list(v, n.elems) - case Field: + case ^Field: if n.docs != nil { walk(v, n.docs) } @@ -331,31 +331,31 @@ walk :: proc(v: ^Visitor, node: ^Node) { if n.comment != nil { walk(v, n.comment) } - case Field_List: + case ^Field_List: for x in n.list { walk(v, x) } - case Typeid_Type: + case ^Typeid_Type: if n.specialization != nil { walk(v, n.specialization) } - case Helper_Type: + case ^Helper_Type: walk(v, n.type) - case Distinct_Type: + case ^Distinct_Type: walk(v, n.type) - case Poly_Type: + case ^Poly_Type: walk(v, n.type) if n.specialization != nil { walk(v, n.specialization) } - case Proc_Type: + case ^Proc_Type: walk(v, n.params) walk(v, n.results) - case Pointer_Type: + case ^Pointer_Type: walk(v, n.elem) - case Multi_Pointer_Type: + case ^Multi_Pointer_Type: walk(v, n.elem) - case Array_Type: + case ^Array_Type: if n.tag != nil { walk(v, n.tag) } @@ -363,12 +363,12 @@ walk :: proc(v: ^Visitor, node: ^Node) { walk(v, n.len) } walk(v, n.elem) - case Dynamic_Array_Type: + case ^Dynamic_Array_Type: if n.tag != nil { walk(v, n.tag) } walk(v, n.elem) - case Struct_Type: + case ^Struct_Type: if n.poly_params != nil { walk(v, n.poly_params) } @@ -377,7 +377,7 @@ walk :: proc(v: ^Visitor, node: ^Node) { } walk_expr_list(v, n.where_clauses) walk(v, n.fields) - case Union_Type: + case ^Union_Type: if n.poly_params != nil { walk(v, n.poly_params) } @@ -386,23 +386,23 @@ walk :: proc(v: ^Visitor, node: ^Node) { } walk_expr_list(v, n.where_clauses) walk_expr_list(v, n.variants) - case Enum_Type: + case ^Enum_Type: if n.base_type != nil { walk(v, n.base_type) } walk_expr_list(v, n.fields) - case Bit_Set_Type: + case ^Bit_Set_Type: walk(v, n.elem) if n.underlying != nil { walk(v, n.underlying) } - case Map_Type: + case ^Map_Type: walk(v, n.key) walk(v, n.value) - case Relative_Type: + case ^Relative_Type: walk(v, n.tag) walk(v, n.type) - case Matrix_Type: + case ^Matrix_Type: walk(v, n.row_count) walk(v, n.column_count) walk(v, n.elem) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index cc802e7d2..7cce986ae 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -195,10 +195,10 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool { for p.curr_tok.kind != .EOF { stmt := parse_stmt(p) if stmt != nil { - if _, ok := stmt.derived.(ast.Empty_Stmt); !ok { + if _, ok := stmt.derived.(^ast.Empty_Stmt); !ok { append(&p.file.decls, stmt) - if es, es_ok := stmt.derived.(ast.Expr_Stmt); es_ok && es.expr != nil { - if _, pl_ok := es.expr.derived.(ast.Proc_Lit); pl_ok { + if es, es_ok := stmt.derived.(^ast.Expr_Stmt); es_ok && es.expr != nil { + if _, pl_ok := es.expr.derived.(^ast.Proc_Lit); pl_ok { error(p, stmt.pos, "procedure literal evaluated but not used") } } @@ -447,7 +447,7 @@ is_blank_ident_token :: proc(tok: tokenizer.Token) -> bool { return false } is_blank_ident_node :: proc(node: ^ast.Node) -> bool { - if ident, ok := node.derived.(ast.Ident); ok { + if ident, ok := node.derived.(^ast.Ident); ok { return is_blank_ident(ident.name) } return true @@ -490,34 +490,34 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool { return true } - switch n in node.derived { - case ast.Empty_Stmt, ast.Block_Stmt: + #partial switch n in node.derived { + case ^ast.Empty_Stmt, ^ast.Block_Stmt: return true - case ast.If_Stmt, ast.When_Stmt, - ast.For_Stmt, ast.Range_Stmt, ast.Inline_Range_Stmt, - ast.Switch_Stmt, ast.Type_Switch_Stmt: + case ^ast.If_Stmt, ^ast.When_Stmt, + ^ast.For_Stmt, ^ast.Range_Stmt, ^ast.Inline_Range_Stmt, + ^ast.Switch_Stmt, ^ast.Type_Switch_Stmt: return true - case ast.Helper_Type: + case ^ast.Helper_Type: return is_semicolon_optional_for_node(p, n.type) - case ast.Distinct_Type: + case ^ast.Distinct_Type: return is_semicolon_optional_for_node(p, n.type) - case ast.Pointer_Type: + case ^ast.Pointer_Type: return is_semicolon_optional_for_node(p, n.elem) - case ast.Struct_Type, ast.Union_Type, ast.Enum_Type: + case ^ast.Struct_Type, ^ast.Union_Type, ^ast.Enum_Type: // Require semicolon within a procedure body return p.curr_proc == nil - case ast.Proc_Lit: + case ^ast.Proc_Lit: return true - case ast.Package_Decl, ast.Import_Decl, ast.Foreign_Import_Decl: + case ^ast.Package_Decl, ^ast.Import_Decl, ^ast.Foreign_Import_Decl: return true - case ast.Foreign_Block_Decl: + case ^ast.Foreign_Block_Decl: return is_semicolon_optional_for_node(p, n.body) - case ast.Value_Decl: + case ^ast.Value_Decl: if n.is_mutable { return false } @@ -629,10 +629,10 @@ parse_stmt_list :: proc(p: ^Parser) -> []^ast.Stmt { p.curr_tok.kind != .EOF { stmt := parse_stmt(p) if stmt != nil { - if _, ok := stmt.derived.(ast.Empty_Stmt); !ok { + if _, ok := stmt.derived.(^ast.Empty_Stmt); !ok { append(&list, stmt) - if es, es_ok := stmt.derived.(ast.Expr_Stmt); es_ok && es.expr != nil { - if _, pl_ok := es.expr.derived.(ast.Proc_Lit); pl_ok { + if es, es_ok := stmt.derived.(^ast.Expr_Stmt); es_ok && es.expr != nil { + if _, pl_ok := es.expr.derived.(^ast.Proc_Lit); pl_ok { error(p, stmt.pos, "procedure literal evaluated but not used") } } @@ -710,7 +710,7 @@ convert_stmt_to_expr :: proc(p: ^Parser, stmt: ^ast.Stmt, kind: string) -> ^ast. if stmt == nil { return nil } - if es, ok := stmt.derived.(ast.Expr_Stmt); ok { + if es, ok := stmt.derived.(^ast.Expr_Stmt); ok { return es.expr } error(p, stmt.pos, "expected %s, found a simple statement", kind) @@ -852,7 +852,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { if p.curr_tok.kind != .Semicolon { cond = parse_simple_stmt(p, {Stmt_Allow_Flag.In}) - if as, ok := cond.derived.(ast.Assign_Stmt); ok && as.op.kind == .In { + if as, ok := cond.derived.(^ast.Assign_Stmt); ok && as.op.kind == .In { is_range = true } } @@ -894,7 +894,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { if is_range { - assign_stmt := cond.derived.(ast.Assign_Stmt) + assign_stmt := cond.derived.(^ast.Assign_Stmt) vals := assign_stmt.lhs[:] rhs: ^ast.Expr @@ -975,7 +975,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt { tag = as } else { tag = parse_simple_stmt(p, {Stmt_Allow_Flag.In}) - if as, ok := tag.derived.(ast.Assign_Stmt); ok && as.op.kind == .In { + if as, ok := tag.derived.(^ast.Assign_Stmt); ok && as.op.kind == .In { is_type_switch = true } else if parse_control_statement_semicolon_separator(p) { init = tag @@ -1062,14 +1062,14 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind: skip_possible_newline(p) decl := parse_stmt(p) - switch d in &decl.derived { - case ast.Value_Decl: + #partial switch d in decl.derived_stmt { + case ^ast.Value_Decl: if d.docs == nil { d.docs = docs } append(&d.attributes, attribute) - case ast.Foreign_Block_Decl: + case ^ast.Foreign_Block_Decl: if d.docs == nil { d.docs = docs } append(&d.attributes, attribute) - case ast.Foreign_Import_Decl: + case ^ast.Foreign_Import_Decl: if d.docs == nil { d.docs = docs } append(&d.attributes, attribute) case: @@ -1083,11 +1083,11 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind: parse_foreign_block_decl :: proc(p: ^Parser) -> ^ast.Stmt { decl := parse_stmt(p) - switch in decl.derived { - case ast.Empty_Stmt, ast.Bad_Stmt, ast.Bad_Decl: + #partial switch in decl.derived_stmt { + case ^ast.Empty_Stmt, ^ast.Bad_Stmt, ^ast.Bad_Decl: // Ignore return nil - case ast.When_Stmt, ast.Value_Decl: + case ^ast.When_Stmt, ^ast.Value_Decl: return decl } @@ -1291,13 +1291,13 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { case .Defer: tok := advance_token(p) stmt := parse_stmt(p) - switch s in stmt.derived { - case ast.Empty_Stmt: + #partial switch s in stmt.derived_stmt { + case ^ast.Empty_Stmt: error(p, s.pos, "empty statement after defer (e.g. ';')") - case ast.Defer_Stmt: + case ^ast.Defer_Stmt: error(p, s.pos, "you cannot defer a defer statement") stmt = s.stmt - case ast.Return_Stmt: + case ^ast.Return_Stmt: error(p, s.pos, "you cannot defer a return statement") } ds := ast.new(ast.Defer_Stmt, tok.pos, stmt.end) @@ -1369,8 +1369,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { expect_token_after(p, .Colon, "identifier list") decl := parse_value_decl(p, list, docs) if decl != nil { - switch d in &decl.derived { - case ast.Value_Decl: + #partial switch d in decl.derived_stmt { + case ^ast.Value_Decl: d.is_using = true return decl } @@ -1401,9 +1401,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { return stmt case "partial": stmt := parse_stmt(p) - switch s in &stmt.derived { - case ast.Switch_Stmt: s.partial = true - case ast.Type_Switch_Stmt: s.partial = true + #partial switch s in stmt.derived_stmt { + case ^ast.Switch_Stmt: s.partial = true + case ^ast.Type_Switch_Stmt: s.partial = true case: error(p, stmt.pos, "#partial can only be applied to a switch statement") } return stmt @@ -1548,11 +1548,11 @@ parse_body :: proc(p: ^Parser) -> ^ast.Block_Stmt { } convert_stmt_to_body :: proc(p: ^Parser, stmt: ^ast.Stmt) -> ^ast.Stmt { - switch s in stmt.derived { - case ast.Block_Stmt: + #partial switch s in stmt.derived_stmt { + case ^ast.Block_Stmt: error(p, stmt.pos, "expected a normal statement rather than a block statement") return stmt - case ast.Empty_Stmt: + case ^ast.Empty_Stmt: error(p, stmt.pos, "expected a non-empty statement") } @@ -1629,10 +1629,10 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags, id: ^ast.Expr = ident.expr - switch n in ident.expr.derived { - case ast.Ident: - case ast.Bad_Expr: - case ast.Poly_Type: + #partial switch n in ident.expr.derived_expr { + case ^ast.Ident: + case ^ast.Bad_Expr: + case ^ast.Poly_Type: if allow_poly_names { if n.specialization == nil { break @@ -1794,21 +1794,21 @@ check_procedure_name_list :: proc(p: ^Parser, names: []^ast.Expr) -> bool { return false } - _, first_is_polymorphic := names[0].derived.(ast.Poly_Type) + _, first_is_polymorphic := names[0].derived.(^ast.Poly_Type) any_polymorphic_names := first_is_polymorphic for i := 1; i < len(names); i += 1 { name := names[i] if first_is_polymorphic { - if _, ok := name.derived.(ast.Poly_Type); ok { + if _, ok := name.derived.(^ast.Poly_Type); ok { any_polymorphic_names = true } else { error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers") return any_polymorphic_names } } else { - if _, ok := name.derived.(ast.Poly_Type); ok { + if _, ok := name.derived.(^ast.Poly_Type); ok { any_polymorphic_names = true error(p, name.pos, "mixture of polymorphic and non-polymorphic identifiers") return any_polymorphic_names @@ -1873,7 +1873,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags if type == nil { return false } - _, ok := type.derived.(ast.Ellipsis) + _, ok := type.derived.(^ast.Ellipsis) return ok } @@ -1891,7 +1891,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags type = parse_var_type(p, allowed_flags) tt := ast.unparen_expr(type) if is_signature && !any_polymorphic_names { - if ti, ok := tt.derived.(ast.Typeid_Type); ok && ti.specialization != nil { + if ti, ok := tt.derived.(^ast.Typeid_Type); ok && ti.specialization != nil { error(p, tt.pos, "specialization of typeid is not allowed without polymorphic names") } } @@ -1967,7 +1967,7 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags p.curr_tok.kind != .EOF { prefix_flags := parse_field_prefixes(p) param := parse_var_type(p, allowed_flags & {.Typeid_Token, .Ellipsis}) - if _, ok := param.derived.(ast.Ellipsis); ok { + if _, ok := param.derived.(^ast.Ellipsis); ok { if seen_ellipsis { error(p, param.pos, "extra variadic parameter after ellipsis") } @@ -1994,8 +1994,8 @@ parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags names := make([]^ast.Expr, 1) names[0] = ast.new(ast.Ident, tok.pos, end_pos(tok)) - switch ident in &names[0].derived { - case ast.Ident: + #partial switch ident in names[0].derived_expr { + case ^ast.Ident: ident.name = tok.text case: unreachable() @@ -2125,12 +2125,12 @@ parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type { loop: for param in params.list { if param.type != nil { - if _, ok := param.type.derived.(ast.Poly_Type); ok { + if _, ok := param.type.derived.(^ast.Poly_Type); ok { is_generic = true break loop } for name in param.names { - if _, ok := name.derived.(ast.Poly_Type); ok { + if _, ok := name.derived.(^ast.Poly_Type); ok { is_generic = true break loop } @@ -2167,13 +2167,13 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^ } } - switch e in &ast.unparen_expr(expr).derived { - case ast.Proc_Lit: + #partial switch e in ast.unparen_expr(expr).derived_expr { + case ^ast.Proc_Lit: if e.inlining != .None && e.inlining != pi { error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure literal") } e.inlining = pi - case ast.Call_Expr: + case ^ast.Call_Expr: if e.inlining != .None && e.inlining != pi { error(p, expr.pos, "both 'inline' and 'no_inline' cannot be applied to a procedure call") } @@ -2264,9 +2264,9 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { bd.name = name.text original_type := parse_type(p) type := ast.unparen_expr(original_type) - switch t in &type.derived { - case ast.Array_Type: t.tag = bd - case ast.Dynamic_Array_Type: t.tag = bd + #partial switch t in type.derived_expr { + case ^ast.Array_Type: t.tag = bd + case ^ast.Dynamic_Array_Type: t.tag = bd case: error(p, original_type.pos, "expected an array type after #%s", name.text) } @@ -2278,10 +2278,10 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { tag.name = name.text original_expr := parse_expr(p, lhs) expr := ast.unparen_expr(original_expr) - switch t in &expr.derived { - case ast.Comp_Lit: + #partial switch t in expr.derived_expr { + case ^ast.Comp_Lit: t.tag = tag - case ast.Array_Type: + case ^ast.Array_Type: t.tag = tag error(p, tok.pos, "#%s has been replaced with #sparse for non-contiguous enumerated array types", name.text) case: @@ -2296,8 +2296,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { tag.name = name.text original_type := parse_type(p) type := ast.unparen_expr(original_type) - switch t in &type.derived { - case ast.Array_Type: + #partial switch t in type.derived_expr { + case ^ast.Array_Type: t.tag = tag case: error(p, tok.pos, "expected an enumerated array type after #%s", name.text) @@ -2677,7 +2677,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { variants: [dynamic]^ast.Expr for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { type := parse_type(p) - if _, ok := type.derived.(ast.Bad_Expr); !ok { + if _, ok := type.derived.(^ast.Bad_Expr); !ok { append(&variants, type) } if !allow_token(p, .Comma) { @@ -2852,19 +2852,19 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool { if val == nil { return false } - switch _ in val.derived { - case ast.Bad_Expr, - ast.Ident, - ast.Selector_Expr, - ast.Array_Type, - ast.Struct_Type, - ast.Union_Type, - ast.Enum_Type, - ast.Dynamic_Array_Type, - ast.Map_Type, - ast.Bit_Set_Type, - ast.Matrix_Type, - ast.Call_Expr: + #partial switch _ in val.derived_expr { + case ^ast.Bad_Expr, + ^ast.Ident, + ^ast.Selector_Expr, + ^ast.Array_Type, + ^ast.Struct_Type, + ^ast.Union_Type, + ^ast.Enum_Type, + ^ast.Dynamic_Array_Type, + ^ast.Map_Type, + ^ast.Bit_Set_Type, + ^ast.Matrix_Type, + ^ast.Call_Expr: return true } return false @@ -2986,7 +2986,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr { ce.close = close.pos o := ast.unparen_expr(operand) - if se, ok := o.derived.(ast.Selector_Expr); ok && se.op.kind == .Arrow_Right { + if se, ok := o.derived.(^ast.Selector_Expr); ok && se.op.kind == .Arrow_Right { sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce.end) sce.expr = o sce.call = ce @@ -3416,13 +3416,13 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { stmt := parse_stmt(p) if stmt != nil { - switch n in &stmt.derived { - case ast.Block_Stmt: n.label = label - case ast.If_Stmt: n.label = label - case ast.For_Stmt: n.label = label - case ast.Switch_Stmt: n.label = label - case ast.Type_Switch_Stmt: n.label = label - case ast.Range_Stmt: n.label = label + #partial switch n in stmt.derived_stmt { + case ^ast.Block_Stmt: n.label = label + case ^ast.If_Stmt: n.label = label + case ^ast.For_Stmt: n.label = label + case ^ast.Switch_Stmt: n.label = label + case ^ast.Type_Switch_Stmt: n.label = label + case ^ast.Range_Stmt: n.label = label } } diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 023583bde..9eba29987 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -342,16 +342,16 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { return } - switch v in &decl.derived { - case Expr_Stmt: + #partial switch v in decl.derived_stmt { + case ^Expr_Stmt: move_line(p, decl.pos) visit_expr(p, v.expr) if p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case When_Stmt: + case ^When_Stmt: visit_stmt(p, cast(^Stmt)decl) - case Foreign_Import_Decl: + case ^Foreign_Import_Decl: if len(v.attributes) > 0 { sort.sort(sort_attribute(&v.attributes)) move_line(p, v.attributes[0].pos) @@ -370,7 +370,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { for path in v.fullpaths { push_ident_token(p, path, 0) } - case Foreign_Block_Decl: + case ^Foreign_Block_Decl: if len(v.attributes) > 0 { sort.sort(sort_attribute(&v.attributes)) move_line(p, v.attributes[0].pos) @@ -383,7 +383,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { visit_expr(p, v.foreign_library) visit_stmt(p, v.body) - case Import_Decl: + case ^Import_Decl: move_line(p, decl.pos) if v.name.text != "" { @@ -395,7 +395,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { push_ident_token(p, v.fullpath, 1) } - case Value_Decl: + case ^Value_Decl: if len(v.attributes) > 0 { sort.sort(sort_attribute(&v.attributes)) move_line(p, v.attributes[0].pos) @@ -446,10 +446,10 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { add_semicolon := true for value in v.values { - switch a in value.derived { - case Union_Type, Enum_Type, Struct_Type: + #partial switch a in value.derived { + case ^Union_Type, ^Enum_Type, ^Struct_Type: add_semicolon = false || called_in_stmt - case Proc_Lit: + case ^Proc_Lit: add_semicolon = false } } @@ -516,23 +516,34 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener return } - switch v in stmt.derived { - case Import_Decl: - visit_decl(p, cast(^Decl)stmt, true) - return - case Value_Decl: - visit_decl(p, cast(^Decl)stmt, true) - return - case Foreign_Import_Decl: - visit_decl(p, cast(^Decl)stmt, true) - return - case Foreign_Block_Decl: - visit_decl(p, cast(^Decl)stmt, true) - return - } - switch v in stmt.derived { - case Using_Stmt: + switch v in stmt.derived_stmt { + case ^Bad_Stmt: + case ^Bad_Decl: + case ^Package_Decl: + + case ^Empty_Stmt: + push_generic_token(p, .Semicolon, 0) + case ^Tag_Stmt: + push_generic_token(p, .Hash, 1) + push_generic_token(p, v.op.kind, 1, v.op.text) + visit_stmt(p, v.stmt) + + + case ^Import_Decl: + visit_decl(p, cast(^Decl)stmt, true) + return + case ^Value_Decl: + visit_decl(p, cast(^Decl)stmt, true) + return + case ^Foreign_Import_Decl: + visit_decl(p, cast(^Decl)stmt, true) + return + case ^Foreign_Block_Decl: + visit_decl(p, cast(^Decl)stmt, true) + return + + case ^Using_Stmt: move_line(p, v.pos) push_generic_token(p, .Using, 1) @@ -542,7 +553,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case Block_Stmt: + case ^Block_Stmt: move_line(p, v.pos) if v.pos.line == v.end.line { @@ -572,7 +583,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_end_brace(p, v.end) } } - case If_Stmt: + case ^If_Stmt: move_line(p, v.pos) if v.label != nil { @@ -595,7 +606,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener uses_do := false - if check_stmt, ok := v.body.derived.(Block_Stmt); ok && check_stmt.uses_do { + if check_stmt, ok := v.body.derived.(^Block_Stmt); ok && check_stmt.uses_do { uses_do = true } @@ -626,7 +637,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_stmt(p, v.else_stmt) } - case Switch_Stmt: + case ^Switch_Stmt: move_line(p, v.pos) if v.label != nil { @@ -654,7 +665,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_expr(p, v.cond) visit_stmt(p, v.body) - case Case_Clause: + case ^Case_Clause: move_line(p, v.pos) if !p.config.indent_cases { @@ -678,7 +689,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if !p.config.indent_cases { indent(p) } - case Type_Switch_Stmt: + case ^Type_Switch_Stmt: move_line(p, v.pos) hint_current_line(p, {.Switch_Stmt}) @@ -696,7 +707,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_stmt(p, v.tag) visit_stmt(p, v.body) - case Assign_Stmt: + case ^Assign_Stmt: move_line(p, v.pos) hint_current_line(p, {.Assign}) @@ -710,13 +721,13 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if block_stmt && p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case Expr_Stmt: + case ^Expr_Stmt: move_line(p, v.pos) visit_expr(p, v.expr) if block_stmt && p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case For_Stmt: + case ^For_Stmt: // this should be simplified move_line(p, v.pos) @@ -753,7 +764,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_stmt(p, v.body) - case Inline_Range_Stmt: + case ^Inline_Range_Stmt: move_line(p, v.pos) if v.label != nil { @@ -779,7 +790,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_expr(p, v.expr) visit_stmt(p, v.body) - case Range_Stmt: + case ^Range_Stmt: move_line(p, v.pos) if v.label != nil { @@ -805,7 +816,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_expr(p, v.expr) visit_stmt(p, v.body) - case Return_Stmt: + case ^Return_Stmt: move_line(p, v.pos) push_generic_token(p, .Return, 1) @@ -817,7 +828,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if block_stmt && p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case Defer_Stmt: + case ^Defer_Stmt: move_line(p, v.pos) push_generic_token(p, .Defer, 0) @@ -826,7 +837,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if p.config.semicolons { push_generic_token(p, .Semicolon, 0) } - case When_Stmt: + case ^When_Stmt: move_line(p, v.pos) push_generic_token(p, .When, 1) visit_expr(p, v.cond) @@ -846,7 +857,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_stmt(p, v.else_stmt) } - case Branch_Stmt: + case ^Branch_Stmt: move_line(p, v.pos) push_generic_token(p, v.tok.kind, 0) @@ -918,8 +929,15 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { set_source_position(p, expr.pos) - switch v in expr.derived { - case Inline_Asm_Expr: + switch v in expr.derived_expr { + case ^Bad_Expr: + + case ^Tag_Expr: + push_generic_token(p, .Hash, 1) + push_generic_token(p, v.op.kind, 1, v.op.text) + visit_expr(p, v.expr) + + case ^Inline_Asm_Expr: push_generic_token(p, v.tok.kind, 1, v.tok.text) push_generic_token(p, .Open_Paren, 1) @@ -936,42 +954,42 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { push_generic_token(p, .Comma, 0) visit_expr(p, v.constraints_string) push_generic_token(p, .Close_Brace, 0) - case Undef: + case ^Undef: push_generic_token(p, .Undef, 1) - case Auto_Cast: + case ^Auto_Cast: push_generic_token(p, v.op.kind, 1) visit_expr(p, v.expr) - case Ternary_If_Expr: + case ^Ternary_If_Expr: visit_expr(p, v.x) push_generic_token(p, v.op1.kind, 1) visit_expr(p, v.cond) push_generic_token(p, v.op2.kind, 1) visit_expr(p, v.y) - case Ternary_When_Expr: + case ^Ternary_When_Expr: visit_expr(p, v.x) push_generic_token(p, v.op1.kind, 1) visit_expr(p, v.cond) push_generic_token(p, v.op2.kind, 1) visit_expr(p, v.y) - case Or_Else_Expr: + case ^Or_Else_Expr: visit_expr(p, v.x) push_generic_token(p, v.token.kind, 1) visit_expr(p, v.y) - case Or_Return_Expr: + case ^Or_Return_Expr: visit_expr(p, v.expr) push_generic_token(p, v.token.kind, 1) - case Selector_Call_Expr: + case ^Selector_Call_Expr: visit_expr(p, v.call.expr) push_generic_token(p, .Open_Paren, 1) visit_exprs(p, v.call.args, {.Add_Comma}) push_generic_token(p, .Close_Paren, 0) - case Ellipsis: + case ^Ellipsis: push_generic_token(p, .Ellipsis, 1) visit_expr(p, v.expr) - case Relative_Type: + case ^Relative_Type: visit_expr(p, v.tag) visit_expr(p, v.type) - case Slice_Expr: + case ^Slice_Expr: visit_expr(p, v.expr) push_generic_token(p, .Open_Bracket, 0) visit_expr(p, v.low) @@ -981,37 +999,37 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { visit_expr(p, v.high) } push_generic_token(p, .Close_Bracket, 0) - case Ident: + case ^Ident: if .Enforce_Poly_Names in options { push_generic_token(p, .Dollar, 1) push_ident_token(p, v.name, 0) } else { push_ident_token(p, v.name, 1) } - case Deref_Expr: + case ^Deref_Expr: visit_expr(p, v.expr) push_generic_token(p, v.op.kind, 0) - case Type_Cast: + case ^Type_Cast: push_generic_token(p, v.tok.kind, 1) push_generic_token(p, .Open_Paren, 0) visit_expr(p, v.type) push_generic_token(p, .Close_Paren, 0) merge_next_token(p) visit_expr(p, v.expr) - case Basic_Directive: + case ^Basic_Directive: push_generic_token(p, v.tok.kind, 1) push_ident_token(p, v.name, 0) - case Distinct_Type: + case ^Distinct_Type: push_generic_token(p, .Distinct, 1) visit_expr(p, v.type) - case Dynamic_Array_Type: + case ^Dynamic_Array_Type: visit_expr(p, v.tag) push_generic_token(p, .Open_Bracket, 1) push_generic_token(p, .Dynamic, 0) push_generic_token(p, .Close_Bracket, 0) merge_next_token(p) visit_expr(p, v.elem) - case Bit_Set_Type: + case ^Bit_Set_Type: push_generic_token(p, .Bit_Set, 1) push_generic_token(p, .Open_Bracket, 0) @@ -1023,7 +1041,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { } push_generic_token(p, .Close_Bracket, 0) - case Union_Type: + case ^Union_Type: push_generic_token(p, .Union, 1) push_poly_params(p, v.poly_params) @@ -1045,7 +1063,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { visit_exprs(p, v.variants, {.Add_Comma, .Trailing}) visit_end_brace(p, v.end) } - case Enum_Type: + case ^Enum_Type: push_generic_token(p, .Enum, 1) hint_current_line(p, {.Enum}) @@ -1068,7 +1086,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { } set_source_position(p, v.end) - case Struct_Type: + case ^Struct_Type: push_generic_token(p, .Struct, 1) hint_current_line(p, {.Struct}) @@ -1103,7 +1121,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { } set_source_position(p, v.end) - case Proc_Lit: + case ^Proc_Lit: switch v.inlining { case .None: case .Inline: @@ -1112,7 +1130,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { push_ident_token(p, "#force_no_inline", 0) } - visit_proc_type(p, v.type^, true) + visit_proc_type(p, v.type, true) push_where_clauses(p, v.where_clauses) @@ -1122,16 +1140,16 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { } else { push_generic_token(p, .Undef, 1) } - case Proc_Type: + case ^Proc_Type: visit_proc_type(p, v) - case Basic_Lit: + case ^Basic_Lit: push_generic_token(p, v.tok.kind, 1, v.tok.text) - case Binary_Expr: + case ^Binary_Expr: visit_binary_expr(p, v) - case Implicit_Selector_Expr: + case ^Implicit_Selector_Expr: push_generic_token(p, .Period, 1) push_ident_token(p, v.field.name, 0) - case Call_Expr: + case ^Call_Expr: visit_expr(p, v.expr) push_format_token(p, @@ -1146,27 +1164,34 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis) push_generic_token(p, .Close_Paren, 0) - case Typeid_Type: + case ^Typeid_Type: push_generic_token(p, .Typeid, 1) if v.specialization != nil { push_generic_token(p, .Quo, 0) visit_expr(p, v.specialization) } - case Selector_Expr: + case ^Selector_Expr: visit_expr(p, v.expr) push_generic_token(p, v.op.kind, 0) visit_expr(p, v.field) - case Paren_Expr: + case ^Paren_Expr: push_generic_token(p, .Open_Paren, 1) visit_expr(p, v.expr) push_generic_token(p, .Close_Paren, 0) - case Index_Expr: + case ^Index_Expr: visit_expr(p, v.expr) push_generic_token(p, .Open_Bracket, 0) visit_expr(p, v.index) push_generic_token(p, .Close_Bracket, 0) - case Proc_Group: + case ^Matrix_Index_Expr: + visit_expr(p, v.expr) + push_generic_token(p, .Open_Bracket, 0) + visit_expr(p, v.row_index) + push_generic_token(p, .Comma, 0) + visit_expr(p, v.column_index) + push_generic_token(p, .Close_Bracket, 0) + case ^Proc_Group: push_generic_token(p, v.tok.kind, 1) if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line { @@ -1181,7 +1206,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { push_generic_token(p, .Close_Brace, 0) } - case Comp_Lit: + case ^Comp_Lit: if v.type != nil { visit_expr(p, v.type) } @@ -1198,18 +1223,18 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { push_generic_token(p, .Close_Brace, 0) } - case Unary_Expr: + case ^Unary_Expr: push_generic_token(p, v.op.kind, 1) merge_next_token(p) visit_expr(p, v.expr) - case Field_Value: + case ^Field_Value: visit_expr(p, v.field) push_generic_token(p, .Eq, 1) visit_expr(p, v.value) - case Type_Assertion: + case ^Type_Assertion: visit_expr(p, v.expr) - if unary, ok := v.type.derived.(Unary_Expr); ok && unary.op.text == "?" { + if unary, ok := v.type.derived.(^Unary_Expr); ok && unary.op.text == "?" { push_generic_token(p, .Period, 0) visit_expr(p, v.type) } else { @@ -1219,13 +1244,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { push_generic_token(p, .Close_Paren, 0) } - case Pointer_Type: + case ^Pointer_Type: push_generic_token(p, .Pointer, 1) merge_next_token(p) visit_expr(p, v.elem) - case Implicit: + case ^Implicit: push_generic_token(p, v.tok.kind, 1) - case Poly_Type: + case ^Poly_Type: push_generic_token(p, .Dollar, 1) merge_next_token(p) visit_expr(p, v.type) @@ -1235,22 +1260,35 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, options := List_Options{}) { merge_next_token(p) visit_expr(p, v.specialization) } - case Array_Type: + case ^Array_Type: visit_expr(p, v.tag) push_generic_token(p, .Open_Bracket, 1) visit_expr(p, v.len) push_generic_token(p, .Close_Bracket, 0) merge_next_token(p) visit_expr(p, v.elem) - case Map_Type: + case ^Map_Type: push_generic_token(p, .Map, 1) push_generic_token(p, .Open_Bracket, 0) visit_expr(p, v.key) push_generic_token(p, .Close_Bracket, 0) merge_next_token(p) visit_expr(p, v.value) - case Helper_Type: + case ^Helper_Type: visit_expr(p, v.type) + case ^Multi_Pointer_Type: + push_generic_token(p, .Open_Bracket, 1) + push_generic_token(p, .Pointer, 0) + push_generic_token(p, .Close_Bracket, 0) + visit_expr(p, v.elem) + case ^Matrix_Type: + push_generic_token(p, .Matrix, 1) + push_generic_token(p, .Open_Bracket, 0) + visit_expr(p, v.row_count) + push_generic_token(p, .Comma, 0) + visit_expr(p, v.column_count) + push_generic_token(p, .Close_Bracket, 0) + visit_expr(p, v.elem) case: panic(fmt.aprint(expr.derived)) } @@ -1348,7 +1386,7 @@ visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, options := List_Opt } } -visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := false) { +visit_proc_type :: proc(p: ^Printer, proc_type: ^ast.Proc_Type, is_proc_lit := false) { if is_proc_lit { push_format_token(p, Format_Token { kind = .Proc, @@ -1392,7 +1430,7 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := fa } else if len(proc_type.results.list) == 1 { for name in proc_type.results.list[0].names { - if ident, ok := name.derived.(ast.Ident); ok { + if ident, ok := name.derived.(^ast.Ident); ok { if ident.name != "_" { use_parens = true } @@ -1410,19 +1448,19 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := fa } } -visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) { +visit_binary_expr :: proc(p: ^Printer, binary: ^ast.Binary_Expr) { move_line(p, binary.left.pos) - if v, ok := binary.left.derived.(ast.Binary_Expr); ok { + if v, ok := binary.left.derived.(^ast.Binary_Expr); ok { visit_binary_expr(p, v) } else { visit_expr(p, binary.left) } either_implicit_selector := false - if _, ok := binary.left.derived.(ast.Implicit_Selector_Expr); ok { + if _, ok := binary.left.derived.(^ast.Implicit_Selector_Expr); ok { either_implicit_selector = true - } else if _, ok := binary.right.derived.(ast.Implicit_Selector_Expr); ok { + } else if _, ok := binary.right.derived.(^ast.Implicit_Selector_Expr); ok { either_implicit_selector = true } @@ -1439,7 +1477,7 @@ visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) { move_line(p, binary.right.pos) - if v, ok := binary.right.derived.(ast.Binary_Expr); ok { + if v, ok := binary.right.derived.(^ast.Binary_Expr); ok { visit_binary_expr(p, v) } else { visit_expr(p, binary.right) @@ -1499,7 +1537,7 @@ visit_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, remove_blank := named := false for name in field.names { - if ident, ok := name.derived.(ast.Ident); ok { + if ident, ok := name.derived.(^ast.Ident); ok { //for some reason the parser uses _ to mean empty if ident.name != "_" || !remove_blank { named = true From bd1b54e0db0bb599f3118c60aac7fdaaaa0dacd4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Mar 2022 13:58:22 +0000 Subject: [PATCH 2/5] Fix #1503 --- core/odin/ast/clone.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 723f7b90d..1f2eee124 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -98,7 +98,7 @@ clone_node :: proc(node: ^Node) -> ^Node { reflect.set_union_value(res.derived, derived_expr) reflect.set_union_value(res.derived, derived_stmt) - switch r in res.derived { + if res.derived != nil do switch r in res.derived { case ^Package, ^File: case ^Bad_Expr: case ^Ident: @@ -313,7 +313,7 @@ clone_node :: proc(node: ^Node) -> ^Node { r.tag = clone(r.tag) r.type = clone(r.type) case: - fmt.panicf("Unhandled node kind: %T", r) + fmt.panicf("Unhandled node kind: %v", r) } return res From 2944969ca027f87d278233bb327f12b271522f62 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Mar 2022 14:01:37 +0000 Subject: [PATCH 3/5] Correct `clone_node` --- core/odin/ast/clone.odin | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 1f2eee124..b0d997091 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -68,12 +68,13 @@ clone_node :: proc(node: ^Node) -> ^Node { return nil } - size := size_of(Node) + size := size_of(Node) align := align_of(Node) ti := reflect.union_variant_type_info(node.derived) if ti != nil { - size = ti.size - align = ti.align + elem := ti.variant.(reflect.Type_Info_Pointer).elem + size = elem.size + align = elem.align } #partial switch in node.derived { From 913d802e3381f61d3bd6e9e67b91fbe991733c88 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Mar 2022 23:10:38 +0000 Subject: [PATCH 4/5] Fix `ast.clone_node` --- core/odin/ast/clone.odin | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index b0d997091..400c064f5 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -88,16 +88,20 @@ clone_node :: proc(node: ^Node) -> ^Node { src = (^rawptr)(&node.derived)^ } mem.copy(res, src, size) - res_any: any - res_any.data = res - res_any.id = ti.id + res_ptr_any: any + res_ptr_any.data = &res + res_ptr_any.id = ti.id - reflect.set_union_value(res.derived, res_any) + reflect.set_union_value(res.derived, res_ptr_any) - derived_expr := reflect.struct_field_value_by_name(res_any, "derived_expr", true) - derived_stmt := reflect.struct_field_value_by_name(res_any, "derived_stmt", true) - reflect.set_union_value(res.derived, derived_expr) - reflect.set_union_value(res.derived, derived_stmt) + res_ptr := reflect.deref(res_ptr_any) + + if de := reflect.struct_field_value_by_name(res_ptr, "derived_expr", true); de != nil { + reflect.set_union_value(de, res_ptr_any) + } + if ds := reflect.struct_field_value_by_name(res_ptr, "derived_stmt", true); ds != nil { + reflect.set_union_value(ds, res_ptr_any) + } if res.derived != nil do switch r in res.derived { case ^Package, ^File: From 1abd95094d0853fd9bcc5825ef3b63e8d26443bc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Mar 2022 23:25:22 +0000 Subject: [PATCH 5/5] Add `reflect.deref` --- core/reflect/reflect.odin | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 05b3a5da0..d05026532 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -365,6 +365,19 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any { return nil } +deref :: proc(val: any) -> any { + if val != nil { + ti := type_info_base(type_info_of(val.id)) + if info, ok := ti.variant.(Type_Info_Pointer); ok { + return any{ + (^rawptr)(val.data)^, + info.elem.id, + } + } + } + return val +} + // Struct_Tag represents the type of the string of a struct field @@ -680,7 +693,6 @@ union_variant_typeid :: proc(a: any) -> typeid { return nil } panic("expected a union to reflect.union_variant_typeid") - } get_union_variant_raw_tag :: proc(a: any) -> i64 {