Skip to content

Commit

Permalink
v,breaking: add ability to read enum, fn, interface and sumtype attri…
Browse files Browse the repository at this point in the history
…butes in compile-time, change builtin `StructAttribute` to `VAttribute` (vlang#21149)
  • Loading branch information
felipensp authored Mar 31, 2024
1 parent dbc4896 commit 24af002
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 30 deletions.
2 changes: 1 addition & 1 deletion vlib/builtin/builtin.v
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ pub enum AttributeKind {
comptime_define // [if name]
}

pub struct StructAttribute {
pub struct VAttribute {
pub:
name string
has_arg bool
Expand Down
4 changes: 2 additions & 2 deletions vlib/db/mysql/mysql_orm_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions vlib/db/pg/pg_orm_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
4 changes: 2 additions & 2 deletions vlib/db/sqlite/sqlite_orm_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion vlib/orm/orm.v
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ pub:
typ int
nullable bool
default_val string
attrs []StructAttribute
attrs []VAttribute
is_arr bool
}

Expand Down
22 changes: 11 additions & 11 deletions vlib/orm/orm_fn_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -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'
Expand All @@ -235,7 +235,7 @@ fn test_orm_table_gen() {
name: 'test'
typ: typeof[string]().idx
attrs: [
StructAttribute{
VAttribute{
name: 'unique'
},
]
Expand All @@ -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'
Expand All @@ -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'
Expand All @@ -285,7 +285,7 @@ fn test_orm_table_gen() {
nullable: true
default_val: '6754'
attrs: [
StructAttribute{
VAttribute{
name: 'unique'
has_arg: true
arg: 'test'
Expand Down
29 changes: 29 additions & 0 deletions vlib/v/ast/table.v
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 []
}
}
}
10 changes: 5 additions & 5 deletions vlib/v/gen/c/comptime.v
Original file line number Diff line number Diff line change
Expand Up @@ -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};')
Expand Down
6 changes: 3 additions & 3 deletions vlib/v/gen/c/orm.v
Original file line number Diff line number Diff line change
Expand Up @@ -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},')
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/parser/comptime.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion vlib/v/parser/parser.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand Down
78 changes: 78 additions & 0 deletions vlib/v/tests/comptime_attr_test.v
Original file line number Diff line number Diff line change
@@ -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
}
2 changes: 1 addition & 1 deletion vlib/v/tests/comptime_dump_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit 24af002

Please sign in to comment.