1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

v.reflection: add type symbol info metadata (#17188)

This commit is contained in:
Felipe Pena 2023-02-08 16:30:44 -03:00 committed by GitHub
parent fbfdab9e2d
commit 47e8d967e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 462 additions and 126 deletions

View File

@ -237,10 +237,7 @@ mut:
out_fn_start_pos []int // for generating multiple .c files, stores locations of all fn positions in `out` string builder
static_modifier string // for parallel_cc
has_reflection bool
// reflection metadata initialization
reflection_funcs strings.Builder
reflection_others strings.Builder
has_reflection bool
reflection_strings &map[string]int
}
@ -314,8 +311,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref_ &pref.Preferences) (string
|| pref_.os in [.wasm32, .wasm32_emscripten])
static_modifier: if pref_.parallel_cc { 'static' } else { '' }
has_reflection: 'v.reflection' in table.modules
reflection_funcs: strings.new_builder(100)
reflection_others: strings.new_builder(100)
reflection_strings: &reflection_strings
}
@ -370,7 +365,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref_ &pref.Preferences) (string
global_g.embedded_data.write(g.embedded_data) or { panic(err) }
global_g.shared_types.write(g.shared_types) or { panic(err) }
global_g.shared_functions.write(g.channel_definitions) or { panic(err) }
global_g.reflection_funcs.write(g.reflection_funcs) or { panic(err) }
global_g.force_main_console = global_g.force_main_console || g.force_main_console
@ -679,8 +673,6 @@ fn cgen_process_one_file_cb(mut p pool.PoolProcessor, idx int, wid int) &Gen {
is_cc_msvc: global_g.is_cc_msvc
use_segfault_handler: global_g.use_segfault_handler
has_reflection: 'v.reflection' in global_g.table.modules
reflection_funcs: strings.new_builder(100)
reflection_others: strings.new_builder(100)
reflection_strings: global_g.reflection_strings
}
g.gen_file()

View File

@ -288,7 +288,6 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
}
fn_header := '${visibility_kw}${type_name} ${fn_attrs}${name}('
g.definitions.write_string(fn_header)
g.gen_reflection_function(node)
g.write(fn_header)
}
arg_start_pos := g.out.len

View File

@ -3,6 +3,8 @@ module c
import v.ast
import v.util
const cprefix = 'v__reflection__'
// reflection_string maps string to its idx
fn (mut g Gen) reflection_string(str string) int {
return unsafe {
@ -17,7 +19,7 @@ fn (mut g Gen) reflection_string(str string) int {
[inline]
fn (mut g Gen) gen_reflection_strings() {
for str, idx in g.reflection_strings {
g.reflection_others.write_string('\tv__reflection__add_string(_SLIT("${str}"), ${idx});\n')
g.writeln('\t${c.cprefix}add_string(_SLIT("${str}"), ${idx});')
}
}
@ -29,23 +31,21 @@ fn (g Gen) gen_empty_array(type_name string) string {
// gen_functionarg_array generates the code for functionarg argument
[inline]
fn (g Gen) gen_functionarg_array(type_name string, node ast.FnDecl) string {
fn (g Gen) gen_functionarg_array(type_name string, node ast.Fn) string {
if node.params.len == 0 {
return g.gen_empty_array(type_name)
}
mut out := 'new_array_from_c_array(${node.params.len},${node.params.len},sizeof(${type_name}),'
out += '_MOV((${type_name}[${node.params.len}]){'
for param in node.params {
out += '((${type_name}){.name=_SLIT("${param.name}"),.typ=${param.typ.idx()},}),'
}
out += node.params.map('((${type_name}){.name=_SLIT("${it.name}"),.typ=${int(it.typ)},.is_mut=${it.is_mut}})').join(',')
out += '}))'
return out
}
// gen_functionarg_array generates the code for functionarg argument
[inline]
fn (mut g Gen) gen_function_array(nodes []ast.FnDecl) string {
type_name := 'v__reflection__Function'
fn (mut g Gen) gen_function_array(nodes []ast.Fn) string {
type_name := '${c.cprefix}Function'
if nodes.len == 0 {
return g.gen_empty_array(type_name)
@ -53,108 +53,182 @@ fn (mut g Gen) gen_function_array(nodes []ast.FnDecl) string {
mut out := 'new_array_from_c_array(${nodes.len},${nodes.len},sizeof(${type_name}),'
out += '_MOV((${type_name}[${nodes.len}]){'
for method in nodes {
out += g.gen_reflection_fndecl(method)
out += ','
}
out += nodes.map(g.gen_reflection_fn(it)).join(',')
out += '}))'
return out
}
// gen_reflection_enum_fields generates C code for enum fields
// gen_reflection_fn generates C code for Function struct
[inline]
fn (g Gen) gen_reflection_enum_fields(fields []ast.EnumField) string {
if fields.len == 0 {
return g.gen_empty_array('v__reflection__EnumField')
}
mut out := 'new_array_from_c_array(${fields.len},${fields.len},sizeof(v__reflection__EnumField),'
out += '_MOV((v__reflection__EnumField[${fields.len}]){'
for field in fields {
out += '((v__reflection__EnumField){.name=_SLIT("${field.name}")}),'
}
out += '}))'
return out
}
// gen_reflection_fndecl generates C code for function declaration
[inline]
fn (mut g Gen) gen_reflection_fndecl(node ast.FnDecl) string {
mut arg_str := '((v__reflection__Function){'
fn (mut g Gen) gen_reflection_fn(node ast.Fn) string {
mut arg_str := '((${c.cprefix}Function){'
v_name := node.name.all_after_last('.')
arg_str += '.mod_name=_SLIT("${node.mod}"),'
arg_str += '.name=_SLIT("${v_name}"),'
arg_str += '.args=${g.gen_functionarg_array('v__reflection__FunctionArg', node)},'
arg_str += '.args=${g.gen_functionarg_array(c.cprefix + 'FunctionArg', node)},'
arg_str += '.file_idx=${g.reflection_string(util.cescaped_path(node.file))},'
arg_str += '.line_start=${node.pos.line_nr},'
arg_str += '.line_end=${node.pos.last_line},'
arg_str += '.is_variadic=${node.is_variadic},'
arg_str += '.return_typ=${node.return_type.idx()},'
arg_str += '.receiver_typ=${node.receiver.typ.idx()}'
arg_str += '.return_typ=${int(node.return_type)},'
arg_str += '.receiver_typ=${int(node.receiver_type)},'
arg_str += '.is_pub=${node.is_pub}'
arg_str += '})'
return arg_str
}
// gen_reflection_sym generates C code for TypeSymbol struct
[inline]
fn (g Gen) gen_reflection_sym(tsym ast.TypeSymbol) string {
fn (mut g Gen) gen_reflection_sym(tsym ast.TypeSymbol) string {
kind_name := if tsym.kind in [.none_, .struct_, .enum_, .interface_] {
tsym.kind.str() + '_'
} else {
tsym.kind.str()
}
return '(v__reflection__TypeSymbol){.name=_SLIT("${tsym.name}"),.idx=${tsym.idx},.parent_idx=${tsym.parent_idx},.language=_SLIT("${tsym.language}"),.kind=v__ast__Kind__${kind_name}}'
info := g.gen_reflection_sym_info(tsym)
methods := g.gen_function_array(tsym.methods)
return '(${c.cprefix}TypeSymbol){.name=_SLIT("${tsym.name}"),.idx=${tsym.idx},.parent_idx=${tsym.parent_idx},.language=${c.cprefix}VLanguage__${tsym.language},.kind=${c.cprefix}VKind__${kind_name},.info=${info},.methods=${methods}}'
}
// gen_reflection_function generates C code for reflection function metadata
// gen_attrs_array generates C code for []Attr
[inline]
fn (mut g Gen) gen_reflection_function(node ast.FnDecl) {
if !g.has_reflection {
return
fn (g Gen) gen_attrs_array(attrs []ast.Attr) string {
if attrs.len == 0 {
return g.gen_empty_array('string')
}
mut out := 'new_array_from_c_array(${attrs.len},${attrs.len},sizeof(string),'
out += '_MOV((string[${attrs.len}]){'
out += attrs.map(if it.has_arg { '_SLIT("${it.name}=${it.arg}")' } else { '_SLIT("${it.name}")' }).join(',')
out += '}))'
return out
}
// gen_fields_array generates C code for []StructField
[inline]
fn (g Gen) gen_fields_array(fields []ast.StructField) string {
if fields.len == 0 {
return g.gen_empty_array('${c.cprefix}StructField')
}
mut out := 'new_array_from_c_array(${fields.len},${fields.len},sizeof(${c.cprefix}StructField),'
out += '_MOV((${c.cprefix}StructField[${fields.len}]){'
out += fields.map('((${c.cprefix}StructField){.name=_SLIT("${it.name}"),.typ=${int(it.typ)},.attrs=${g.gen_attrs_array(it.attrs)},.is_pub=${it.is_pub},.is_mut=${it.is_mut}})').join(',')
out += '}))'
return out
}
// gen_type_array generates C code for []Type
[inline]
fn (g Gen) gen_type_array(types []ast.Type) string {
if types.len == 0 {
return g.gen_empty_array('int')
}
return 'new_array_from_c_array(${types.len},${types.len},sizeof(int),_MOV((int[${types.len}]){${types.map(int(it).str()).join(',')}}))'
}
// gen_string_array generates C code for []string
[inline]
fn (g Gen) gen_string_array(strs []string) string {
if strs.len == 0 {
return g.gen_empty_array('string')
}
items := strs.map('_SLIT("${it}")').join(',')
return 'new_array_from_c_array(${strs.len},${strs.len},sizeof(string),_MOV((string[${strs.len}]){${items}}))'
}
// gen_reflection_sym_info generates C code for TypeSymbol's info sum type
[inline]
fn (mut g Gen) gen_reflection_sym_info(tsym ast.TypeSymbol) string {
match tsym.kind {
.array {
info := tsym.info as ast.Array
s := 'ADDR(${c.cprefix}Array,(((${c.cprefix}Array){.nr_dims=${info.nr_dims},.elem_type=${int(info.elem_type)}})))'
return '(${c.cprefix}TypeInfo){._${c.cprefix}Array = memdup(${s},sizeof(${c.cprefix}Array)),._typ=${g.table.find_type_idx('v.reflection.Array')}}'
}
.array_fixed {
info := tsym.info as ast.ArrayFixed
s := 'ADDR(${c.cprefix}ArrayFixed,(((${c.cprefix}ArrayFixed){.size=${info.size},.elem_type=${int(info.elem_type)}})))'
return '(${c.cprefix}TypeInfo){._${c.cprefix}ArrayFixed=memdup(${s},sizeof(${c.cprefix}ArrayFixed)),._typ=${g.table.find_type_idx('v.reflection.ArrayFixed')}}'
}
.map {
info := tsym.info as ast.Map
s := 'ADDR(${c.cprefix}Map,(((${c.cprefix}Map){.key_type=${int(info.key_type)},.value_type=${int(info.value_type)}})))'
return '(${c.cprefix}TypeInfo){._${c.cprefix}Map=memdup(${s},sizeof(${c.cprefix}Map)),._typ=${g.table.find_type_idx('v.reflection.Map')}}'
}
.sum_type {
info := tsym.info as ast.SumType
s := 'ADDR(${c.cprefix}SumType,(((${c.cprefix}SumType){.parent_idx=${info.parent_type.idx()},.variants=${g.gen_type_array(info.variants)}})))'
return '(${c.cprefix}TypeInfo){._${c.cprefix}SumType=memdup(${s},sizeof(${c.cprefix}SumType)),._typ=${g.table.find_type_idx('v.reflection.SumType')}}'
}
.struct_ {
info := tsym.info as ast.Struct
attrs := g.gen_attrs_array(info.attrs)
fields := g.gen_fields_array(info.fields)
s := 'ADDR(${c.cprefix}Struct,(((${c.cprefix}Struct){.parent_idx=${(tsym.info as ast.Struct).parent_type.idx()},.attrs=${attrs},.fields=${fields}})))'
return '(${c.cprefix}TypeInfo){._${c.cprefix}Struct=memdup(${s},sizeof(${c.cprefix}Struct)),._typ=${g.table.find_type_idx('v.reflection.Struct')}}'
}
.enum_ {
info := tsym.info as ast.Enum
vals := g.gen_string_array(info.vals)
s := 'ADDR(${c.cprefix}Enum,(((${c.cprefix}Enum){.vals=${vals},.is_flag=${info.is_flag}})))'
return '(${c.cprefix}TypeInfo){._${c.cprefix}Enum=memdup(${s},sizeof(${c.cprefix}Enum)),._typ=${g.table.find_type_idx('v.reflection.Enum')}}'
}
.function {
info := tsym.info as ast.FnType
s := 'ADDR(${c.cprefix}Function,${g.gen_reflection_fn(info.func)})'
return '(${c.cprefix}TypeInfo){._${c.cprefix}Function=memdup(${s},sizeof(${c.cprefix}Function)),._typ=${g.table.find_type_idx('v.reflection.Function')}}'
}
.interface_ {
name := tsym.name.all_after_last('.')
info := tsym.info as ast.Interface
methods := g.gen_function_array(info.methods)
fields := g.gen_fields_array(info.fields)
s := 'ADDR(${c.cprefix}Interface,(((${c.cprefix}Interface){.name=_SLIT("${name}"),.methods=${methods},.fields=${fields},.is_generic=${info.is_generic}})))'
return '(${c.cprefix}TypeInfo){._${c.cprefix}Interface=memdup(${s},sizeof(${c.cprefix}Interface)),._typ=${g.table.find_type_idx('v.reflection.Interface')}}'
}
.alias {
info := tsym.info as ast.Alias
s := 'ADDR(${c.cprefix}Alias,(((${c.cprefix}Alias){.parent_idx=${info.parent_type.idx()},.language=${c.cprefix}VLanguage__${info.language.str()}})))'
return '(${c.cprefix}TypeInfo){._${c.cprefix}Alias=memdup(${s},sizeof(${c.cprefix}Alias)),._typ=${g.table.find_type_idx('v.reflection.Alias')}}'
}
.multi_return {
info := tsym.info as ast.MultiReturn
s := 'ADDR(${c.cprefix}MultiReturn,(((${c.cprefix}MultiReturn){.types=${g.gen_type_array(info.types)}})))'
return '(${c.cprefix}TypeInfo){._${c.cprefix}MultiReturn=memdup(${s},sizeof(${c.cprefix}MultiReturn)),._typ=${g.table.find_type_idx('v.reflection.MultiReturn')}}'
}
else {
s := 'ADDR(${c.cprefix}None,(((${c.cprefix}None){.parent_idx=${tsym.parent_idx},})))'
return '(${c.cprefix}TypeInfo){._${c.cprefix}None=memdup(${s},sizeof(${c.cprefix}None)),._typ=${g.table.find_type_idx('v.reflection.None')}}'
}
}
func_struct := g.gen_reflection_fndecl(node)
g.reflection_funcs.write_string('\tv__reflection__add_func(${func_struct});\n')
}
// gen_reflection_data generates code to initilized V reflection metadata
fn (mut g Gen) gen_reflection_data() {
// modules declaration
for mod_name in g.table.modules {
g.reflection_others.write_string('\tv__reflection__add_module(_SLIT("${mod_name}"));\n')
}
// enum declaration
for full_name, enum_ in g.table.enum_decls {
name := full_name.all_after_last('.')
fields := g.gen_reflection_enum_fields(enum_.fields)
g.reflection_others.write_string('\tv__reflection__add_enum((v__reflection__Enum){.name=_SLIT("${name}"),.is_pub=${enum_.is_pub},.is_flag=${enum_.is_flag},.typ=${enum_.typ.idx()},.line_start=${enum_.pos.line_nr},.line_end=${enum_.pos.last_line},.fields=${fields}});\n')
}
// types declaration
for full_name, idx in g.table.type_idxs {
tsym := g.table.sym_by_idx(idx)
name := full_name.all_after_last('.')
sym := g.gen_reflection_sym(tsym)
g.reflection_others.write_string('\tv__reflection__add_type((v__reflection__Type){.name=_SLIT("${name}"),.idx=${idx},.sym=${sym}});\n')
}
// interface declaration
for _, idecl in g.table.interfaces {
name := idecl.name.all_after_last('.')
methods := g.gen_function_array(idecl.methods)
g.reflection_others.write_string('\tv__reflection__add_interface((v__reflection__Interface){.name=_SLIT("${name}"),.typ=${idecl.typ.idx()},.is_pub=${idecl.is_pub},.methods=${methods}});\n')
g.writeln('\t${c.cprefix}add_module(_SLIT("${mod_name}"));')
}
// type symbols declaration
for _, tsym in g.table.type_symbols {
sym := g.gen_reflection_sym(tsym)
g.reflection_others.write_string('\tv__reflection__add_type_symbol(${sym});\n')
g.writeln('\t${c.cprefix}add_type_symbol(${sym});')
}
// types declaration
for full_name, idx in g.table.type_idxs {
name := full_name.all_after_last('.')
g.writeln('\t${c.cprefix}add_type((${c.cprefix}Type){.name=_SLIT("${name}"),.idx=${idx}});')
}
// func declaration (methods come from struct methods)
for _, fn_ in g.table.fns {
if fn_.no_body || fn_.is_method || fn_.language != .v {
continue
}
func := g.gen_reflection_fn(fn_)
g.writeln('\t${c.cprefix}add_func(${func});')
}
g.gen_reflection_strings()
// funcs meta info filling
g.writeln(g.reflection_funcs.str())
// others meta info filling
g.writeln(g.reflection_others.str())
}

View File

@ -1,7 +1,7 @@
[has_globals]
module reflection
import v.ast
import arrays
__global g_reflection = Reflection{}
@ -17,37 +17,187 @@ pub mut:
strings map[int]string
}
pub struct Interface {
pub:
name string // interface name
typ int // type idx
is_pub bool // is pub?
methods []Function // methods
pub enum VLanguage {
v
c
js
amd64 // aka x86_64
i386
arm64 // 64-bit arm
arm32 // 32-bit arm
rv64 // 64-bit risc-v
rv32 // 32-bit risc-v
wasm32
}
pub struct EnumField {
type VType = u32
// max of 8
pub enum VTypeFlag {
option
result
variadic
generic
shared_f
atomic_f
}
pub enum VKind {
placeholder
void
voidptr
byteptr
charptr
i8
i16
int
i64
isize
u8
u16
u32
u64
usize
f32
f64
char
rune
bool
none_
string
array
array_fixed
map
chan
any
struct_
generic_inst
multi_return
sum_type
alias
enum_
function
interface_
float_literal
int_literal
aggregate
thread
}
// return true if `flag` is set on `t`
[inline]
pub fn (t VType) has_flag(flag VTypeFlag) bool {
return int(t) & (1 << (int(flag) + 24)) > 0
}
[inline]
pub fn (t VType) idx() int {
return u16(t) & 0xffff
}
pub fn (t VType) str() string {
return 'VType(0x${t.hex()} = ${u32(t)})'
}
// return true if `t` is a pointer (nr_muls>0)
[inline]
pub fn (t VType) is_ptr() bool {
// any normal pointer, i.e. &Type, &&Type etc;
// Note: voidptr, charptr and byteptr are NOT included!
return (int(t) >> 16) & 0xff > 0
}
pub struct ArrayFixed {
pub:
name string // field name
size int // array size
elem_type int // elem type idx
}
pub struct Array {
pub:
nr_dims int // nr of dimensions
elem_type int // elem type idx
}
pub struct Alias {
pub:
parent_idx int // parent type idx
language VLanguage // language
}
pub struct Interface {
pub:
name string // interface name
methods []Function // methods
fields []StructField // fields
is_generic bool // is generic?
}
pub struct None {
pub:
parent_idx int
}
pub struct Enum {
pub:
name string // enum name
is_pub bool // is pub?
is_flag bool // is flag?
typ int // type idx
line_start int // decl start line
line_end int // decl end line
fields []EnumField // enum fields
vals []string // enum values
is_flag bool // is flag?
}
pub struct StructField {
pub:
name string // field name
typ VType // type
attrs []string // field attrs
is_pub bool // is pub?
is_mut bool // is mut?
}
pub struct Struct {
pub:
parent_idx int // parent type
attrs []string // struct attrs
fields []StructField // fields
}
pub struct SumType {
pub:
parent_idx int // parent type
variants []VType // variant type
}
pub struct Map {
pub:
key_type VType // key type
value_type VType // value type
}
pub struct MultiReturn {
pub:
types []VType // types
}
pub type TypeInfo = Alias
| Array
| ArrayFixed
| Enum
| Function
| Interface
| Map
| MultiReturn
| None
| Struct
| SumType
pub struct TypeSymbol {
pub:
name string // symbol name
idx int // symbol idx
parent_idx int // symbol parent idx
language string // language
kind ast.Kind // kind
name string // symbol name
idx int // symbol idx
parent_idx int // symbol parent idx
language VLanguage // language
kind VKind // kind
info TypeInfo // info
methods []Function // methods
}
pub struct Type {
@ -64,8 +214,9 @@ pub:
pub struct FunctionArg {
pub:
name string // argument name
typ int // argument type idx
name string // argument name
typ VType // argument type idx
is_mut bool // is mut?
}
pub struct Function {
@ -73,12 +224,13 @@ pub:
mod_name string // module name
name string // function/method name
args []FunctionArg // function/method args
file_idx int // source file name
line_start int // decl start line
line_end int // decl end line
is_variadic bool // is variadic?
return_typ int // return type idx
receiver_typ int // receiver type idx (is a method)
file_idx int // source file name
line_start int // decl start line
line_end int // decl end line
is_variadic bool // is variadic?
return_typ VType // return type idx
receiver_typ VType // receiver type idx (is a method)
is_pub bool // is pub?
}
// API module
@ -99,7 +251,14 @@ pub fn get_modules() []Module {
// get_functions returns the functions built with V source
pub fn get_funcs() []Function {
return g_reflection.funcs
mut out := g_reflection.funcs.clone()
out << arrays.flatten[Function](get_types().map(it.sym.methods).filter(it.len))
return out
}
pub fn get_structs() []Type {
struct_idxs := g_reflection.type_symbols.filter(it.kind == .struct_).map(it.idx)
return g_reflection.types.filter(it.idx in struct_idxs)
}
// get_types returns the registered types
@ -108,8 +267,9 @@ pub fn get_types() []Type {
}
// get_enums returns the registered enums
pub fn get_enums() []Enum {
return g_reflection.enums
pub fn get_enums() []Type {
enum_idxs := g_reflection.type_symbols.filter(it.kind == .enum_).map(it.idx)
return g_reflection.types.filter(it.idx in enum_idxs)
}
// get_aliases returns the registered aliases
@ -120,7 +280,8 @@ pub fn get_aliases() []Type {
// get_interfaces returns the registered aliases
pub fn get_interfaces() []Interface {
return g_reflection.interfaces
iface_idxs := g_reflection.type_symbols.filter(it.kind == .interface_).map(it.idx)
return g_reflection.types.filter(it.idx in iface_idxs).map(it.sym.info as Interface)
}
// get_sum_types returns the registered sum types
@ -170,7 +331,10 @@ fn add_func(func Function) {
[markused]
fn add_type(type_ Type) {
g_reflection.types << type_
g_reflection.types << Type{
...type_
sym: g_reflection.type_symbols.filter(it.idx == type_.idx).first()
}
}
[markused]
@ -178,16 +342,6 @@ fn add_type_symbol(typesymbol TypeSymbol) {
g_reflection.type_symbols << typesymbol
}
[markused]
fn add_enum(enum_ Enum) {
g_reflection.enums << enum_
}
[markused]
fn add_interface(interface_ Interface) {
g_reflection.interfaces << interface_
}
[markused]
fn add_string(str string, idx int) {
g_reflection.strings[idx] = str

View File

@ -0,0 +1,117 @@
import v.reflection
[test_struct]
struct Test {
m map[int]string [test]
n ?string [test2; test3]
}
enum Flags {
foo
bar
}
type MySum = f64 | int
type MyAlias = int
fn foo() ?string {
return ''
}
fn bar() !string {
return ''
}
fn baz() (int, f64, string) {
return 1, 2.0, 'foo'
}
fn test_flag_option() {
funcs := reflection.get_funcs().filter(it.name == 'foo')
assert funcs[0].return_typ.has_flag(.option)
}
fn test_flag_result() {
funcs := reflection.get_funcs().filter(it.name == 'bar')
assert funcs[0].return_typ.has_flag(.result)
}
fn test_array_sym() {
var := [1, 2]
typ := reflection.type_of(var)
assert typ.sym.kind == .array
assert typ.sym.language == .v
assert typ.sym.methods.len > 0
assert typ.sym.methods.filter(it.name == 'reduce').len > 0
assert typ.sym.name == '[]int'
assert (typ.sym.info as reflection.Array).nr_dims == 1
assert (typ.sym.info as reflection.Array).elem_type == typeof[int]().idx
}
fn test_sumtype_sym() {
var := MySum(1)
typ := reflection.type_of(var)
assert typ.sym.kind == .sum_type
assert (typ.sym.info as reflection.SumType).variants[0] == typeof[f64]().idx
assert (typ.sym.info as reflection.SumType).variants[1] == typeof[int]().idx
}
fn test_alias_sym() {
var := MyAlias(1)
typ := reflection.type_of(var)
assert typ.sym.kind == .alias
assert typ.sym.language == .v
assert (typ.sym.info as reflection.Alias).parent_idx == typeof[int]().idx
assert typ.sym.methods.len == 0
}
fn test_multi_return_sym() {
func := reflection.get_funcs().filter(it.name == 'baz')[0]
assert func.name == 'baz'
assert func.args.len == 0
assert func.is_variadic == false
assert func.return_typ.has_flag(.option) == false
assert func.return_typ.has_flag(.result) == false
assert func.return_typ.has_flag(.shared_f) == false
assert func.receiver_typ == 0
assert func.is_pub == false
typ := reflection.get_type(func.return_typ)?
assert typ.name == '(int, f64, string)'
assert typ.sym.language == .v
assert typ.sym.kind == .multi_return
}
fn test_enum_sym() {
var := reflection.type_of(Flags.foo)
assert var.sym.name == 'main.Flags'
assert var.sym.parent_idx == 0
assert var.sym.kind == .enum_
assert var.sym.language == .v
assert (var.sym.info as reflection.Enum).vals == ['foo', 'bar']
}
fn test_struct_sym() {
var := reflection.type_of(Test{})
assert var.sym.kind == .struct_
assert (var.sym.info as reflection.Struct).attrs.len == 1
assert (var.sym.info as reflection.Struct).attrs == ['test_struct']
field := (var.sym.info as reflection.Struct).fields[0]
field_typ := field.typ
field_sym := reflection.get_type(field_typ.idx())?
assert field_sym.name == 'map[int]string'
assert field_sym.sym.kind == .map
assert (field_sym.sym.info as reflection.Map).key_type.idx() == typeof[int]().idx
assert (field_sym.sym.info as reflection.Map).value_type.idx() == typeof[string]().idx
assert field.attrs.len == 1
field2 := (var.sym.info as reflection.Struct).fields[1]
field2_typ := (var.sym.info as reflection.Struct).fields[1].typ
assert field2_typ.has_flag(.option)
assert field2.name == 'n'
assert field2.attrs.len == 2
assert field2.attrs == ['test2', 'test3']
assert field2.is_pub == false
}

View File

@ -45,7 +45,7 @@ fn test_type_name() {
fn test_type_symbol() {
ret_typ := reflection.get_funcs().filter(it.name == 'test3')[0].return_typ
assert reflection.get_type_symbol(ret_typ)?.language == 'v'
assert reflection.get_type_symbol(ret_typ)?.language == .v
}
fn test_method() {
@ -76,7 +76,7 @@ fn test_interfaces() {
}
fn test_enum_fields() {
assert reflection.get_enums().filter(it.name == 'TestEnum')[0].fields.map(it.name) == [
assert (reflection.get_enums().filter(it.name == 'TestEnum')[0].sym.info as reflection.Enum).vals == [
'foo',
'bar',
]