1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

fmt: handle anon structs; tests: bring back anon struct test

This commit is contained in:
Alexander Medvednikov 2022-07-07 16:09:58 +03:00
parent 972bba66d1
commit f5001192f9
7 changed files with 63 additions and 15 deletions

View File

@ -316,6 +316,7 @@ pub mut:
default_expr_typ Type
name string
typ Type
anon_struct_decl StructDecl // only if the field is an anonymous struct
}
pub fn (f &StructField) equals(o &StructField) bool {

View File

@ -1121,7 +1121,7 @@ pub mut:
parent_type Type
}
// human readable type name
// human readable type name, also used by vfmt
pub fn (t &Table) type_to_str(typ Type) string {
return t.type_to_str_using_aliases(typ, map[string]string{})
}

View File

@ -500,7 +500,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
f.sql_stmt(node)
}
ast.StructDecl {
f.struct_decl(node)
f.struct_decl(node, false)
}
ast.TypeDecl {
f.type_decl(node)

View File

@ -6,7 +6,7 @@ module fmt
import strings
import v.ast
pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
pub fn (mut f Fmt) struct_decl(node ast.StructDecl, is_anon bool) {
f.attrs(node.attrs)
if node.is_pub {
f.write('pub ')
@ -18,7 +18,9 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
}
f.write_language_prefix(node.language)
name := node.name.after('.') // strip prepended module
f.write(name)
if !is_anon {
f.write(name)
}
f.write_generic_types(node.generic_types)
if node.fields.len == 0 && node.embeds.len == 0 && node.pos.line_nr == node.pos.last_line {
f.writeln(' {}')
@ -28,8 +30,11 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
mut comment_aligns := []AlignInfo{}
mut default_expr_aligns := []AlignInfo{}
mut field_types := []string{cap: node.fields.len}
// Calculate the alignments first
for i, field in node.fields {
ft := f.no_cur_mod(f.table.type_to_str_using_aliases(field.typ, f.mod2alias))
// Handle anon structs recursively
sym := f.table.sym(field.typ)
field_types << ft
attrs_len := inline_attrs_len(field.attrs)
end_pos := field.pos.pos + field.pos.len
@ -68,6 +73,7 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
f.comments(comments, level: .indent)
}
}
// Now handle each field
mut field_align_i := 0
mut comment_align_i := 0
mut default_expr_align_i := 0
@ -125,7 +131,21 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
field_align = field_aligns[field_align_i]
}
f.write(strings.repeat(` `, field_align.max_len - field.name.len - comments_len))
f.write(field_types[i])
// 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
f.write(field_types[i])
}
f.mark_types_import_as_used(field.typ)
attrs_len := inline_attrs_len(field.attrs)
has_attrs := field.attrs.len > 0
@ -174,7 +194,11 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
}
}
f.comments_after_last_field(node.end_comments)
f.writeln('}\n')
if is_anon {
f.write('}')
} else {
f.writeln('}\n')
}
}
pub fn (mut f Fmt) struct_init(node ast.StructInit) {

View File

@ -26,7 +26,17 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
defer {
g.write(')')
}
if g.is_shared && !g.inside_opt_data && !g.is_arraymap_set {
mut is_anon := false
if sym.kind == .struct_ {
mut info := sym.info as ast.Struct
is_anon = info.is_anon
}
if is_anon {
// No name needed for anon structs, C figures it out on its own.
g.writeln('{')
} else if g.is_shared && !g.inside_opt_data && !g.is_arraymap_set {
mut shared_typ := node.typ.set_flag(.shared_f)
shared_styp = g.typ(shared_typ)
g.writeln('($shared_styp*)__dup${shared_styp}(&($shared_styp){.mtx = {0}, .val =($styp){')

View File

@ -199,6 +199,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
mut typ := ast.Type(0)
mut type_pos := token.Pos{}
mut field_pos := token.Pos{}
mut anon_struct_decl := ast.StructDecl{}
if is_embed {
// struct embedding
type_pos = p.tok.pos()
@ -237,7 +238,16 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
}
}
p.inside_struct_field_decl = true
typ = p.parse_type()
if p.tok.kind == .key_struct {
// Anon structs
if p.tok.kind == .key_struct {
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)
}
} else {
typ = p.parse_type()
}
p.inside_struct_field_decl = false
if typ.idx() == 0 {
// error is set in parse_type
@ -287,6 +297,7 @@ 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
}
}
// save embeds as table fields too, it will be used in generation phase

View File

@ -413,16 +413,18 @@ fn test_struct_update() {
assert c2.name == 'test'
}
/*
// Test anon structs
struct Book {
x Foo
title string
author struct {
x Foo
author struct {
name string
age int
age int
}
title string
}
fn test_anon() {}
*/
fn test_anon() {
// book := Book{author:struct{'sdf', 23}}
// println(book.author.age)
}