mirror of
https://github.com/vlang/v.git
synced 2025-09-19 04:17:46 -04:00
all: wrap up anonymous structs
This commit is contained in:
parent
1ae11b41e7
commit
7d0a9186bb
@ -452,8 +452,9 @@ pub struct StructInit {
|
|||||||
pub:
|
pub:
|
||||||
pos token.Pos
|
pos token.Pos
|
||||||
name_pos token.Pos
|
name_pos token.Pos
|
||||||
is_short bool // Foo{val1, val2}
|
no_keys bool // `Foo{val1, val2}`
|
||||||
is_short_syntax bool // foo(field1: val1, field2: val2)
|
is_short_syntax bool // `foo(field1: val1, field2: val2)`
|
||||||
|
is_anon bool // `x: struct{ foo: bar }`
|
||||||
pub mut:
|
pub mut:
|
||||||
unresolved bool
|
unresolved bool
|
||||||
pre_comments []Comment
|
pre_comments []Comment
|
||||||
@ -469,6 +470,12 @@ pub mut:
|
|||||||
generic_types []Type
|
generic_types []Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum StructInitKind {
|
||||||
|
normal
|
||||||
|
short_syntax
|
||||||
|
anon
|
||||||
|
}
|
||||||
|
|
||||||
// import statement
|
// import statement
|
||||||
pub struct Import {
|
pub struct Import {
|
||||||
pub:
|
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 {
|
&& c.table.cur_concrete_types.len == 0 {
|
||||||
pos := type_sym.name.last_index('.') or { -1 }
|
pos := type_sym.name.last_index('.') or { -1 }
|
||||||
first_letter := type_sym.name[pos + 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)
|
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 {
|
} else {
|
||||||
info = type_sym.info as ast.Struct
|
info = type_sym.info as ast.Struct
|
||||||
}
|
}
|
||||||
if node.is_short {
|
if node.no_keys {
|
||||||
exp_len := info.fields.len
|
exp_len := info.fields.len
|
||||||
got_len := node.fields.len
|
got_len := node.fields.len
|
||||||
if exp_len != got_len && !c.pref.translated {
|
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{}
|
mut info_fields_sorted := []ast.StructField{}
|
||||||
if node.is_short {
|
if node.no_keys {
|
||||||
info_fields_sorted = info.fields.clone()
|
info_fields_sorted = info.fields.clone()
|
||||||
info_fields_sorted.sort(a.i < b.i)
|
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 {
|
for i, mut field in node.fields {
|
||||||
mut field_info := ast.StructField{}
|
mut field_info := ast.StructField{}
|
||||||
mut field_name := ''
|
mut field_name := ''
|
||||||
if node.is_short {
|
if node.no_keys {
|
||||||
if i >= info.fields.len {
|
if i >= info.fields.len {
|
||||||
// It doesn't make sense to check for fields that don't exist.
|
// It doesn't make sense to check for fields that don't exist.
|
||||||
// We should just stop here.
|
// 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
|
// 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
|
mut found := false
|
||||||
for init_field in node.fields {
|
for init_field in node.fields {
|
||||||
if field.name == init_field.name {
|
if field.name == init_field.name {
|
||||||
|
@ -703,7 +703,7 @@ fn expr_is_single_line(expr ast.Expr) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.StructInit {
|
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
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,6 +216,9 @@ pub fn (mut f Fmt) struct_init(node ast.StructInit) {
|
|||||||
if name == 'void' {
|
if name == 'void' {
|
||||||
name = ''
|
name = ''
|
||||||
}
|
}
|
||||||
|
if node.is_anon {
|
||||||
|
f.write('struct ')
|
||||||
|
}
|
||||||
if node.fields.len == 0 && !node.has_update_expr {
|
if node.fields.len == 0 && !node.has_update_expr {
|
||||||
// `Foo{}` on one line if there are no fields or comments
|
// `Foo{}` on one line if there are no fields or comments
|
||||||
if node.pre_comments.len == 0 {
|
if node.pre_comments.len == 0 {
|
||||||
@ -226,8 +229,8 @@ pub fn (mut f Fmt) struct_init(node ast.StructInit) {
|
|||||||
f.write('}')
|
f.write('}')
|
||||||
}
|
}
|
||||||
f.mark_import_as_used(name)
|
f.mark_import_as_used(name)
|
||||||
} else if node.is_short {
|
} else if node.no_keys {
|
||||||
// `Foo{1,2,3}` (short syntax )
|
// `Foo{1,2,3}` (short syntax, no keys)
|
||||||
f.write('$name{')
|
f.write('$name{')
|
||||||
f.mark_import_as_used(name)
|
f.mark_import_as_used(name)
|
||||||
if node.has_update_expr {
|
if node.has_update_expr {
|
||||||
|
@ -22,17 +22,18 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
|
|||||||
if is_amp {
|
if is_amp {
|
||||||
g.out.go_back(1) // delete the `&` already generated in `prefix_expr()
|
g.out.go_back(1) // delete the `&` already generated in `prefix_expr()
|
||||||
}
|
}
|
||||||
g.write('(')
|
|
||||||
defer {
|
|
||||||
g.write(')')
|
|
||||||
}
|
|
||||||
|
|
||||||
mut is_anon := false
|
mut is_anon := false
|
||||||
if sym.kind == .struct_ {
|
if sym.kind == .struct_ {
|
||||||
mut info := sym.info as ast.Struct
|
mut info := sym.info as ast.Struct
|
||||||
|
|
||||||
is_anon = info.is_anon
|
is_anon = info.is_anon
|
||||||
}
|
}
|
||||||
|
if !is_anon {
|
||||||
|
g.write('(')
|
||||||
|
defer {
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
|
}
|
||||||
if is_anon {
|
if is_anon {
|
||||||
// No name needed for anon structs, C figures it out on its own.
|
// No name needed for anon structs, C figures it out on its own.
|
||||||
g.writeln('{')
|
g.writeln('{')
|
||||||
|
@ -325,6 +325,11 @@ pub fn (mut p Parser) check_expr(precedence int) ?ast.Expr {
|
|||||||
node = p.map_init()
|
node = p.map_init()
|
||||||
p.check(.rcbr)
|
p.check(.rcbr)
|
||||||
}
|
}
|
||||||
|
.key_struct {
|
||||||
|
// Anonymous struct
|
||||||
|
p.next()
|
||||||
|
return p.struct_init('', .anon)
|
||||||
|
}
|
||||||
.key_fn {
|
.key_fn {
|
||||||
if p.expecting_type {
|
if p.expecting_type {
|
||||||
// Anonymous function type
|
// Anonymous function type
|
||||||
|
@ -123,7 +123,7 @@ pub fn (mut p Parser) call_args() []ast.CallArg {
|
|||||||
mut expr := ast.empty_expr()
|
mut expr := ast.empty_expr()
|
||||||
if p.tok.kind == .name && p.peek_tok.kind == .colon {
|
if p.tok.kind == .name && p.peek_tok.kind == .colon {
|
||||||
// `foo(key:val, key2:val2)`
|
// `foo(key:val, key2:val2)`
|
||||||
expr = p.struct_init('void_type', true) // short_syntax:true
|
expr = p.struct_init('void_type', .short_syntax)
|
||||||
} else {
|
} else {
|
||||||
expr = p.expr(0)
|
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 || (p.inside_select && prev_tok_kind == .arrow && lit0_is_capital))
|
||||||
&& !p.inside_match_case && (!p.inside_if || p.inside_select)
|
&& !p.inside_match_case && (!p.inside_if || p.inside_select)
|
||||||
&& (!p.inside_for || p.inside_select) && !known_var {
|
&& (!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
|
} else if p.peek_tok.kind == .lcbr
|
||||||
&& ((p.inside_if && lit0_is_capital && p.tok.lit.len > 1 && !known_var && language == .v)
|
&& ((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)) {
|
|| (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{} {...} }`
|
// `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) {
|
} else if p.peek_tok.kind == .dot && (lit0_is_capital && !known_var && language == .v) {
|
||||||
// T.name
|
// T.name
|
||||||
if p.is_generic_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 {
|
fn (mut p Parser) struct_init(typ_str string, kind ast.StructInitKind) ast.StructInit {
|
||||||
first_pos := (if short_syntax && p.prev_tok.kind == .lcbr { p.prev_tok } else { p.tok }).pos()
|
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{}
|
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 = ''
|
p.expr_mod = ''
|
||||||
if !short_syntax {
|
if kind != .short_syntax {
|
||||||
p.check(.lcbr)
|
p.check(.lcbr)
|
||||||
}
|
}
|
||||||
pre_comments := p.eat_comments()
|
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.check(.rcbr)
|
||||||
}
|
}
|
||||||
p.is_amp = saved_is_amp
|
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
|
update_expr_comments: update_expr_comments
|
||||||
has_update_expr: has_update_expr
|
has_update_expr: has_update_expr
|
||||||
name_pos: first_pos
|
name_pos: first_pos
|
||||||
pos: first_pos.extend(if short_syntax { p.tok.pos() } else { p.prev_tok.pos() })
|
pos: first_pos.extend(if kind == .short_syntax { p.tok.pos() } else { p.prev_tok.pos() })
|
||||||
is_short: no_keys
|
no_keys: no_keys
|
||||||
is_short_syntax: short_syntax
|
is_short_syntax: kind == .short_syntax
|
||||||
|
is_anon: kind == .anon
|
||||||
pre_comments: pre_comments
|
pre_comments: pre_comments
|
||||||
generic_types: p.struct_init_generic_types
|
generic_types: p.struct_init_generic_types
|
||||||
}
|
}
|
||||||
|
@ -425,9 +425,25 @@ struct Book {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_anon() {
|
fn test_anon() {
|
||||||
empty_book := Book{} // author:struct{'sdf', 23}}
|
empty_book := Book{}
|
||||||
assert empty_book.author.age == 0
|
assert empty_book.author.age == 0
|
||||||
assert empty_book.author.name == ''
|
assert empty_book.author.name == ''
|
||||||
|
|
||||||
println(empty_book.author.age)
|
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