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:
Felipe Pena 2024-03-31 03:14:33 -03:00 committed by GitHub
parent dbc4896aa1
commit 24af002249
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 139 additions and 30 deletions

View file

@ -151,7 +151,7 @@ pub enum AttributeKind {
comptime_define // [if name] comptime_define // [if name]
} }
pub struct StructAttribute { pub struct VAttribute {
pub: pub:
name string name string
has_arg bool has_arg bool

View file

@ -51,10 +51,10 @@ fn test_mysql_orm() {
name: 'id' name: 'id'
typ: typeof[int]().idx typ: typeof[int]().idx
attrs: [ attrs: [
StructAttribute{ VAttribute{
name: 'primary' name: 'primary'
}, },
StructAttribute{ VAttribute{
name: 'sql' name: 'sql'
has_arg: true has_arg: true
kind: .plain kind: .plain

View file

@ -55,13 +55,13 @@ fn test_pg_orm() {
default_val: '' default_val: ''
is_arr: false is_arr: false
attrs: [ attrs: [
StructAttribute{ VAttribute{
name: 'primary' name: 'primary'
has_arg: false has_arg: false
arg: '' arg: ''
kind: .plain kind: .plain
}, },
StructAttribute{ VAttribute{
name: 'sql' name: 'sql'
has_arg: true has_arg: true
arg: 'serial' arg: 'serial'

View file

@ -36,10 +36,10 @@ fn test_sqlite_orm() {
name: 'id' name: 'id'
typ: typeof[int]().idx typ: typeof[int]().idx
attrs: [ attrs: [
StructAttribute{ VAttribute{
name: 'primary' name: 'primary'
}, },
StructAttribute{ VAttribute{
name: 'sql' name: 'sql'
has_arg: true has_arg: true
kind: .plain kind: .plain

View file

@ -152,7 +152,7 @@ pub:
typ int typ int
nullable bool nullable bool
default_val string default_val string
attrs []StructAttribute attrs []VAttribute
is_arr bool is_arr bool
} }

View file

@ -156,10 +156,10 @@ fn test_orm_table_gen() {
default_val: '10' default_val: '10'
nullable: true nullable: true
attrs: [ attrs: [
StructAttribute{ VAttribute{
name: 'primary' name: 'primary'
}, },
StructAttribute{ VAttribute{
name: 'sql' name: 'sql'
has_arg: true has_arg: true
arg: 'serial' arg: 'serial'
@ -188,10 +188,10 @@ fn test_orm_table_gen() {
nullable: true nullable: true
default_val: '10' default_val: '10'
attrs: [ attrs: [
StructAttribute{ VAttribute{
name: 'primary' name: 'primary'
}, },
StructAttribute{ VAttribute{
name: 'sql' name: 'sql'
has_arg: true has_arg: true
arg: 'serial' arg: 'serial'
@ -220,10 +220,10 @@ fn test_orm_table_gen() {
nullable: true nullable: true
default_val: '10' default_val: '10'
attrs: [ attrs: [
StructAttribute{ VAttribute{
name: 'primary' name: 'primary'
}, },
StructAttribute{ VAttribute{
name: 'sql' name: 'sql'
has_arg: true has_arg: true
arg: 'serial' arg: 'serial'
@ -235,7 +235,7 @@ fn test_orm_table_gen() {
name: 'test' name: 'test'
typ: typeof[string]().idx typ: typeof[string]().idx
attrs: [ attrs: [
StructAttribute{ VAttribute{
name: 'unique' name: 'unique'
}, },
] ]
@ -255,10 +255,10 @@ fn test_orm_table_gen() {
nullable: true nullable: true
default_val: '10' default_val: '10'
attrs: [ attrs: [
StructAttribute{ VAttribute{
name: 'primary' name: 'primary'
}, },
StructAttribute{ VAttribute{
name: 'sql' name: 'sql'
has_arg: true has_arg: true
arg: 'serial' arg: 'serial'
@ -271,7 +271,7 @@ fn test_orm_table_gen() {
typ: typeof[string]().idx typ: typeof[string]().idx
nullable: true nullable: true
attrs: [ attrs: [
StructAttribute{ VAttribute{
name: 'unique' name: 'unique'
has_arg: true has_arg: true
arg: 'test' arg: 'test'
@ -285,7 +285,7 @@ fn test_orm_table_gen() {
nullable: true nullable: true
default_val: '6754' default_val: '6754'
attrs: [ attrs: [
StructAttribute{ VAttribute{
name: 'unique' name: 'unique'
has_arg: true has_arg: true
arg: 'test' arg: 'test'

View file

@ -24,6 +24,7 @@ pub mut:
redefined_fns []string redefined_fns []string
fn_generic_types map[string][][]Type // for generic functions fn_generic_types map[string][][]Type // for generic functions
interfaces map[int]InterfaceDecl interfaces map[int]InterfaceDecl
sumtypes map[int]SumTypeDecl
cmod_prefix string // needed for ast.type_to_str(Type) while vfmt; contains `os.` cmod_prefix string // needed for ast.type_to_str(Type) while vfmt; contains `os.`
is_fmt bool is_fmt bool
used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true; 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 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 { pub fn (mut t TypeSymbol) register_method(new_fn Fn) int {
// returns a method index, stored in the ast.FnDecl // returns a method index, stored in the ast.FnDecl
// for faster lookup in the checker's fn_decl method // 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 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 []
}
}
}

View file

@ -932,11 +932,11 @@ fn (mut g Gen) comptime_for(node ast.ComptimeFor) {
} }
} }
} else if node.kind == .attributes { } else if node.kind == .attributes {
if sym.info is ast.Struct { attrs := g.table.get_attrs(sym)
if sym.info.attrs.len > 0 { if attrs.len > 0 {
g.writeln('\tStructAttribute ${node.val_var} = {0};') g.writeln('\tVAttribute ${node.val_var} = {0};')
}
for attr in sym.info.attrs { for attr in attrs {
g.writeln('/* attribute ${i} */ {') g.writeln('/* attribute ${i} */ {')
g.writeln('\t${node.val_var}.name = _SLIT("${attr.name}");') g.writeln('\t${node.val_var}.name = _SLIT("${attr.name}");')
g.writeln('\t${node.val_var}.has_arg = ${attr.has_arg};') g.writeln('\t${node.val_var}.has_arg = ${attr.has_arg};')

View file

@ -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('.is_arr = ${sym.kind == .array}, ')
g.writeln('.nullable = ${field.typ.has_flag(.option)},') g.writeln('.nullable = ${field.typ.has_flag(.option)},')
g.writeln('.default_val = (string){ .str = (byteptr) "${field.default_val}", .is_lit = 1 },') 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++ g.indent++
if field.attrs.len > 0 { if field.attrs.len > 0 {
g.write('_MOV((StructAttribute[${field.attrs.len}]){') g.write('_MOV((VAttribute[${field.attrs.len}]){')
g.indent++ g.indent++
for attr in field.attrs { for attr in field.attrs {
g.write('(StructAttribute){') g.write('(VAttribute){')
g.indent++ g.indent++
g.write(' .name = _SLIT("${attr.name}"),') g.write(' .name = _SLIT("${attr.name}"),')
g.write(' .has_arg = ${attr.has_arg},') g.write(' .has_arg = ${attr.has_arg},')

View file

@ -360,7 +360,7 @@ fn (mut p Parser) comptime_for() ast.ComptimeFor {
'attributes' { 'attributes' {
p.scope.register(ast.Var{ p.scope.register(ast.Var{
name: val_var name: val_var
typ: p.table.find_type_idx('StructAttribute') typ: p.table.find_type_idx('VAttribute')
pos: var_pos pos: var_pos
}) })
kind = .attributes kind = .attributes

View file

@ -4409,7 +4409,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
name_pos) name_pos)
return ast.SumTypeDecl{} return ast.SumTypeDecl{}
} }
return ast.SumTypeDecl{ node := ast.SumTypeDecl{
name: name name: name
typ: typ typ: typ
is_pub: is_pub is_pub: is_pub
@ -4419,6 +4419,8 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
pos: decl_pos pos: decl_pos
name_pos: name_pos name_pos: name_pos
} }
p.table.register_sumtype(node)
return node
} }
// type MyType = int // type MyType = int
if generic_types.len > 0 { if generic_types.len > 0 {

View 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
}

View file

@ -42,7 +42,7 @@ fn test_main() {
dump(f) dump(f)
dump(f.name) dump(f.name)
c += 1 c += 1
assert typeof(f).name == 'StructAttribute' assert typeof(f).name == 'VAttribute'
} }
assert c == 8 assert c == 8
} }