From af8ef12990a7a3c63ce0093488d6d4674a791463 Mon Sep 17 00:00:00 2001 From: Enzo Date: Fri, 23 Apr 2021 14:51:52 +0200 Subject: [PATCH] ast: use `AttrKind` (#9845) --- vlib/v/ast/attr.v | 62 ++++++++++----------- vlib/v/checker/checker.v | 9 +-- vlib/v/gen/c/sql.v | 6 +- vlib/v/parser/fn.v | 8 +-- vlib/v/parser/parser.v | 60 +++++++------------- vlib/v/parser/tests/invalid_attribute_a.out | 5 ++ vlib/v/parser/tests/invalid_attribute_a.vv | 3 + vlib/v/parser/tests/invalid_attribute_b.out | 5 ++ vlib/v/parser/tests/invalid_attribute_b.vv | 3 + vlib/v/parser/tests/invalid_attribute_c.out | 5 ++ vlib/v/parser/tests/invalid_attribute_c.vv | 3 + vlib/v/parser/tests/invalid_attribute_d.out | 5 ++ vlib/v/parser/tests/invalid_attribute_d.vv | 3 + 13 files changed, 89 insertions(+), 88 deletions(-) create mode 100644 vlib/v/parser/tests/invalid_attribute_a.out create mode 100644 vlib/v/parser/tests/invalid_attribute_a.vv create mode 100644 vlib/v/parser/tests/invalid_attribute_b.out create mode 100644 vlib/v/parser/tests/invalid_attribute_b.vv create mode 100644 vlib/v/parser/tests/invalid_attribute_c.out create mode 100644 vlib/v/parser/tests/invalid_attribute_c.vv create mode 100644 vlib/v/parser/tests/invalid_attribute_d.out create mode 100644 vlib/v/parser/tests/invalid_attribute_d.vv diff --git a/vlib/v/ast/attr.v b/vlib/v/ast/attr.v index 1d473a4e19..0884ce8de5 100644 --- a/vlib/v/ast/attr.v +++ b/vlib/v/ast/attr.v @@ -5,55 +5,49 @@ module ast import v.token +pub enum AttrKind { + plain // [name] + string // ['name'] + number // [123] + comptime_define // [if name] +} + // e.g. `[unsafe]` pub struct Attr { pub: - name string // [name] - is_string bool // ['name'] - is_comptime_define bool // [if name] - arg string // [name: arg] - is_string_arg bool // [name: 'arg'] - is_number_arg bool // [name: 123] - pos token.Position + name string // [name] + has_arg bool + arg string // [name: arg] + kind AttrKind + pos token.Position } -// no square brackets -pub fn (attr Attr) str() string { +// str returns the string representation without square brackets +pub fn (a Attr) str() string { mut s := '' - if attr.is_comptime_define { - s += 'if ' - } - if attr.is_string { - s += "'$attr.name'" + mut arg := if a.has_arg { + s += '$a.name: ' + a.arg } else { - s += attr.name - if attr.arg.len > 0 { - s += ': ' - if attr.is_string_arg { - a := attr.arg.replace("'", "\\'") - s += "'$a'" - } else { - s += attr.arg - } - } + a.name + } + s += match a.kind { + .plain, .number { arg } + .string { "'$arg'" } + .comptime_define { 'if $arg' } } return s } pub fn (attrs []Attr) contains(str string) bool { - for a in attrs { - if a.name == str { - return true - } - } - return false + return attrs.any(it.name == str) } -pub fn (attrs []Attr) has_comptime_define() (bool, string) { +pub fn (attrs []Attr) find_comptime_define() ?string { for a in attrs { - if a.is_comptime_define { - return true, a.name + if a.kind == .comptime_define { + return a.name } } - return false, '' + return none } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 11d9706128..e25e71d325 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -6481,12 +6481,9 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { c.main_fn_decl_node = node } if node.return_type != ast.void_type { - for attr in node.attrs { - if attr.is_comptime_define { - c.error('only functions that do NOT return values can have `[if $attr.name]` tags', - node.pos) - break - } + if ct_name := node.attrs.find_comptime_define() { + c.error('only functions that do NOT return values can have `[if $ct_name]` tags', + node.pos) } } if node.is_method { diff --git a/vlib/v/gen/c/sql.v b/vlib/v/gen/c/sql.v index ca67d805d6..a8929e1d7b 100644 --- a/vlib/v/gen/c/sql.v +++ b/vlib/v/gen/c/sql.v @@ -1075,7 +1075,7 @@ fn (mut g Gen) parse_db_from_type_string(name string) SqlType { fn (mut g Gen) get_sql_field_type(field ast.StructField) ast.Type { mut typ := field.typ for attr in field.attrs { - if attr.name == 'sql' && !attr.is_string_arg && attr.arg != '' { + if attr.kind == .plain && attr.name == 'sql' && attr.arg != '' { if attr.arg.to_lower() == 'serial' { typ = ast.Type(-1) break @@ -1090,7 +1090,7 @@ fn (mut g Gen) get_table_name(table_expr ast.TypeNode) string { info := g.table.get_type_symbol(table_expr.typ).struct_info() mut tablename := util.strip_mod_name(g.table.get_type_symbol(table_expr.typ).name) for attr in info.attrs { - if attr.name == 'table' && attr.is_string_arg && attr.arg != '' { + if attr.kind == .string && attr.name == 'table' && attr.arg != '' { tablename = attr.arg break } @@ -1112,7 +1112,7 @@ fn (mut g Gen) get_struct_field(name string) ast.StructField { fn (mut g Gen) get_field_name(field ast.StructField) string { mut name := field.name for attr in field.attrs { - if attr.name == 'sql' && attr.is_string_arg && attr.arg != '' { + if attr.kind == .string && attr.name == 'sql' && attr.arg != '' { name = attr.arg break } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 096a0efc7a..6e165fb91d 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -177,7 +177,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { is_manualfree := p.is_manualfree || p.attrs.contains('manualfree') is_deprecated := p.attrs.contains('deprecated') is_direct_arr := p.attrs.contains('direct_array_access') - is_conditional, conditional_ctdefine := p.attrs.has_comptime_define() + conditional_ctdefine := p.attrs.find_comptime_define() or { '' } mut is_unsafe := p.attrs.contains('unsafe') is_keep_alive := p.attrs.contains('keep_args_alive') is_pub := p.tok.kind == .key_pub @@ -349,7 +349,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { is_unsafe: is_unsafe is_main: is_main is_test: is_test - is_conditional: is_conditional + is_conditional: conditional_ctdefine != '' is_keep_alive: is_keep_alive ctdefine: conditional_ctdefine no_body: no_body @@ -378,7 +378,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { is_unsafe: is_unsafe is_main: is_main is_test: is_test - is_conditional: is_conditional + is_conditional: conditional_ctdefine != '' is_keep_alive: is_keep_alive ctdefine: conditional_ctdefine no_body: no_body @@ -421,7 +421,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { is_variadic: is_variadic is_main: is_main is_test: is_test - is_conditional: is_conditional + is_conditional: conditional_ctdefine != '' is_keep_alive: is_keep_alive receiver: ast.StructField{ name: rec.name diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index e52644c80d..81c43bdb0b 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -439,30 +439,14 @@ pub fn (mut p Parser) parse_block_no_scope(is_top_level bool) []ast.Stmt { return stmts } -/* -fn (mut p Parser) next_with_comment() { - p.tok = p.peek_tok - p.peek_tok = p.scanner.scan() -} -*/ fn (mut p Parser) next() { p.prev_tok = p.tok p.tok = p.peek_tok p.peek_tok = p.scanner.scan() - /* - if p.tok.kind==.comment { - p.comments << ast.Comment{text:p.tok.lit, line_nr:p.tok.line_nr} - p.next() - } - */ } fn (mut p Parser) check(expected token.Kind) { p.name_error = false - // for p.tok.kind in [.line_comment, .mline_comment] { - // p.next() - // } - if _likely_(p.tok.kind == expected) { p.next() } else { @@ -1469,7 +1453,7 @@ fn (mut p Parser) attributes() { p.error_with_pos('duplicate attribute `$attr.name`', start_pos.extend(p.prev_tok.position())) return } - if attr.is_comptime_define { + if attr.kind == .comptime_define { if has_ctdefine { p.error_with_pos('only one `[if flag]` may be applied at a time `$attr.name`', start_pos.extend(p.prev_tok.position())) @@ -1496,61 +1480,55 @@ fn (mut p Parser) attributes() { } fn (mut p Parser) parse_attr() ast.Attr { + mut kind := ast.AttrKind.plain apos := p.prev_tok.position() if p.tok.kind == .key_unsafe { p.next() return ast.Attr{ name: 'unsafe' + kind: kind pos: apos.extend(p.tok.position()) } } - is_comptime_define := p.tok.kind == .key_if - if is_comptime_define { - p.next() - } mut name := '' + mut has_arg := false mut arg := '' - is_string := p.tok.kind == .string - mut is_string_arg := false - mut is_number_arg := false - if is_string { + if p.tok.kind == .key_if { + kind = .comptime_define + p.next() + p.check(.name) + name = p.prev_tok.lit + } else if p.tok.kind == .string { name = p.tok.lit + kind = .string p.next() } else { name = p.check_name() - if name == 'unsafe_fn' { - p.error_with_pos('[unsafe_fn] is obsolete, use `[unsafe]` instead', apos.extend(p.tok.position())) - return ast.Attr{} - } else if name == 'trusted_fn' { - p.error_with_pos('[trusted_fn] is obsolete, use `[trusted]` instead', apos.extend(p.tok.position())) - return ast.Attr{} - } else if name == 'ref_only' { - p.warn_with_pos('[ref_only] is deprecated, use [heap] instead', apos.extend(p.tok.position())) - name = 'heap' - } if p.tok.kind == .colon { + has_arg = true p.next() // `name: arg` if p.tok.kind == .name { + kind = .plain arg = p.check_name() } else if p.tok.kind == .number { + kind = .number arg = p.tok.lit - is_number_arg = true p.next() } else if p.tok.kind == .string { // `name: 'arg'` + kind = .string arg = p.tok.lit - is_string_arg = true p.next() + } else { + p.error('unexpected $p.tok, an argument is expected after `:`') } } } return ast.Attr{ name: name - is_string: is_string - is_comptime_define: is_comptime_define + has_arg: has_arg arg: arg - is_string_arg: is_string_arg - is_number_arg: is_number_arg + kind: kind pos: apos.extend(p.tok.position()) } } diff --git a/vlib/v/parser/tests/invalid_attribute_a.out b/vlib/v/parser/tests/invalid_attribute_a.out new file mode 100644 index 0000000000..7ae507c72c --- /dev/null +++ b/vlib/v/parser/tests/invalid_attribute_a.out @@ -0,0 +1,5 @@ +vlib/v/parser/tests/invalid_attribute_a.vv:1:9: error: unexpected token `]`, an argument is expected after `:` + 1 | [foobar:] + | ^ + 2 | fn my_fn_with_invalid_attr() { + 3 | } diff --git a/vlib/v/parser/tests/invalid_attribute_a.vv b/vlib/v/parser/tests/invalid_attribute_a.vv new file mode 100644 index 0000000000..971dc285e0 --- /dev/null +++ b/vlib/v/parser/tests/invalid_attribute_a.vv @@ -0,0 +1,3 @@ +[foobar:] +fn my_fn_with_invalid_attr() { +} diff --git a/vlib/v/parser/tests/invalid_attribute_b.out b/vlib/v/parser/tests/invalid_attribute_b.out new file mode 100644 index 0000000000..763de97ab0 --- /dev/null +++ b/vlib/v/parser/tests/invalid_attribute_b.out @@ -0,0 +1,5 @@ +vlib/v/parser/tests/invalid_attribute_b.vv:1:6: error: unexpected token `:`, an argument is expected after `:` + 1 | [foo::] + | ^ + 2 | fn my_fn_with_invalid_attr() { + 3 | } diff --git a/vlib/v/parser/tests/invalid_attribute_b.vv b/vlib/v/parser/tests/invalid_attribute_b.vv new file mode 100644 index 0000000000..d6af445673 --- /dev/null +++ b/vlib/v/parser/tests/invalid_attribute_b.vv @@ -0,0 +1,3 @@ +[foo::] +fn my_fn_with_invalid_attr() { +} diff --git a/vlib/v/parser/tests/invalid_attribute_c.out b/vlib/v/parser/tests/invalid_attribute_c.out new file mode 100644 index 0000000000..a30cb4254a --- /dev/null +++ b/vlib/v/parser/tests/invalid_attribute_c.out @@ -0,0 +1,5 @@ +vlib/v/parser/tests/invalid_attribute_c.vv:1:6: error: unexpected token `[`, an argument is expected after `:` + 1 | [bar:[] + | ^ + 2 | fn my_fn_with_invalid_attr() { + 3 | } diff --git a/vlib/v/parser/tests/invalid_attribute_c.vv b/vlib/v/parser/tests/invalid_attribute_c.vv new file mode 100644 index 0000000000..527076de3b --- /dev/null +++ b/vlib/v/parser/tests/invalid_attribute_c.vv @@ -0,0 +1,3 @@ +[bar:[] +fn my_fn_with_invalid_attr() { +} diff --git a/vlib/v/parser/tests/invalid_attribute_d.out b/vlib/v/parser/tests/invalid_attribute_d.out new file mode 100644 index 0000000000..3d05dc2bbd --- /dev/null +++ b/vlib/v/parser/tests/invalid_attribute_d.out @@ -0,0 +1,5 @@ +vlib/v/parser/tests/invalid_attribute_d.vv:1:9: error: unexpected token `}`, an argument is expected after `:` + 1 | [foobar:} + | ^ + 2 | fn my_fn_with_invalid_attr() { + 3 | } diff --git a/vlib/v/parser/tests/invalid_attribute_d.vv b/vlib/v/parser/tests/invalid_attribute_d.vv new file mode 100644 index 0000000000..0b7d2e2d57 --- /dev/null +++ b/vlib/v/parser/tests/invalid_attribute_d.vv @@ -0,0 +1,3 @@ +[foobar:} +fn my_fn_with_invalid_attr() { +}