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:
parent
fbfdab9e2d
commit
47e8d967e6
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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
|
||||
|
117
vlib/v/tests/reflection_sym_test.v
Normal file
117
vlib/v/tests/reflection_sym_test.v
Normal 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
|
||||
}
|
@ -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',
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user