mirror of
https://github.com/vlang/v.git
synced 2025-09-13 22:42:26 +03:00
v,breaking: add ability to read enum, fn, interface and sumtype attributes in compile-time, change builtin StructAttribute
to VAttribute
(#21149)
This commit is contained in:
parent
dbc4896aa1
commit
24af002249
13 changed files with 139 additions and 30 deletions
|
@ -151,7 +151,7 @@ pub enum AttributeKind {
|
|||
comptime_define // [if name]
|
||||
}
|
||||
|
||||
pub struct StructAttribute {
|
||||
pub struct VAttribute {
|
||||
pub:
|
||||
name string
|
||||
has_arg bool
|
||||
|
|
|
@ -51,10 +51,10 @@ fn test_mysql_orm() {
|
|||
name: 'id'
|
||||
typ: typeof[int]().idx
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'primary'
|
||||
},
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'sql'
|
||||
has_arg: true
|
||||
kind: .plain
|
||||
|
|
|
@ -55,13 +55,13 @@ fn test_pg_orm() {
|
|||
default_val: ''
|
||||
is_arr: false
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'primary'
|
||||
has_arg: false
|
||||
arg: ''
|
||||
kind: .plain
|
||||
},
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'sql'
|
||||
has_arg: true
|
||||
arg: 'serial'
|
||||
|
|
|
@ -36,10 +36,10 @@ fn test_sqlite_orm() {
|
|||
name: 'id'
|
||||
typ: typeof[int]().idx
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'primary'
|
||||
},
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'sql'
|
||||
has_arg: true
|
||||
kind: .plain
|
||||
|
|
|
@ -152,7 +152,7 @@ pub:
|
|||
typ int
|
||||
nullable bool
|
||||
default_val string
|
||||
attrs []StructAttribute
|
||||
attrs []VAttribute
|
||||
is_arr bool
|
||||
}
|
||||
|
||||
|
|
|
@ -156,10 +156,10 @@ fn test_orm_table_gen() {
|
|||
default_val: '10'
|
||||
nullable: true
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'primary'
|
||||
},
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'sql'
|
||||
has_arg: true
|
||||
arg: 'serial'
|
||||
|
@ -188,10 +188,10 @@ fn test_orm_table_gen() {
|
|||
nullable: true
|
||||
default_val: '10'
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'primary'
|
||||
},
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'sql'
|
||||
has_arg: true
|
||||
arg: 'serial'
|
||||
|
@ -220,10 +220,10 @@ fn test_orm_table_gen() {
|
|||
nullable: true
|
||||
default_val: '10'
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'primary'
|
||||
},
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'sql'
|
||||
has_arg: true
|
||||
arg: 'serial'
|
||||
|
@ -235,7 +235,7 @@ fn test_orm_table_gen() {
|
|||
name: 'test'
|
||||
typ: typeof[string]().idx
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'unique'
|
||||
},
|
||||
]
|
||||
|
@ -255,10 +255,10 @@ fn test_orm_table_gen() {
|
|||
nullable: true
|
||||
default_val: '10'
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'primary'
|
||||
},
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'sql'
|
||||
has_arg: true
|
||||
arg: 'serial'
|
||||
|
@ -271,7 +271,7 @@ fn test_orm_table_gen() {
|
|||
typ: typeof[string]().idx
|
||||
nullable: true
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'unique'
|
||||
has_arg: true
|
||||
arg: 'test'
|
||||
|
@ -285,7 +285,7 @@ fn test_orm_table_gen() {
|
|||
nullable: true
|
||||
default_val: '6754'
|
||||
attrs: [
|
||||
StructAttribute{
|
||||
VAttribute{
|
||||
name: 'unique'
|
||||
has_arg: true
|
||||
arg: 'test'
|
||||
|
|
|
@ -24,6 +24,7 @@ pub mut:
|
|||
redefined_fns []string
|
||||
fn_generic_types map[string][][]Type // for generic functions
|
||||
interfaces map[int]InterfaceDecl
|
||||
sumtypes map[int]SumTypeDecl
|
||||
cmod_prefix string // needed for ast.type_to_str(Type) while vfmt; contains `os.`
|
||||
is_fmt bool
|
||||
used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
||||
|
@ -222,6 +223,10 @@ pub fn (mut t Table) register_interface(idecl InterfaceDecl) {
|
|||
t.interfaces[idecl.typ] = idecl
|
||||
}
|
||||
|
||||
pub fn (mut t Table) register_sumtype(sumtyp SumTypeDecl) {
|
||||
t.sumtypes[sumtyp.typ] = sumtyp
|
||||
}
|
||||
|
||||
pub fn (mut t TypeSymbol) register_method(new_fn Fn) int {
|
||||
// returns a method index, stored in the ast.FnDecl
|
||||
// for faster lookup in the checker's fn_decl method
|
||||
|
@ -2519,3 +2524,27 @@ pub fn (t &Table) get_trace_fn_name(cur_fn FnDecl, node CallExpr) (string, strin
|
|||
}
|
||||
return hash_fn, fn_name
|
||||
}
|
||||
|
||||
// get_attrs retrieve the attribrutes from the type symbol
|
||||
pub fn (t &Table) get_attrs(sym TypeSymbol) []Attr {
|
||||
match sym.info {
|
||||
Enum {
|
||||
return t.enum_decls[sym.name].attrs
|
||||
}
|
||||
Struct {
|
||||
return sym.info.attrs
|
||||
}
|
||||
FnType {
|
||||
return sym.info.func.attrs
|
||||
}
|
||||
Interface {
|
||||
return unsafe { t.interfaces[sym.idx].attrs }
|
||||
}
|
||||
SumType {
|
||||
return unsafe { t.sumtypes[sym.idx].attrs }
|
||||
}
|
||||
else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -932,11 +932,11 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
|
|||
}
|
||||
}
|
||||
} else if node.kind == .attributes {
|
||||
if sym.info is ast.Struct {
|
||||
if sym.info.attrs.len > 0 {
|
||||
g.writeln('\tStructAttribute ${node.val_var} = {0};')
|
||||
}
|
||||
for attr in sym.info.attrs {
|
||||
attrs := g.table.get_attrs(sym)
|
||||
if attrs.len > 0 {
|
||||
g.writeln('\tVAttribute ${node.val_var} = {0};')
|
||||
|
||||
for attr in attrs {
|
||||
g.writeln('/* attribute ${i} */ {')
|
||||
g.writeln('\t${node.val_var}.name = _SLIT("${attr.name}");')
|
||||
g.writeln('\t${node.val_var}.has_arg = ${attr.has_arg};')
|
||||
|
|
|
@ -170,14 +170,14 @@ fn (mut g Gen) write_orm_create_table(node ast.SqlStmtLine, table_name string, c
|
|||
g.writeln('.is_arr = ${sym.kind == .array}, ')
|
||||
g.writeln('.nullable = ${field.typ.has_flag(.option)},')
|
||||
g.writeln('.default_val = (string){ .str = (byteptr) "${field.default_val}", .is_lit = 1 },')
|
||||
g.writeln('.attrs = new_array_from_c_array(${field.attrs.len}, ${field.attrs.len}, sizeof(StructAttribute),')
|
||||
g.writeln('.attrs = new_array_from_c_array(${field.attrs.len}, ${field.attrs.len}, sizeof(VAttribute),')
|
||||
g.indent++
|
||||
|
||||
if field.attrs.len > 0 {
|
||||
g.write('_MOV((StructAttribute[${field.attrs.len}]){')
|
||||
g.write('_MOV((VAttribute[${field.attrs.len}]){')
|
||||
g.indent++
|
||||
for attr in field.attrs {
|
||||
g.write('(StructAttribute){')
|
||||
g.write('(VAttribute){')
|
||||
g.indent++
|
||||
g.write(' .name = _SLIT("${attr.name}"),')
|
||||
g.write(' .has_arg = ${attr.has_arg},')
|
||||
|
|
|
@ -360,7 +360,7 @@ fn (mut p Parser) comptime_for() ast.ComptimeFor {
|
|||
'attributes' {
|
||||
p.scope.register(ast.Var{
|
||||
name: val_var
|
||||
typ: p.table.find_type_idx('StructAttribute')
|
||||
typ: p.table.find_type_idx('VAttribute')
|
||||
pos: var_pos
|
||||
})
|
||||
kind = .attributes
|
||||
|
|
|
@ -4409,7 +4409,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
|||
name_pos)
|
||||
return ast.SumTypeDecl{}
|
||||
}
|
||||
return ast.SumTypeDecl{
|
||||
node := ast.SumTypeDecl{
|
||||
name: name
|
||||
typ: typ
|
||||
is_pub: is_pub
|
||||
|
@ -4419,6 +4419,8 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
|||
pos: decl_pos
|
||||
name_pos: name_pos
|
||||
}
|
||||
p.table.register_sumtype(node)
|
||||
return node
|
||||
}
|
||||
// type MyType = int
|
||||
if generic_types.len > 0 {
|
||||
|
|
78
vlib/v/tests/comptime_attr_test.v
Normal file
78
vlib/v/tests/comptime_attr_test.v
Normal file
|
@ -0,0 +1,78 @@
|
|||
@[bar; foo]
|
||||
fn abc() {
|
||||
}
|
||||
|
||||
@[foo]
|
||||
struct Foo {
|
||||
}
|
||||
|
||||
@[bar]
|
||||
fn Foo.bar() {
|
||||
}
|
||||
|
||||
@[baz]
|
||||
enum EnumFoo {
|
||||
a
|
||||
b
|
||||
}
|
||||
|
||||
@[iface]
|
||||
interface IFoo {
|
||||
}
|
||||
|
||||
@[custom]
|
||||
type CustomType = EnumFoo | Foo
|
||||
|
||||
fn test_main() {
|
||||
mut c := 0
|
||||
$for f in abc.attributes {
|
||||
dump(f)
|
||||
assert f.name in ['foo', 'bar']
|
||||
c++
|
||||
}
|
||||
assert c == 2
|
||||
|
||||
$for f in Foo.attributes {
|
||||
dump(f)
|
||||
assert f.name == 'foo'
|
||||
c++
|
||||
}
|
||||
assert c == 3
|
||||
|
||||
a := Foo.bar
|
||||
$for f in a.attributes {
|
||||
dump(f)
|
||||
assert f.name == 'bar'
|
||||
c++
|
||||
}
|
||||
assert c == 4
|
||||
|
||||
b := abc
|
||||
$for f in b.attributes {
|
||||
dump(f)
|
||||
assert f.name in ['foo', 'bar']
|
||||
c++
|
||||
}
|
||||
assert c == 6
|
||||
|
||||
$for f in EnumFoo.attributes {
|
||||
dump(f)
|
||||
assert f.name == 'baz'
|
||||
c++
|
||||
}
|
||||
assert c == 7
|
||||
|
||||
$for f in IFoo.attributes {
|
||||
dump(f)
|
||||
assert f.name == 'iface'
|
||||
c++
|
||||
}
|
||||
assert c == 8
|
||||
|
||||
$for f in CustomType.attributes {
|
||||
dump(f)
|
||||
assert f.name == 'custom'
|
||||
c++
|
||||
}
|
||||
assert c == 9
|
||||
}
|
|
@ -42,7 +42,7 @@ fn test_main() {
|
|||
dump(f)
|
||||
dump(f.name)
|
||||
c += 1
|
||||
assert typeof(f).name == 'StructAttribute'
|
||||
assert typeof(f).name == 'VAttribute'
|
||||
}
|
||||
assert c == 8
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue