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:
parent
1b46f9aa02
commit
af8ef12990
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
5
vlib/v/parser/tests/invalid_attribute_a.out
Normal file
5
vlib/v/parser/tests/invalid_attribute_a.out
Normal 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 | }
|
3
vlib/v/parser/tests/invalid_attribute_a.vv
Normal file
3
vlib/v/parser/tests/invalid_attribute_a.vv
Normal file
@ -0,0 +1,3 @@
|
||||
[foobar:]
|
||||
fn my_fn_with_invalid_attr() {
|
||||
}
|
5
vlib/v/parser/tests/invalid_attribute_b.out
Normal file
5
vlib/v/parser/tests/invalid_attribute_b.out
Normal 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 | }
|
3
vlib/v/parser/tests/invalid_attribute_b.vv
Normal file
3
vlib/v/parser/tests/invalid_attribute_b.vv
Normal file
@ -0,0 +1,3 @@
|
||||
[foo::]
|
||||
fn my_fn_with_invalid_attr() {
|
||||
}
|
5
vlib/v/parser/tests/invalid_attribute_c.out
Normal file
5
vlib/v/parser/tests/invalid_attribute_c.out
Normal 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 | }
|
3
vlib/v/parser/tests/invalid_attribute_c.vv
Normal file
3
vlib/v/parser/tests/invalid_attribute_c.vv
Normal file
@ -0,0 +1,3 @@
|
||||
[bar:[]
|
||||
fn my_fn_with_invalid_attr() {
|
||||
}
|
5
vlib/v/parser/tests/invalid_attribute_d.out
Normal file
5
vlib/v/parser/tests/invalid_attribute_d.out
Normal 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 | }
|
3
vlib/v/parser/tests/invalid_attribute_d.vv
Normal file
3
vlib/v/parser/tests/invalid_attribute_d.vv
Normal file
@ -0,0 +1,3 @@
|
||||
[foobar:}
|
||||
fn my_fn_with_invalid_attr() {
|
||||
}
|
Loading…
Reference in New Issue
Block a user