1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

ast: use AttrKind (#9845)

This commit is contained in:
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
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
}

View File

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

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

View File

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

View File

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

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() {
}