mirror of
https://github.com/vlang/v.git
synced 2025-08-03 09:47:15 -04:00
vfmt: automate transition from the old [attribute]
to the new @[attribute]
syntax (#19912)
This commit is contained in:
parent
157d603e5c
commit
f7b9e4eafd
@ -707,12 +707,14 @@ fn (t Tree) attr(node ast.Attr) &Node {
|
||||
obj.add_terse('ast_type', t.string_node('Attr'))
|
||||
obj.add_terse('name', t.string_node(node.name))
|
||||
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('ct_expr', t.expr(node.ct_expr))
|
||||
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_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
|
||||
}
|
||||
|
||||
|
18
doc/docs.md
18
doc/docs.md
@ -2271,7 +2271,7 @@ It's also possible to define custom default values.
|
||||
|
||||
```v
|
||||
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
|
||||
// to have its default value, like 0 for numbers, or '' for strings,
|
||||
// and decoding will not fail.
|
||||
name string [required]
|
||||
name string @[required]
|
||||
age int
|
||||
// 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
|
||||
last_name string [json: lastName]
|
||||
last_name string @[json: lastName]
|
||||
}
|
||||
|
||||
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)
|
||||
@[table: 'customers']
|
||||
struct Customer {
|
||||
id int [primary; sql: serial] // a field named `id` of integer type must be the first field
|
||||
name string [nonull]
|
||||
id int @[primary; sql: serial] // a field named `id` of integer type must be the first field
|
||||
name string @[nonull]
|
||||
nr_orders int
|
||||
country string [nonull]
|
||||
country string @[nonull]
|
||||
}
|
||||
|
||||
db := sqlite.connect('customers.db')!
|
||||
@ -5385,7 +5385,7 @@ module abc
|
||||
pub struct Xyz {
|
||||
pub mut:
|
||||
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
|
||||
}
|
||||
```
|
||||
@ -7111,4 +7111,4 @@ Assignment Operators
|
||||
+= -= *= /= %=
|
||||
&= |= ^=
|
||||
>>= <<= >>>=
|
||||
```
|
||||
```
|
@ -11,7 +11,7 @@ struct App {
|
||||
@[table: 'benchmark']
|
||||
struct Task {
|
||||
mut:
|
||||
id u32 [primary; serial; sql: serial]
|
||||
id u32 @[primary; serial; sql: serial]
|
||||
title string
|
||||
status string
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ Create a new file `article.v`:
|
||||
module main
|
||||
|
||||
struct Article {
|
||||
id int [primary; sql: serial]
|
||||
id int @[primary; sql: serial]
|
||||
title string
|
||||
text string
|
||||
}
|
||||
@ -411,4 +411,4 @@ app is run you will see the articles created from the previous executions
|
||||
|
||||
To be continued...
|
||||
|
||||
For an example of a more sophisticated web app written in V, check out Vorum: https://github.com/vlang/vorum
|
||||
For an example of a more sophisticated web app written in V, check out Vorum: https://github.com/vlang/vorum
|
@ -21,10 +21,10 @@ enum JobTitle {
|
||||
struct Employee {
|
||||
mut:
|
||||
name string
|
||||
family string [json: '-'] // this field will be skipped
|
||||
family string @[json: '-'] // this field will be skipped
|
||||
age int
|
||||
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() {
|
||||
@ -43,4 +43,4 @@ fn main() {
|
||||
println('JSON encoding of employee y: ${ss}')
|
||||
assert ss == s
|
||||
}
|
||||
```
|
||||
```
|
@ -4,8 +4,8 @@ struct PostTag {
|
||||
id string
|
||||
parent ?&PostTag
|
||||
visibility string
|
||||
created_at string [json: 'createdAt']
|
||||
metadata string [raw]
|
||||
created_at string @[json: 'createdAt']
|
||||
metadata string @[raw]
|
||||
}
|
||||
|
||||
fn test_main() {
|
||||
|
@ -101,7 +101,7 @@ fn (db MockDB) last_id() int {
|
||||
@[table: 'foo']
|
||||
struct Foo {
|
||||
mut:
|
||||
id u64 [primary; sql: serial]
|
||||
id u64 @[primary; sql: serial]
|
||||
a string
|
||||
// b string [default: '"yes"']
|
||||
c ?string
|
||||
@ -222,7 +222,7 @@ fn test_option_struct_fields_and_none() {
|
||||
}
|
||||
|
||||
struct Bar {
|
||||
id u64 [primary; sql: serial]
|
||||
id u64 @[primary; sql: serial]
|
||||
name ?string
|
||||
age int
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ pub fn (t &Table) fn_type_source_signature(f &Fn) string {
|
||||
sig += ' ?'
|
||||
} else if f.return_type == rvoid_type {
|
||||
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)
|
||||
if f.return_type.has_flag(.option) {
|
||||
sig += ' ?${return_type_sym.name}'
|
||||
|
@ -17,10 +17,7 @@ pub fn (mut f Fmt) attrs(attrs []ast.Attr) {
|
||||
f.single_line_attrs(sorted_attrs[i..])
|
||||
break
|
||||
}
|
||||
if attr.has_at {
|
||||
f.write('@')
|
||||
}
|
||||
f.writeln('[${attr}]')
|
||||
f.writeln('@[${attr}]')
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,10 +35,7 @@ pub fn (mut f Fmt) single_line_attrs(attrs []ast.Attr, options AttrsOptions) {
|
||||
if options.same_line {
|
||||
f.write(' ')
|
||||
}
|
||||
if attrs[0].has_at {
|
||||
f.write('@')
|
||||
}
|
||||
f.write('[')
|
||||
f.write('@[')
|
||||
for i, attr in sorted_attrs {
|
||||
if i > 0 {
|
||||
f.write('; ')
|
||||
|
@ -30,7 +30,7 @@ fn test_fmt() {
|
||||
}
|
||||
vroot := os.dir(vexe)
|
||||
os.chdir(vroot) or {}
|
||||
basepath := os.join_path(vroot, '')
|
||||
basepath := vroot + '/'
|
||||
tmpfolder := os.temp_dir()
|
||||
diff_cmd := diff.find_working_diff_command() or { '' }
|
||||
mut fmt_bench := benchmark.new_benchmark()
|
||||
@ -40,6 +40,7 @@ fn test_fmt() {
|
||||
input_files << keep_input_files
|
||||
input_files << expected_input_files
|
||||
input_files = vtest.filter_vtest_only(input_files, basepath: vroot)
|
||||
input_files.sort()
|
||||
fmt_bench.set_total_expected_steps(input_files.len + 1)
|
||||
prepare_bin2v_file(mut fmt_bench)
|
||||
for istep, ipath in input_files {
|
||||
|
@ -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)
|
||||
attrs_len := inline_attrs_len(field.attrs)
|
||||
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
|
||||
if has_attrs && !has_at {
|
||||
f.write(strings.repeat(` `, field_align.max_type_len - field_types[i].len))
|
||||
|
26
vlib/v/fmt/tests/old_attrs_to_new_expected.vv
Normal file
26
vlib/v/fmt/tests/old_attrs_to_new_expected.vv
Normal 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]
|
||||
}
|
23
vlib/v/fmt/tests/old_attrs_to_new_input.vv
Normal file
23
vlib/v/fmt/tests/old_attrs_to_new_input.vv
Normal 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]
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
enum Color {
|
||||
red = 1 + 1 [json: 'Red']
|
||||
blue = 10 / 2 [json: 'Blue']
|
||||
red = 1 + 1 @[json: 'Red']
|
||||
blue = 10 / 2 @[json: 'Blue']
|
||||
}
|
||||
|
||||
fn test_main() {
|
||||
|
@ -21,7 +21,7 @@ pub fn (ar &Vec[T]) iter() Iter[T] {
|
||||
|
||||
pub struct Iter[T] {
|
||||
mut:
|
||||
v &Vec[T] [required]
|
||||
v &Vec[T] @[required]
|
||||
pos usize
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
struct Fns {
|
||||
f1 fn () [required]
|
||||
f2 fn () [attr1; required]
|
||||
f1 fn () @[required]
|
||||
f2 fn () @[attr1; required]
|
||||
}
|
||||
|
||||
fn func() {
|
||||
|
@ -360,8 +360,8 @@ fn test_struct_with_default_values_no_init() {
|
||||
}
|
||||
|
||||
struct FieldsWithOptionVoidReturnType {
|
||||
f fn () ! [required]
|
||||
g fn () ? [required]
|
||||
f fn () ! @[required]
|
||||
g fn () ? @[required]
|
||||
}
|
||||
|
||||
fn test_fields_anon_fn_with_option_void_return_type() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user