ast: use `AttrKind` (#9845)

pull/9855/head
Enzo 2021-04-23 14:51:52 +02:00 committed by GitHub
parent 1b46f9aa02
commit af8ef12990
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 89 additions and 88 deletions

View File

@ -5,55 +5,49 @@ module ast
import v.token import v.token
pub enum AttrKind {
plain // [name]
string // ['name']
number // [123]
comptime_define // [if name]
}
// e.g. `[unsafe]` // e.g. `[unsafe]`
pub struct Attr { pub struct Attr {
pub: pub:
name string // [name] name string // [name]
is_string bool // ['name'] has_arg bool
is_comptime_define bool // [if name]
arg string // [name: arg] arg string // [name: arg]
is_string_arg bool // [name: 'arg'] kind AttrKind
is_number_arg bool // [name: 123]
pos token.Position pos token.Position
} }
// no square brackets // str returns the string representation without square brackets
pub fn (attr Attr) str() string { pub fn (a Attr) str() string {
mut s := '' mut s := ''
if attr.is_comptime_define { mut arg := if a.has_arg {
s += 'if ' s += '$a.name: '
} a.arg
if attr.is_string {
s += "'$attr.name'"
} else { } else {
s += attr.name a.name
if attr.arg.len > 0 {
s += ': '
if attr.is_string_arg {
a := attr.arg.replace("'", "\\'")
s += "'$a'"
} else {
s += attr.arg
}
} }
s += match a.kind {
.plain, .number { arg }
.string { "'$arg'" }
.comptime_define { 'if $arg' }
} }
return s return s
} }
pub fn (attrs []Attr) contains(str string) bool { pub fn (attrs []Attr) contains(str string) bool {
for a in attrs { return attrs.any(it.name == str)
if a.name == str {
return true
}
}
return false
} }
pub fn (attrs []Attr) has_comptime_define() (bool, string) { pub fn (attrs []Attr) find_comptime_define() ?string {
for a in attrs { for a in attrs {
if a.is_comptime_define { if a.kind == .comptime_define {
return true, a.name return a.name
} }
} }
return false, '' return none
} }

View File

@ -6481,12 +6481,9 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
c.main_fn_decl_node = node c.main_fn_decl_node = node
} }
if node.return_type != ast.void_type { if node.return_type != ast.void_type {
for attr in node.attrs { if ct_name := node.attrs.find_comptime_define() {
if attr.is_comptime_define { c.error('only functions that do NOT return values can have `[if $ct_name]` tags',
c.error('only functions that do NOT return values can have `[if $attr.name]` tags',
node.pos) node.pos)
break
}
} }
} }
if node.is_method { if node.is_method {

View File

@ -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 { fn (mut g Gen) get_sql_field_type(field ast.StructField) ast.Type {
mut typ := field.typ mut typ := field.typ
for attr in field.attrs { 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' { if attr.arg.to_lower() == 'serial' {
typ = ast.Type(-1) typ = ast.Type(-1)
break 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() 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) mut tablename := util.strip_mod_name(g.table.get_type_symbol(table_expr.typ).name)
for attr in info.attrs { 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 tablename = attr.arg
break 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 { fn (mut g Gen) get_field_name(field ast.StructField) string {
mut name := field.name mut name := field.name
for attr in field.attrs { 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 name = attr.arg
break break
} }

View File

@ -177,7 +177,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
is_manualfree := p.is_manualfree || p.attrs.contains('manualfree') is_manualfree := p.is_manualfree || p.attrs.contains('manualfree')
is_deprecated := p.attrs.contains('deprecated') is_deprecated := p.attrs.contains('deprecated')
is_direct_arr := p.attrs.contains('direct_array_access') 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') mut is_unsafe := p.attrs.contains('unsafe')
is_keep_alive := p.attrs.contains('keep_args_alive') is_keep_alive := p.attrs.contains('keep_args_alive')
is_pub := p.tok.kind == .key_pub is_pub := p.tok.kind == .key_pub
@ -349,7 +349,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
is_unsafe: is_unsafe is_unsafe: is_unsafe
is_main: is_main is_main: is_main
is_test: is_test is_test: is_test
is_conditional: is_conditional is_conditional: conditional_ctdefine != ''
is_keep_alive: is_keep_alive is_keep_alive: is_keep_alive
ctdefine: conditional_ctdefine ctdefine: conditional_ctdefine
no_body: no_body no_body: no_body
@ -378,7 +378,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
is_unsafe: is_unsafe is_unsafe: is_unsafe
is_main: is_main is_main: is_main
is_test: is_test is_test: is_test
is_conditional: is_conditional is_conditional: conditional_ctdefine != ''
is_keep_alive: is_keep_alive is_keep_alive: is_keep_alive
ctdefine: conditional_ctdefine ctdefine: conditional_ctdefine
no_body: no_body no_body: no_body
@ -421,7 +421,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
is_variadic: is_variadic is_variadic: is_variadic
is_main: is_main is_main: is_main
is_test: is_test is_test: is_test
is_conditional: is_conditional is_conditional: conditional_ctdefine != ''
is_keep_alive: is_keep_alive is_keep_alive: is_keep_alive
receiver: ast.StructField{ receiver: ast.StructField{
name: rec.name name: rec.name

View File

@ -439,30 +439,14 @@ pub fn (mut p Parser) parse_block_no_scope(is_top_level bool) []ast.Stmt {
return stmts 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() { fn (mut p Parser) next() {
p.prev_tok = p.tok p.prev_tok = p.tok
p.tok = p.peek_tok p.tok = p.peek_tok
p.peek_tok = p.scanner.scan() 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) { fn (mut p Parser) check(expected token.Kind) {
p.name_error = false p.name_error = false
// for p.tok.kind in [.line_comment, .mline_comment] {
// p.next()
// }
if _likely_(p.tok.kind == expected) { if _likely_(p.tok.kind == expected) {
p.next() p.next()
} else { } 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())) p.error_with_pos('duplicate attribute `$attr.name`', start_pos.extend(p.prev_tok.position()))
return return
} }
if attr.is_comptime_define { if attr.kind == .comptime_define {
if has_ctdefine { if has_ctdefine {
p.error_with_pos('only one `[if flag]` may be applied at a time `$attr.name`', p.error_with_pos('only one `[if flag]` may be applied at a time `$attr.name`',
start_pos.extend(p.prev_tok.position())) start_pos.extend(p.prev_tok.position()))
@ -1496,61 +1480,55 @@ fn (mut p Parser) attributes() {
} }
fn (mut p Parser) parse_attr() ast.Attr { fn (mut p Parser) parse_attr() ast.Attr {
mut kind := ast.AttrKind.plain
apos := p.prev_tok.position() apos := p.prev_tok.position()
if p.tok.kind == .key_unsafe { if p.tok.kind == .key_unsafe {
p.next() p.next()
return ast.Attr{ return ast.Attr{
name: 'unsafe' name: 'unsafe'
kind: kind
pos: apos.extend(p.tok.position()) pos: apos.extend(p.tok.position())
} }
} }
is_comptime_define := p.tok.kind == .key_if
if is_comptime_define {
p.next()
}
mut name := '' mut name := ''
mut has_arg := false
mut arg := '' mut arg := ''
is_string := p.tok.kind == .string if p.tok.kind == .key_if {
mut is_string_arg := false kind = .comptime_define
mut is_number_arg := false p.next()
if is_string { p.check(.name)
name = p.prev_tok.lit
} else if p.tok.kind == .string {
name = p.tok.lit name = p.tok.lit
kind = .string
p.next() p.next()
} else { } else {
name = p.check_name() 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 { if p.tok.kind == .colon {
has_arg = true
p.next() p.next()
// `name: arg` // `name: arg`
if p.tok.kind == .name { if p.tok.kind == .name {
kind = .plain
arg = p.check_name() arg = p.check_name()
} else if p.tok.kind == .number { } else if p.tok.kind == .number {
kind = .number
arg = p.tok.lit arg = p.tok.lit
is_number_arg = true
p.next() p.next()
} else if p.tok.kind == .string { // `name: 'arg'` } else if p.tok.kind == .string { // `name: 'arg'`
kind = .string
arg = p.tok.lit arg = p.tok.lit
is_string_arg = true
p.next() p.next()
} else {
p.error('unexpected $p.tok, an argument is expected after `:`')
} }
} }
} }
return ast.Attr{ return ast.Attr{
name: name name: name
is_string: is_string has_arg: has_arg
is_comptime_define: is_comptime_define
arg: arg arg: arg
is_string_arg: is_string_arg kind: kind
is_number_arg: is_number_arg
pos: apos.extend(p.tok.position()) pos: apos.extend(p.tok.position())
} }
} }

View File

@ -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 | }

View File

@ -0,0 +1,3 @@
[foobar:]
fn my_fn_with_invalid_attr() {
}

View File

@ -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 | }

View File

@ -0,0 +1,3 @@
[foo::]
fn my_fn_with_invalid_attr() {
}

View File

@ -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 | }

View File

@ -0,0 +1,3 @@
[bar:[]
fn my_fn_with_invalid_attr() {
}

View File

@ -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 | }

View File

@ -0,0 +1,3 @@
[foobar:}
fn my_fn_with_invalid_attr() {
}