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:
parent
f18cc6ebb0
commit
d1d26893f5
@ -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')
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
17
vlib/v/tests/option_import_struct_test.v
Normal file
17
vlib/v/tests/option_import_struct_test.v
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user