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 default_expr_typ Type
name string name string
typ Type typ Type
anon_struct_decl StructDecl // only if the field is an anonymous struct
} }
pub fn (f &StructField) equals(o &StructField) bool { pub fn (f &StructField) equals(o &StructField) bool {

View File

@ -1121,7 +1121,7 @@ pub mut:
parent_type Type 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 { pub fn (t &Table) type_to_str(typ Type) string {
return t.type_to_str_using_aliases(typ, map[string]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) f.sql_stmt(node)
} }
ast.StructDecl { ast.StructDecl {
f.struct_decl(node) f.struct_decl(node, false)
} }
ast.TypeDecl { ast.TypeDecl {
f.type_decl(node) f.type_decl(node)

View File

@ -6,7 +6,7 @@ module fmt
import strings import strings
import v.ast 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) f.attrs(node.attrs)
if node.is_pub { if node.is_pub {
f.write('pub ') f.write('pub ')
@ -18,7 +18,9 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
} }
f.write_language_prefix(node.language) f.write_language_prefix(node.language)
name := node.name.after('.') // strip prepended module name := node.name.after('.') // strip prepended module
f.write(name) if !is_anon {
f.write(name)
}
f.write_generic_types(node.generic_types) f.write_generic_types(node.generic_types)
if node.fields.len == 0 && node.embeds.len == 0 && node.pos.line_nr == node.pos.last_line { if node.fields.len == 0 && node.embeds.len == 0 && node.pos.line_nr == node.pos.last_line {
f.writeln(' {}') f.writeln(' {}')
@ -28,8 +30,11 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
mut comment_aligns := []AlignInfo{} mut comment_aligns := []AlignInfo{}
mut default_expr_aligns := []AlignInfo{} mut default_expr_aligns := []AlignInfo{}
mut field_types := []string{cap: node.fields.len} mut field_types := []string{cap: node.fields.len}
// Calculate the alignments first
for i, field in node.fields { for i, field in node.fields {
ft := f.no_cur_mod(f.table.type_to_str_using_aliases(field.typ, f.mod2alias)) 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 field_types << ft
attrs_len := inline_attrs_len(field.attrs) attrs_len := inline_attrs_len(field.attrs)
end_pos := field.pos.pos + field.pos.len 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) f.comments(comments, level: .indent)
} }
} }
// Now handle each field
mut field_align_i := 0 mut field_align_i := 0
mut comment_align_i := 0 mut comment_align_i := 0
mut default_expr_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] field_align = field_aligns[field_align_i]
} }
f.write(strings.repeat(` `, field_align.max_len - field.name.len - comments_len)) 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) f.mark_types_import_as_used(field.typ)
attrs_len := inline_attrs_len(field.attrs) attrs_len := inline_attrs_len(field.attrs)
has_attrs := field.attrs.len > 0 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.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) { 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 { defer {
g.write(')') 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) mut shared_typ := node.typ.set_flag(.shared_f)
shared_styp = g.typ(shared_typ) shared_styp = g.typ(shared_typ)
g.writeln('($shared_styp*)__dup${shared_styp}(&($shared_styp){.mtx = {0}, .val =($styp){') 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 typ := ast.Type(0)
mut type_pos := token.Pos{} mut type_pos := token.Pos{}
mut field_pos := token.Pos{} mut field_pos := token.Pos{}
mut anon_struct_decl := ast.StructDecl{}
if is_embed { if is_embed {
// struct embedding // struct embedding
type_pos = p.tok.pos() 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 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 p.inside_struct_field_decl = false
if typ.idx() == 0 { if typ.idx() == 0 {
// error is set in parse_type // 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_global: is_field_global
is_volatile: is_field_volatile is_volatile: is_field_volatile
is_deprecated: is_field_deprecated is_deprecated: is_field_deprecated
anon_struct_decl: anon_struct_decl
} }
} }
// save embeds as table fields too, it will be used in generation phase // 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' assert c2.name == 'test'
} }
/*
// Test anon structs // Test anon structs
struct Book { struct Book {
x Foo x Foo
title string author struct {
author struct {
name string name string
age int age int
} }
title string
} }
fn test_anon() {} fn test_anon() {
*/ // book := Book{author:struct{'sdf', 23}}
// println(book.author.age)
}