vfmt: automate transition from the old [attribute] to the new @[attribute] syntax (#19912)

This commit is contained in:
Delyan Angelov 2023-11-17 17:43:29 +02:00 committed by GitHub
parent 157d603e5c
commit f7b9e4eafd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 86 additions and 39 deletions

View File

@ -707,12 +707,14 @@ fn (t Tree) attr(node ast.Attr) &Node {
obj.add_terse('ast_type', t.string_node('Attr')) obj.add_terse('ast_type', t.string_node('Attr'))
obj.add_terse('name', t.string_node(node.name)) obj.add_terse('name', t.string_node(node.name))
obj.add_terse('has_arg', t.bool_node(node.has_arg)) obj.add_terse('has_arg', t.bool_node(node.has_arg))
obj.add_terse('arg', t.string_node(node.arg))
obj.add_terse('kind', t.enum_node(node.kind)) obj.add_terse('kind', t.enum_node(node.kind))
obj.add_terse('ct_expr', t.expr(node.ct_expr))
obj.add_terse('ct_opt', t.bool_node(node.ct_opt)) obj.add_terse('ct_opt', t.bool_node(node.ct_opt))
obj.add_terse('has_at', t.bool_node(node.has_at))
obj.add_terse('ct_expr', t.expr(node.ct_expr))
obj.add_terse('ct_evaled', t.bool_node(node.ct_evaled)) obj.add_terse('ct_evaled', t.bool_node(node.ct_evaled))
obj.add_terse('ct_skip', t.bool_node(node.ct_skip)) obj.add_terse('ct_skip', t.bool_node(node.ct_skip))
obj.add_terse('arg', t.string_node(node.arg)) obj.add('pos', t.pos(node.pos))
return obj return obj
} }

View File

@ -2271,7 +2271,7 @@ It's also possible to define custom default values.
```v ```v
struct Foo { struct Foo {
n int [required] n int @[required]
} }
``` ```
@ -4389,12 +4389,12 @@ struct User {
// If a field is not [required], but is missing, it will be assumed // If a field is not [required], but is missing, it will be assumed
// to have its default value, like 0 for numbers, or '' for strings, // to have its default value, like 0 for numbers, or '' for strings,
// and decoding will not fail. // and decoding will not fail.
name string [required] name string @[required]
age int age int
// Use the `skip` attribute to skip certain fields // Use the `skip` attribute to skip certain fields
foo Foo [skip] foo Foo @[skip]
// If the field name is different in JSON, it can be specified // If the field name is different in JSON, it can be specified
last_name string [json: lastName] last_name string @[json: lastName]
} }
data := '{ "name": "Frodo", "lastName": "Baggins", "age": 25 }' data := '{ "name": "Frodo", "lastName": "Baggins", "age": 25 }'
@ -4976,10 +4976,10 @@ import db.sqlite
// sets a custom table name. Default is struct name (case-sensitive) // sets a custom table name. Default is struct name (case-sensitive)
@[table: 'customers'] @[table: 'customers']
struct Customer { struct Customer {
id int [primary; sql: serial] // a field named `id` of integer type must be the first field id int @[primary; sql: serial] // a field named `id` of integer type must be the first field
name string [nonull] name string @[nonull]
nr_orders int nr_orders int
country string [nonull] country string @[nonull]
} }
db := sqlite.connect('customers.db')! db := sqlite.connect('customers.db')!
@ -5385,7 +5385,7 @@ module abc
pub struct Xyz { pub struct Xyz {
pub mut: pub mut:
a int a int
d int [deprecated: 'use Xyz.a instead'; deprecated_after: '2999-03-01'] d int @[deprecated: 'use Xyz.a instead'; deprecated_after: '2999-03-01']
// the tags above, will produce a notice, since the deprecation date is in the far future // the tags above, will produce a notice, since the deprecation date is in the far future
} }
``` ```

View File

@ -11,7 +11,7 @@ struct App {
@[table: 'benchmark'] @[table: 'benchmark']
struct Task { struct Task {
mut: mut:
id u32 [primary; serial; sql: serial] id u32 @[primary; serial; sql: serial]
title string title string
status string status string
} }

View File

@ -234,7 +234,7 @@ Create a new file `article.v`:
module main module main
struct Article { struct Article {
id int [primary; sql: serial] id int @[primary; sql: serial]
title string title string
text string text string
} }

View File

@ -21,10 +21,10 @@ enum JobTitle {
struct Employee { struct Employee {
mut: mut:
name string name string
family string [json: '-'] // this field will be skipped family string @[json: '-'] // this field will be skipped
age int age int
salary f32 salary f32
title JobTitle [json: 'ETitle'] // the key for this field will be 'ETitle', not 'title' title JobTitle @[json: 'ETitle'] // the key for this field will be 'ETitle', not 'title'
} }
fn main() { fn main() {

View File

@ -4,8 +4,8 @@ struct PostTag {
id string id string
parent ?&PostTag parent ?&PostTag
visibility string visibility string
created_at string [json: 'createdAt'] created_at string @[json: 'createdAt']
metadata string [raw] metadata string @[raw]
} }
fn test_main() { fn test_main() {

View File

@ -101,7 +101,7 @@ fn (db MockDB) last_id() int {
@[table: 'foo'] @[table: 'foo']
struct Foo { struct Foo {
mut: mut:
id u64 [primary; sql: serial] id u64 @[primary; sql: serial]
a string a string
// b string [default: '"yes"'] // b string [default: '"yes"']
c ?string c ?string
@ -222,7 +222,7 @@ fn test_option_struct_fields_and_none() {
} }
struct Bar { struct Bar {
id u64 [primary; sql: serial] id u64 @[primary; sql: serial]
name ?string name ?string
age int age int
} }

View File

@ -153,7 +153,7 @@ pub fn (t &Table) fn_type_source_signature(f &Fn) string {
sig += ' ?' sig += ' ?'
} else if f.return_type == rvoid_type { } else if f.return_type == rvoid_type {
sig += ' !' sig += ' !'
} else if f.return_type != void_type { } else if f.return_type != void_type && f.return_type != 0 {
return_type_sym := t.sym(f.return_type) return_type_sym := t.sym(f.return_type)
if f.return_type.has_flag(.option) { if f.return_type.has_flag(.option) {
sig += ' ?${return_type_sym.name}' sig += ' ?${return_type_sym.name}'

View File

@ -17,10 +17,7 @@ pub fn (mut f Fmt) attrs(attrs []ast.Attr) {
f.single_line_attrs(sorted_attrs[i..]) f.single_line_attrs(sorted_attrs[i..])
break break
} }
if attr.has_at { f.writeln('@[${attr}]')
f.write('@')
}
f.writeln('[${attr}]')
} }
} }
@ -38,10 +35,7 @@ pub fn (mut f Fmt) single_line_attrs(attrs []ast.Attr, options AttrsOptions) {
if options.same_line { if options.same_line {
f.write(' ') f.write(' ')
} }
if attrs[0].has_at { f.write('@[')
f.write('@')
}
f.write('[')
for i, attr in sorted_attrs { for i, attr in sorted_attrs {
if i > 0 { if i > 0 {
f.write('; ') f.write('; ')

View File

@ -30,7 +30,7 @@ fn test_fmt() {
} }
vroot := os.dir(vexe) vroot := os.dir(vexe)
os.chdir(vroot) or {} os.chdir(vroot) or {}
basepath := os.join_path(vroot, '') basepath := vroot + '/'
tmpfolder := os.temp_dir() tmpfolder := os.temp_dir()
diff_cmd := diff.find_working_diff_command() or { '' } diff_cmd := diff.find_working_diff_command() or { '' }
mut fmt_bench := benchmark.new_benchmark() mut fmt_bench := benchmark.new_benchmark()
@ -40,6 +40,7 @@ fn test_fmt() {
input_files << keep_input_files input_files << keep_input_files
input_files << expected_input_files input_files << expected_input_files
input_files = vtest.filter_vtest_only(input_files, basepath: vroot) input_files = vtest.filter_vtest_only(input_files, basepath: vroot)
input_files.sort()
fmt_bench.set_total_expected_steps(input_files.len + 1) fmt_bench.set_total_expected_steps(input_files.len + 1)
prepare_bin2v_file(mut fmt_bench) prepare_bin2v_file(mut fmt_bench)
for istep, ipath in input_files { for istep, ipath in input_files {

View File

@ -124,7 +124,8 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl, is_anon bool) {
f.mark_types_import_as_used(field.typ) f.mark_types_import_as_used(field.typ)
attrs_len := inline_attrs_len(field.attrs) attrs_len := inline_attrs_len(field.attrs)
has_attrs := field.attrs.len > 0 has_attrs := field.attrs.len > 0
has_at := if has_attrs { field.attrs[0].has_at } else { false } // has_at := if has_attrs { field.attrs[0].has_at } else { false }
has_at := true
// TODO: this will get removed in next stage // TODO: this will get removed in next stage
if has_attrs && !has_at { if has_attrs && !has_at {
f.write(strings.repeat(` `, field_align.max_type_len - field_types[i].len)) f.write(strings.repeat(` `, field_align.max_type_len - field_types[i].len))

View File

@ -0,0 +1,26 @@
module main
import os
@[export: 'Java_io_vlang_V_callStaticMethods']
@[tom: 'jerry']
@[direct_array_access; inline; unsafe]
fn heavily_tagged() {}
// a console attribute to force-open a console for easier diagnostics on windows
// also it's not safe to use
@[a_console; unsafe]
fn dangerous_console() {}
@[attribute_on_struct]
struct Generic[T] {
x T @[required]
}
struct Abc {
f fn () int = fn () int {
return 456 + os.args.len
} @[atr1; atr2]
//
g Generic[int] = Generic[int]{123} @[atr3; atr4]
}

View File

@ -0,0 +1,23 @@
module main
import os
[inline]
[export: 'Java_io_vlang_V_callStaticMethods']
[direct_array_access]
[unsafe]
[tom: 'jerry']
fn heavily_tagged() {}
[a_console] // a console attribute to force-open a console for easier diagnostics on windows
[unsafe] // also it's not safe to use
fn dangerous_console() {}
[attribute_on_struct]
struct Generic[T] {
x T [required]
}
struct Abc {
f fn () int [atr1] = fn () int { return 456 + os.args.len } @[atr2]
//
g Generic[int] [atr3] = Generic[int] { 123 } @[atr4]
}

View File

@ -1,6 +1,6 @@
enum Color { enum Color {
red = 1 + 1 [json: 'Red'] red = 1 + 1 @[json: 'Red']
blue = 10 / 2 [json: 'Blue'] blue = 10 / 2 @[json: 'Blue']
} }
fn test_main() { fn test_main() {

View File

@ -21,7 +21,7 @@ pub fn (ar &Vec[T]) iter() Iter[T] {
pub struct Iter[T] { pub struct Iter[T] {
mut: mut:
v &Vec[T] [required] v &Vec[T] @[required]
pos usize pos usize
} }

View File

@ -1,6 +1,6 @@
struct Fns { struct Fns {
f1 fn () [required] f1 fn () @[required]
f2 fn () [attr1; required] f2 fn () @[attr1; required]
} }
fn func() { fn func() {

View File

@ -360,8 +360,8 @@ fn test_struct_with_default_values_no_init() {
} }
struct FieldsWithOptionVoidReturnType { struct FieldsWithOptionVoidReturnType {
f fn () ! [required] f fn () ! @[required]
g fn () ? [required] g fn () ? @[required]
} }
fn test_fields_anon_fn_with_option_void_return_type() { fn test_fields_anon_fn_with_option_void_return_type() {