From aef83bae62d53de1c0e4957f7cb6ecda27d1dcf6 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 18 Aug 2023 18:28:57 +0300 Subject: [PATCH] all: `@[attr]` syntax --- vlib/v/ast/attr.v | 1 + vlib/v/fmt/attrs.v | 6 ++++++ vlib/v/parser/parser.v | 28 +++++++++++++++++++++++----- vlib/v/parser/struct.v | 2 +- vlib/v/scanner/scanner.v | 4 ++++ vlib/v/tests/enum_attr_test.v | 4 ++-- 6 files changed, 37 insertions(+), 8 deletions(-) diff --git a/vlib/v/ast/attr.v b/vlib/v/ast/attr.v index 76a1e91634..dc55539075 100644 --- a/vlib/v/ast/attr.v +++ b/vlib/v/ast/attr.v @@ -23,6 +23,7 @@ pub: kind AttrKind ct_opt bool // true for [if user_defined_name?] pos token.Pos + has_at bool // new syntax `@[attr]` pub mut: ct_expr Expr // .kind == comptime_define, for [if !name] ct_evaled bool // whether ct_skip has been evaluated already diff --git a/vlib/v/fmt/attrs.v b/vlib/v/fmt/attrs.v index 9ea265ccc9..75c612e526 100644 --- a/vlib/v/fmt/attrs.v +++ b/vlib/v/fmt/attrs.v @@ -17,6 +17,9 @@ pub fn (mut f Fmt) attrs(attrs []ast.Attr) { f.single_line_attrs(sorted_attrs[i..]) break } + if attr.has_at { + f.write('@') + } f.writeln('[${attr}]') } } @@ -35,6 +38,9 @@ pub fn (mut f Fmt) single_line_attrs(attrs []ast.Attr, options AttrsOptions) { if options.inline { f.write(' ') } + if attrs[0].has_at { + f.write('@') + } f.write('[') for i, attr in sorted_attrs { if i > 0 { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index ba9f3616e5..13cdde633f 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -723,6 +723,14 @@ fn (mut p Parser) top_stmt() ast.Stmt { } } } + .at { + if p.peek_tok.kind == .lsbr { + p.attributes() + continue + } else { + return p.error('@[attr] expected') + } + } .lsbr { // attrs are stored in `p.attrs` p.attributes() @@ -1769,11 +1777,20 @@ fn (mut p Parser) is_attributes() bool { // when is_top_stmt is true attrs are added to p.attrs fn (mut p Parser) attributes() { - p.check(.lsbr) + mut is_at := false + if p.tok.kind == .lsbr { + // [attr] + p.check(.lsbr) + } else if p.tok.kind == .at { + // @[attr] + p.check(.at) + p.check(.lsbr) + is_at = true + } mut has_ctdefine := false for p.tok.kind != .rsbr { start_pos := p.tok.pos() - attr := p.parse_attr() + attr := p.parse_attr(is_at) if p.attrs.contains(attr.name) && attr.name != 'wasm_export' { p.error_with_pos('duplicate attribute `${attr.name}`', start_pos.extend(p.prev_tok.pos())) return @@ -1809,7 +1826,7 @@ fn (mut p Parser) attributes() { } } -fn (mut p Parser) parse_attr() ast.Attr { +fn (mut p Parser) parse_attr(is_at bool) ast.Attr { mut kind := ast.AttrKind.plain apos := p.prev_tok.pos() if p.tok.kind == .key_unsafe { @@ -1882,6 +1899,7 @@ fn (mut p Parser) parse_attr() ast.Attr { ct_expr: comptime_cond ct_opt: comptime_cond_opt pos: apos.extend(p.tok.pos()) + has_at: is_at } } @@ -3431,7 +3449,7 @@ fn (mut p Parser) parse_number_literal() ast.Expr { fn (mut p Parser) module_decl() ast.Module { mut module_attrs := []ast.Attr{} mut attrs_pos := p.tok.pos() - for p.tok.kind == .lsbr { + for p.tok.kind == .lsbr || p.tok.kind == .at { p.attributes() } module_attrs << p.attrs @@ -3959,7 +3977,7 @@ fn (mut p Parser) enum_decl() ast.EnumDecl { uses_exprs = true } mut attrs := []ast.Attr{} - if p.tok.kind == .lsbr { + if p.tok.kind == .lsbr || p.tok.kind == .at { p.attributes() attrs << p.attrs enum_attrs[val] = attrs diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 41336a74e5..caead54cad 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -269,7 +269,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl { // Comments after type (same line) prev_attrs := p.attrs p.attrs = [] - if p.tok.kind == .lsbr { + if p.tok.kind == .lsbr || p.tok.kind == .at { p.inside_struct_attr_decl = true // attrs are stored in `p.attrs` p.attributes() diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index cc880f129a..c429731e66 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -886,6 +886,10 @@ fn (mut s Scanner) text_scan() token.Token { return s.new_token(.comma, '', 1) } `@` { + // @[attr] + if s.text[s.pos + 1] == `[` { + return s.new_token(.at, '', 1) + } mut name := '' if nextc != `\0` { s.pos++ diff --git a/vlib/v/tests/enum_attr_test.v b/vlib/v/tests/enum_attr_test.v index d2595214b3..f55dbe7b8a 100644 --- a/vlib/v/tests/enum_attr_test.v +++ b/vlib/v/tests/enum_attr_test.v @@ -1,8 +1,8 @@ import json enum Foo { - yay [json: 'A'; yay] - foo [foo; json: 'B'] + yay @[json: 'A'; yay] + foo @[foo; json: 'B'] } struct FooStruct {