From 359f16fdfdb628d0c5c3941249ba88a7a901d180 Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Tue, 5 Apr 2022 17:39:49 +0200 Subject: [PATCH] parser: fixed parsing prototype function with recursive type (#13922) --- vlib/v/ast/table.v | 14 +++++++++++++- vlib/v/parser/fn.v | 4 +++- vlib/v/parser/struct.v | 5 +++++ .../parser/tests/function_prototype_in_struct.out | 0 .../v/parser/tests/function_prototype_in_struct.vv | 9 +++++++++ 5 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 vlib/v/parser/tests/function_prototype_in_struct.out create mode 100644 vlib/v/parser/tests/function_prototype_in_struct.vv diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 834e153bd..75c1d8cc1 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -11,6 +11,8 @@ import v.util [heap] pub struct Table { +mut: + parsing_type string // name of the type to enable recursive type parsing pub mut: type_symbols []&TypeSymbol type_idxs map[string]int @@ -830,7 +832,17 @@ pub fn (mut t Table) register_enum_decl(enum_decl EnumDecl) { } pub fn (t &Table) known_type(name string) bool { - return t.find_type_idx(name) != 0 + return t.find_type_idx(name) != 0 || t.parsing_type == name +} + +// start_parsing_type open the scope during the parsing of a type +// where the type name must include the module prefix +pub fn (mut t Table) start_parsing_type(type_name string) { + t.parsing_type = type_name +} + +pub fn (mut t Table) reset_parsing_type() { + t.parsing_type = '' } pub fn (t &Table) known_type_idx(typ Type) bool { diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 295c095db..3072cfb92 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -738,13 +738,14 @@ fn (mut p Parser) fn_args() ([]ast.Param, bool, bool) { } else { p.tok.lit } + types_only := p.tok.kind in [.amp, .ellipsis, .key_fn, .lsbr] || (p.peek_tok.kind == .comma && p.table.known_type(argname)) || p.peek_tok.kind == .dot || p.peek_tok.kind == .rpar || (p.tok.kind == .key_mut && (p.peek_token(2).kind == .comma || p.peek_token(2).kind == .rpar || (p.peek_tok.kind == .name && p.peek_token(2).kind == .dot))) - // TODO copy pasta, merge 2 branches + // TODO copy paste, merge 2 branches if types_only { mut arg_no := 1 for p.tok.kind != .rpar { @@ -800,6 +801,7 @@ fn (mut p Parser) fn_args() ([]ast.Param, bool, bool) { p.error_with_pos('expecting `)`', p.prev_tok.pos()) return []ast.Param{}, false, false } + if p.tok.kind == .comma { if is_variadic { p.error_with_pos('cannot use ...(variadic) with non-final parameter no $arg_no', diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 9ef473eae..c1c289b82 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -51,6 +51,11 @@ fn (mut p Parser) struct_decl() ast.StructDecl { p.error_with_pos('cannot register struct `IError`, it is builtin interface type', name_pos) } + // append module name before any type of parsing to enable recursion parsing + p.table.start_parsing_type(p.prepend_mod(name)) + defer { + p.table.reset_parsing_type() + } generic_types, _ := p.parse_generic_types() no_body := p.tok.kind != .lcbr if language == .v && no_body { diff --git a/vlib/v/parser/tests/function_prototype_in_struct.out b/vlib/v/parser/tests/function_prototype_in_struct.out new file mode 100644 index 000000000..e69de29bb diff --git a/vlib/v/parser/tests/function_prototype_in_struct.vv b/vlib/v/parser/tests/function_prototype_in_struct.vv new file mode 100644 index 000000000..d637f7d37 --- /dev/null +++ b/vlib/v/parser/tests/function_prototype_in_struct.vv @@ -0,0 +1,9 @@ +module main + +struct Ok { + alibaba fn (Ok, ) +} + +struct OkInt { + a fn (int, ) +} -- 2.39.5