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

all: wrap up anonymous structs

This commit is contained in:
Alexander Medvednikov 2022-07-10 12:00:17 +03:00
parent 1ae11b41e7
commit 7d0a9186bb
10 changed files with 62 additions and 28 deletions

View File

@ -452,8 +452,9 @@ pub struct StructInit {
pub:
pos token.Pos
name_pos token.Pos
is_short bool // Foo{val1, val2}
is_short_syntax bool // foo(field1: val1, field2: val2)
no_keys bool // `Foo{val1, val2}`
is_short_syntax bool // `foo(field1: val1, field2: val2)`
is_anon bool // `x: struct{ foo: bar }`
pub mut:
unresolved bool
pre_comments []Comment
@ -469,6 +470,12 @@ pub mut:
generic_types []Type
}
pub enum StructInitKind {
normal
short_syntax
anon
}
// import statement
pub struct Import {
pub:

View File

@ -267,7 +267,8 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
&& c.table.cur_concrete_types.len == 0 {
pos := type_sym.name.last_index('.') or { -1 }
first_letter := type_sym.name[pos + 1]
if !first_letter.is_capital() && type_sym.kind != .placeholder {
if !first_letter.is_capital() && type_sym.kind != .placeholder
&& !type_sym.name.starts_with('main._VAnonStruct') {
c.error('cannot initialize builtin type `$type_sym.name`', node.pos)
}
}
@ -324,7 +325,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
} else {
info = type_sym.info as ast.Struct
}
if node.is_short {
if node.no_keys {
exp_len := info.fields.len
got_len := node.fields.len
if exp_len != got_len && !c.pref.translated {
@ -335,7 +336,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
}
}
mut info_fields_sorted := []ast.StructField{}
if node.is_short {
if node.no_keys {
info_fields_sorted = info.fields.clone()
info_fields_sorted.sort(a.i < b.i)
}
@ -343,7 +344,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
for i, mut field in node.fields {
mut field_info := ast.StructField{}
mut field_name := ''
if node.is_short {
if node.no_keys {
if i >= info.fields.len {
// It doesn't make sense to check for fields that don't exist.
// We should just stop here.
@ -496,7 +497,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
}
*/
// Check for `[required]` struct attr
if field.attrs.contains('required') && !node.is_short && !node.has_update_expr {
if field.attrs.contains('required') && !node.no_keys && !node.has_update_expr {
mut found := false
for init_field in node.fields {
if field.name == init_field.name {

View File

@ -703,7 +703,7 @@ fn expr_is_single_line(expr ast.Expr) bool {
}
}
ast.StructInit {
if !expr.is_short && (expr.fields.len > 0 || expr.pre_comments.len > 0) {
if !expr.no_keys && (expr.fields.len > 0 || expr.pre_comments.len > 0) {
return false
}
}

View File

@ -216,6 +216,9 @@ pub fn (mut f Fmt) struct_init(node ast.StructInit) {
if name == 'void' {
name = ''
}
if node.is_anon {
f.write('struct ')
}
if node.fields.len == 0 && !node.has_update_expr {
// `Foo{}` on one line if there are no fields or comments
if node.pre_comments.len == 0 {
@ -226,8 +229,8 @@ pub fn (mut f Fmt) struct_init(node ast.StructInit) {
f.write('}')
}
f.mark_import_as_used(name)
} else if node.is_short {
// `Foo{1,2,3}` (short syntax )
} else if node.no_keys {
// `Foo{1,2,3}` (short syntax, no keys)
f.write('$name{')
f.mark_import_as_used(name)
if node.has_update_expr {

View File

@ -22,17 +22,18 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
if is_amp {
g.out.go_back(1) // delete the `&` already generated in `prefix_expr()
}
g.write('(')
defer {
g.write(')')
}
mut is_anon := false
if sym.kind == .struct_ {
mut info := sym.info as ast.Struct
is_anon = info.is_anon
}
if !is_anon {
g.write('(')
defer {
g.write(')')
}
}
if is_anon {
// No name needed for anon structs, C figures it out on its own.
g.writeln('{')

View File

@ -325,6 +325,11 @@ pub fn (mut p Parser) check_expr(precedence int) ?ast.Expr {
node = p.map_init()
p.check(.rcbr)
}
.key_struct {
// Anonymous struct
p.next()
return p.struct_init('', .anon)
}
.key_fn {
if p.expecting_type {
// Anonymous function type

View File

@ -123,7 +123,7 @@ pub fn (mut p Parser) call_args() []ast.CallArg {
mut expr := ast.empty_expr()
if p.tok.kind == .name && p.peek_tok.kind == .colon {
// `foo(key:val, key2:val2)`
expr = p.struct_init('void_type', true) // short_syntax:true
expr = p.struct_init('void_type', .short_syntax)
} else {
expr = p.expr(0)
}

View File

@ -2428,12 +2428,12 @@ pub fn (mut p Parser) name_expr() ast.Expr {
&& (!p.inside_match || (p.inside_select && prev_tok_kind == .arrow && lit0_is_capital))
&& !p.inside_match_case && (!p.inside_if || p.inside_select)
&& (!p.inside_for || p.inside_select) && !known_var {
return p.struct_init(p.mod + '.' + p.tok.lit, false) // short_syntax: false
return p.struct_init(p.mod + '.' + p.tok.lit, .normal) // short_syntax: false
} else if p.peek_tok.kind == .lcbr
&& ((p.inside_if && lit0_is_capital && p.tok.lit.len > 1 && !known_var && language == .v)
|| (p.inside_match_case && p.tok.kind == .name && p.peek_tok.pos - p.tok.pos == p.tok.len)) {
// `if a == Foo{} {...}` or `match foo { Foo{} {...} }`
return p.struct_init(p.mod + '.' + p.tok.lit, false)
return p.struct_init(p.mod + '.' + p.tok.lit, .normal)
} else if p.peek_tok.kind == .dot && (lit0_is_capital && !known_var && language == .v) {
// T.name
if p.is_generic_name() {

View File

@ -385,12 +385,12 @@ run them via `v file.v` instead',
}
}
fn (mut p Parser) struct_init(typ_str string, short_syntax bool) ast.StructInit {
first_pos := (if short_syntax && p.prev_tok.kind == .lcbr { p.prev_tok } else { p.tok }).pos()
fn (mut p Parser) struct_init(typ_str string, kind ast.StructInitKind) ast.StructInit {
first_pos := (if kind == .short_syntax && p.prev_tok.kind == .lcbr { p.prev_tok } else { p.tok }).pos()
p.struct_init_generic_types = []ast.Type{}
typ := if short_syntax { ast.void_type } else { p.parse_type() }
typ := if kind == .short_syntax { ast.void_type } else { p.parse_type() }
p.expr_mod = ''
if !short_syntax {
if kind != .short_syntax {
p.check(.lcbr)
}
pre_comments := p.eat_comments()
@ -459,7 +459,7 @@ fn (mut p Parser) struct_init(typ_str string, short_syntax bool) ast.StructInit
}
}
}
if !short_syntax {
if kind != .short_syntax {
p.check(.rcbr)
}
p.is_amp = saved_is_amp
@ -472,9 +472,10 @@ fn (mut p Parser) struct_init(typ_str string, short_syntax bool) ast.StructInit
update_expr_comments: update_expr_comments
has_update_expr: has_update_expr
name_pos: first_pos
pos: first_pos.extend(if short_syntax { p.tok.pos() } else { p.prev_tok.pos() })
is_short: no_keys
is_short_syntax: short_syntax
pos: first_pos.extend(if kind == .short_syntax { p.tok.pos() } else { p.prev_tok.pos() })
no_keys: no_keys
is_short_syntax: kind == .short_syntax
is_anon: kind == .anon
pre_comments: pre_comments
generic_types: p.struct_init_generic_types
}

View File

@ -425,9 +425,25 @@ struct Book {
}
fn test_anon() {
empty_book := Book{} // author:struct{'sdf', 23}}
empty_book := Book{}
assert empty_book.author.age == 0
assert empty_book.author.name == ''
println(empty_book.author.age)
book := Book{
author: struct {'Peter Brown', 23}
}
assert book.author.name == 'Peter Brown'
assert book.author.age == 23
println(book.author.name)
book2 := Book{
author: struct {
name: 'Samantha Black'
age: 24
}
}
assert book2.author.name == 'Samantha Black'
assert book2.author.age == 24
println(book2.author.name)
}