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

parser: fix option struct init decl with module prefix (#17615)

This commit is contained in:
Felipe Pena 2023-03-13 19:50:06 -03:00 committed by GitHub
parent f18cc6ebb0
commit d1d26893f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 44 deletions

View File

@ -6,12 +6,8 @@ module parser
import v.ast
import v.token
fn (mut p Parser) array_init() ast.ArrayInit {
fn (mut p Parser) array_init(is_option bool) ast.ArrayInit {
first_pos := p.tok.pos()
is_option := p.tok.kind == .question
if is_option {
p.next()
}
mut last_pos := p.tok.pos()
p.check(.lsbr)
// p.warn('array_init() exp=$p.expected_type')

View File

@ -195,7 +195,7 @@ pub fn (mut p Parser) check_expr(precedence int) !ast.Expr {
pos: pos
}
} else {
node = p.array_init()
node = p.array_init(false)
}
}
.key_none {
@ -436,7 +436,7 @@ pub fn (mut p Parser) check_expr(precedence int) !ast.Expr {
if p.tok.kind == .key_struct && p.peek_tok.kind == .lcbr {
// Anonymous struct
p.next()
return p.struct_init('', .anon)
return p.struct_init('', .anon, false)
}
if p.tok.kind != .eof && !(p.tok.kind == .rsbr && p.inside_asm) {
// eof should be handled where it happens

View File

@ -113,7 +113,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', .short_syntax)
expr = p.struct_init('void_type', .short_syntax, false)
} else {
expr = p.expr(0)
}

View File

@ -2393,14 +2393,19 @@ pub fn (mut p Parser) name_expr() ast.Expr {
language = ast.Language.wasm
p.check_for_impure_v(language, p.tok.pos())
}
is_option := p.tok.kind == .question
if is_option {
if p.peek_tok.kind in [.name, .lsbr] {
p.check(.question)
}
}
mut mod := ''
// p.warn('resetting')
p.expr_mod = ''
// `map[string]int` initialization
if (p.tok.lit == 'map' && p.peek_tok.kind == .lsbr)
|| (p.tok.kind == .question && p.peek_tok.lit == 'map') {
if p.tok.lit == 'map' && p.peek_tok.kind == .lsbr {
mut pos := p.tok.pos()
map_type := p.parse_map_type()
mut map_type := p.parse_map_type()
if p.tok.kind == .lcbr {
p.next()
if p.tok.kind == .rcbr {
@ -2415,6 +2420,9 @@ pub fn (mut p Parser) name_expr() ast.Expr {
p.error('`}` expected; explicit `map` initialization does not support parameters')
}
}
if is_option {
map_type = map_type.set_flag(.option)
}
return ast.MapInit{
typ: map_type
pos: pos
@ -2519,17 +2527,8 @@ pub fn (mut p Parser) name_expr() ast.Expr {
p.check(.dot)
p.expr_mod = mod
}
is_option := p.tok.kind == .question
lit0_is_capital := if p.tok.kind != .eof && p.tok.lit.len > 0 {
if is_option {
if p.peek_tok.kind != .eof && p.peek_tok.lit.len > 0 {
p.peek_tok.lit[0].is_capital()
} else {
false
}
} else {
p.tok.lit[0].is_capital()
}
} else {
false
}
@ -2550,18 +2549,14 @@ pub fn (mut p Parser) name_expr() ast.Expr {
}
}
} else if p.peek_tok.kind == .lpar || is_generic_call || is_generic_cast
|| (is_option && p.peek_token(2).kind == .lpar) || (is_option && ((p.peek_tok.kind == .lsbr
&& p.peek_token(2).kind == .rsbr && p.peek_token(3).kind == .name
&& p.peek_token(4).kind == .lpar) || (p.peek_tok.kind == .lsbr
&& p.peek_token(2).kind == .number && p.peek_token(3).kind == .rsbr
&& p.peek_token(4).kind == .name && p.peek_token(5).kind == .lpar))) {
is_array := p.peek_tok.kind == .lsbr
is_fixed_array := is_array && p.peek_token(2).kind == .number
// foo(), foo<int>() or type() cast
mut name := if is_option {
if is_array { p.peek_token(if is_fixed_array { 4 } else { 3 }).lit
} else { p.peek_tok.lit
}
|| (p.tok.kind == .lsbr && p.peek_tok.kind == .rsbr && p.peek_token(3).kind == .lpar)
|| (p.tok.kind == .lsbr && p.peek_tok.kind == .number && p.peek_token(2).kind == .rsbr
&& p.peek_token(4).kind == .lpar) {
// ?[]foo(), ?[1]foo, foo(), foo<int>() or type() cast
is_array := p.tok.kind == .lsbr
is_fixed_array := is_array && p.peek_tok.kind == .number
mut name := if is_array {
p.peek_token(if is_fixed_array { 3 } else { 2 }).lit
} else {
p.tok.lit
}
@ -2573,8 +2568,8 @@ pub fn (mut p Parser) name_expr() ast.Expr {
// if name in ast.builtin_type_names_to_idx {
if (!known_var && (name in p.table.type_idxs || name_w_mod in p.table.type_idxs)
&& name !in ['C.statvfs', 'C.stat', 'C.sigaction']) || is_mod_cast
|| is_generic_cast
|| (language == .v && name.len > 0 && name[0].is_capital()) {
|| is_generic_cast || (language == .v && name.len > 0 && (name[0].is_capital()
|| name.all_after_last('.')[0].is_capital())) {
// MainLetter(x) is *always* a cast, as long as it is not `C.`
// TODO handle C.stat()
start_pos := p.tok.pos()
@ -2599,6 +2594,9 @@ pub fn (mut p Parser) name_expr() ast.Expr {
}
end_pos := p.tok.pos()
p.check(.rpar)
if is_option {
to_typ = to_typ.set_flag(.option)
}
node = ast.CastExpr{
typ: to_typ
typname: p.table.sym(to_typ).name
@ -2630,17 +2628,16 @@ pub fn (mut p Parser) name_expr() ast.Expr {
}
}
}
} else if (((!is_option && p.peek_tok.kind == .lcbr)
|| (is_option && p.peek_token(2).kind == .lcbr)) || is_generic_struct_init)
} else if (p.peek_tok.kind == .lcbr || is_generic_struct_init)
&& (!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, .normal) // short_syntax: false
return p.struct_init(p.mod + '.' + p.tok.lit, .normal, is_option) // 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, .normal)
return p.struct_init(p.mod + '.' + p.tok.lit, .normal, is_option)
} else if p.peek_tok.kind == .dot && (lit0_is_capital && !known_var && language == .v) {
// T.name
if p.is_generic_name() {
@ -2696,7 +2693,10 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|| p.table.find_type_idx(p.mod + '.' + p.tok.lit) > 0
|| p.inside_comptime_if) {
type_pos := p.tok.pos()
typ := p.parse_type()
mut typ := p.parse_type()
if is_option {
typ = typ.set_flag(.option)
}
return ast.TypeNode{
typ: typ
pos: type_pos
@ -2719,8 +2719,8 @@ pub fn (mut p Parser) name_expr() ast.Expr {
}
p.expr_mod = ''
return node
} else if p.tok.kind == .question && p.peek_tok.kind == .lsbr {
return p.array_init()
} else if is_option && p.tok.kind == .lsbr {
return p.array_init(is_option)
}
ident := p.parse_ident(language)
node = ident

View File

@ -399,10 +399,13 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
}
}
fn (mut p Parser) struct_init(typ_str string, kind ast.StructInitKind) ast.StructInit {
fn (mut p Parser) struct_init(typ_str string, kind ast.StructInitKind, is_option bool) 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 kind == .short_syntax { ast.void_type } else { p.parse_type() }
mut typ := if kind == .short_syntax { ast.void_type } else { p.parse_type() }
if is_option {
typ = typ.set_flag(.option)
}
p.expr_mod = ''
if kind != .short_syntax {
p.check(.lcbr)

View File

@ -0,0 +1,17 @@
module main
import another_module as aaa
fn test_import_opt_struct_from_another_module() {
x := ?aaa.SomeStruct{}
assert dump(x == none) == true
}
fn test(a ?aaa.SomeStruct) ?aaa.SomeStruct {
return none
}
fn test_fn_decl_with_struct_from_another_module() {
x := test(?aaa.SomeStruct(none))
assert dump(x == none) == true
}