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:
parent
1ae11b41e7
commit
7d0a9186bb
@ -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:
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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('{')
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user