From 148d57827c96907d13d50410466c2cbab80429f0 Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 12 Jan 2023 19:21:29 +0800 Subject: [PATCH] parser, fmt: fix fmt in struct declarations with a fields, declared to be arrays of anonymous structs (fix #16947) (#16952) --- vlib/v/fmt/struct.v | 54 ++++++++++++++----- ...th_array_of_anon_struct_field_decl_keep.vv | 13 +++++ vlib/v/parser/parse_type.v | 4 +- vlib/v/parser/parser.v | 1 + vlib/v/parser/struct.v | 8 +-- 5 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 vlib/v/fmt/tests/struct_with_array_of_anon_struct_field_decl_keep.vv diff --git a/vlib/v/fmt/struct.v b/vlib/v/fmt/struct.v index acbd995447..85b5b24164 100644 --- a/vlib/v/fmt/struct.v +++ b/vlib/v/fmt/struct.v @@ -132,18 +132,7 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl, is_anon bool) { } f.write(strings.repeat(` `, field_align.max_len - field.name.len - comments_len)) // Handle anon structs recursively - mut field_is_anon := false - sym := f.table.sym(field.typ) - if sym.kind == .struct_ { - info := sym.info as ast.Struct - field_is_anon = info.is_anon - } - if field_is_anon { - f.indent++ - f.struct_decl(field.anon_struct_decl, true) - f.indent-- - } else { - // If it's not an anon struct, just write the type of the field + if !f.write_anon_struct_field_decl(field.typ, field.anon_struct_decl) { f.write(field_types[i]) } f.mark_types_import_as_used(field.typ) @@ -201,6 +190,47 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl, is_anon bool) { } } +fn (mut f Fmt) write_anon_struct_field_decl(field_typ ast.Type, field_anon_decl ast.StructDecl) bool { + sym := f.table.sym(field_typ) + match sym.kind { + .struct_ { + info := sym.info as ast.Struct + if info.is_anon { + f.indent++ + f.struct_decl(field_anon_decl, true) + f.indent-- + return true + } + } + .array { + if sym.info is ast.Array { + elem_sym := f.table.sym(sym.info.elem_type) + if elem_sym.info is ast.Struct { + if elem_sym.info.is_anon { + f.write('[]'.repeat(sym.info.nr_dims)) + f.write_anon_struct_field_decl(sym.info.elem_type, field_anon_decl) + return true + } + } + } + } + .array_fixed { + if sym.info is ast.ArrayFixed { + elem_sym := f.table.sym(sym.info.elem_type) + if elem_sym.info is ast.Struct { + if elem_sym.info.is_anon { + f.write('[${sym.info.size}]') + f.write_anon_struct_field_decl(sym.info.elem_type, field_anon_decl) + return true + } + } + } + } + else {} + } + return false +} + pub fn (mut f Fmt) struct_init(node ast.StructInit) { struct_init_save := f.is_struct_init f.is_struct_init = true diff --git a/vlib/v/fmt/tests/struct_with_array_of_anon_struct_field_decl_keep.vv b/vlib/v/fmt/tests/struct_with_array_of_anon_struct_field_decl_keep.vv new file mode 100644 index 0000000000..fb95ea405a --- /dev/null +++ b/vlib/v/fmt/tests/struct_with_array_of_anon_struct_field_decl_keep.vv @@ -0,0 +1,13 @@ +struct Abc { + a []struct { + b string + } +} + +fn main() { + abc := Abc{ + a: [struct {'this is b'}] + } + + dump(abc) +} diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index 04a1bccfe8..5213c5519a 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -434,9 +434,9 @@ pub fn (mut p Parser) parse_type() ast.Type { } // Anon structs if p.tok.kind == .key_struct { - struct_decl := p.struct_decl(true) + p.anon_struct_decl = p.struct_decl(true) // Find the registered anon struct type, it was registered above in `p.struct_decl()` - return p.table.find_type_idx(struct_decl.name) + return p.table.find_type_idx(p.anon_struct_decl.name) } language := p.parse_language() diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 71cddc00ae..4785a7bb18 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -89,6 +89,7 @@ mut: defer_vars []ast.Ident should_abort bool // when too many errors/warnings/notices are accumulated, should_abort becomes true, and the parser should stop codegen_text string + anon_struct_decl ast.StructDecl struct_init_generic_types []ast.Type if_cond_comments []ast.Comment script_mode bool diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 4706690471..f8f2c61f42 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -202,7 +202,6 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { mut type_pos := token.Pos{} mut field_pos := token.Pos{} mut option_pos := token.Pos{} - mut anon_struct_decl := ast.StructDecl{} if is_embed { // struct embedding type_pos = p.tok.pos() @@ -247,9 +246,9 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { if p.tok.kind == .key_struct { // Anon structs if p.tok.kind == .key_struct { - anon_struct_decl = p.struct_decl(true) + p.anon_struct_decl = p.struct_decl(true) // Find the registered anon struct type, it was registered above in `p.struct_decl()` - typ = p.table.find_type_idx(anon_struct_decl.name) + typ = p.table.find_type_idx(p.anon_struct_decl.name) } } else { start_type_pos := p.tok.pos() @@ -308,8 +307,9 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { is_global: is_field_global is_volatile: is_field_volatile is_deprecated: is_field_deprecated - anon_struct_decl: anon_struct_decl + anon_struct_decl: p.anon_struct_decl } + p.anon_struct_decl = ast.StructDecl{} } // save embeds as table fields too, it will be used in generation phase fields << ast.StructField{