diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index c0e92ec373..36ed395e40 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -567,6 +567,14 @@ pub struct Attr { pub: name string } +pub fn (attrs []Attr) contains(attr Attr) bool { + for a in attrs { + if attr.name == a.name { + return true + } + } + return false +} pub struct EnumVal { pub: diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 3d8a61592a..3f2b7bd391 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -414,12 +414,7 @@ pub fn (mut p Parser) top_stmt() ast.Stmt { } } .lsbr { - start_pos := p.tok.position() - attrs := p.attributes() - if attrs.len == 0 { - end_pos := p.tok.position() - p.error_with_pos('attributes cannot be empty', start_pos.extend(end_pos)) - } + attrs := p.attributes(true) return attrs[0] } .key_interface { @@ -626,11 +621,19 @@ fn (mut p Parser) expr_list() []ast.Expr { return exprs } -fn (mut p Parser) attributes() []ast.Attr { +// when is_top_stmt is true attrs are added to p.attrs +fn (mut p Parser) attributes(is_top_stmt bool) []ast.Attr { mut attrs := []ast.Attr{} p.check(.lsbr) for p.tok.kind != .rsbr { + start_pos := p.tok.position() attr := p.parse_attr() + if attr in attrs || (is_top_stmt && attr.name in p.attrs) { + p.error_with_pos('duplicate attribute `$attr.name`', start_pos.extend(p.prev_tok.position())) + } + if is_top_stmt { + p.attrs << attr.name + } attrs << attr if p.tok.kind != .semicolon { expected := `;` @@ -642,11 +645,13 @@ fn (mut p Parser) attributes() []ast.Attr { } p.next() } + if attrs.len == 0 { + p.error_with_pos('attributes cannot be empty', p.prev_tok.position().extend(p.tok.position())) + } return attrs } fn (mut p Parser) parse_attr() ast.Attr { - start_pos := p.prev_tok.position() mut is_if_attr := false if p.tok.kind == .key_if { p.next() @@ -663,10 +668,6 @@ fn (mut p Parser) parse_attr() ast.Attr { p.next() } } - if name in p.attrs { - p.error_with_pos('duplicate attribute `$name`', start_pos.extend(p.tok.position())) - } - p.attrs << name if is_if_attr { p.attr_ctdefine = name } diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 8b5a9d5389..e3cf2e6f07 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -117,7 +117,7 @@ fn (mut p Parser) struct_decl() ast.StructDecl { */ mut attrs := []string{} if p.tok.kind == .lsbr { - parsed_attrs := p.attributes() + parsed_attrs := p.attributes(false) for attr in parsed_attrs { attrs << attr.name } diff --git a/vlib/v/parser/tests/fn_attributes_duplicate_multiple.out b/vlib/v/parser/tests/fn_attributes_duplicate_multiple.out index db1d899ca9..b82d0bb735 100644 --- a/vlib/v/parser/tests/fn_attributes_duplicate_multiple.out +++ b/vlib/v/parser/tests/fn_attributes_duplicate_multiple.out @@ -1,6 +1,6 @@ -vlib/v/parser/tests/fn_attributes_duplicate_multiple.v:2:1: error: duplicate attribute `inline` +vlib/v/parser/tests/fn_attributes_duplicate_multiple.v:2:2: error: duplicate attribute `inline` 1 | [inline] 2 | [inline] - | ~~~~~~~~ + | ~~~~~~ 3 | fn foo() {} 4 | diff --git a/vlib/v/parser/tests/fn_attributes_duplicate_single.out b/vlib/v/parser/tests/fn_attributes_duplicate_single.out index 69a413edc4..c135743ff7 100644 --- a/vlib/v/parser/tests/fn_attributes_duplicate_single.out +++ b/vlib/v/parser/tests/fn_attributes_duplicate_single.out @@ -1,5 +1,5 @@ -vlib/v/parser/tests/fn_attributes_duplicate_single.v:1:8: error: duplicate attribute `inline` +vlib/v/parser/tests/fn_attributes_duplicate_single.v:1:10: error: duplicate attribute `inline` 1 | [inline; inline] - | ~~~~~~~~~ + | ~~~~~~ 2 | fn foo() {} 3 |