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
|
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
|
static_modifier string // for parallel_cc
|
||||||
|
|
||||||
has_reflection bool
|
has_reflection bool
|
||||||
// reflection metadata initialization
|
|
||||||
reflection_funcs strings.Builder
|
|
||||||
reflection_others strings.Builder
|
|
||||||
reflection_strings &map[string]int
|
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])
|
|| pref_.os in [.wasm32, .wasm32_emscripten])
|
||||||
static_modifier: if pref_.parallel_cc { 'static' } else { '' }
|
static_modifier: if pref_.parallel_cc { 'static' } else { '' }
|
||||||
has_reflection: 'v.reflection' in table.modules
|
has_reflection: 'v.reflection' in table.modules
|
||||||
reflection_funcs: strings.new_builder(100)
|
|
||||||
reflection_others: strings.new_builder(100)
|
|
||||||
reflection_strings: &reflection_strings
|
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.embedded_data.write(g.embedded_data) or { panic(err) }
|
||||||
global_g.shared_types.write(g.shared_types) 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.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
|
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
|
is_cc_msvc: global_g.is_cc_msvc
|
||||||
use_segfault_handler: global_g.use_segfault_handler
|
use_segfault_handler: global_g.use_segfault_handler
|
||||||
has_reflection: 'v.reflection' in global_g.table.modules
|
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
|
reflection_strings: global_g.reflection_strings
|
||||||
}
|
}
|
||||||
g.gen_file()
|
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}('
|
fn_header := '${visibility_kw}${type_name} ${fn_attrs}${name}('
|
||||||
g.definitions.write_string(fn_header)
|
g.definitions.write_string(fn_header)
|
||||||
g.gen_reflection_function(node)
|
|
||||||
g.write(fn_header)
|
g.write(fn_header)
|
||||||
}
|
}
|
||||||
arg_start_pos := g.out.len
|
arg_start_pos := g.out.len
|
||||||
|
|
|
@ -3,6 +3,8 @@ module c
|
||||||
import v.ast
|
import v.ast
|
||||||
import v.util
|
import v.util
|
||||||
|
|
||||||
|
const cprefix = 'v__reflection__'
|
||||||
|
|
||||||
// reflection_string maps string to its idx
|
// reflection_string maps string to its idx
|
||||||
fn (mut g Gen) reflection_string(str string) int {
|
fn (mut g Gen) reflection_string(str string) int {
|
||||||
return unsafe {
|
return unsafe {
|
||||||
|
@ -17,7 +19,7 @@ fn (mut g Gen) reflection_string(str string) int {
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut g Gen) gen_reflection_strings() {
|
fn (mut g Gen) gen_reflection_strings() {
|
||||||
for str, idx in g.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
|
// gen_functionarg_array generates the code for functionarg argument
|
||||||
[inline]
|
[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 {
|
if node.params.len == 0 {
|
||||||
return g.gen_empty_array(type_name)
|
return g.gen_empty_array(type_name)
|
||||||
}
|
}
|
||||||
mut out := 'new_array_from_c_array(${node.params.len},${node.params.len},sizeof(${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}]){'
|
out += '_MOV((${type_name}[${node.params.len}]){'
|
||||||
for param in node.params {
|
out += node.params.map('((${type_name}){.name=_SLIT("${it.name}"),.typ=${int(it.typ)},.is_mut=${it.is_mut}})').join(',')
|
||||||
out += '((${type_name}){.name=_SLIT("${param.name}"),.typ=${param.typ.idx()},}),'
|
|
||||||
}
|
|
||||||
out += '}))'
|
out += '}))'
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// gen_functionarg_array generates the code for functionarg argument
|
// gen_functionarg_array generates the code for functionarg argument
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut g Gen) gen_function_array(nodes []ast.FnDecl) string {
|
fn (mut g Gen) gen_function_array(nodes []ast.Fn) string {
|
||||||
type_name := 'v__reflection__Function'
|
type_name := '${c.cprefix}Function'
|
||||||
|
|
||||||
if nodes.len == 0 {
|
if nodes.len == 0 {
|
||||||
return g.gen_empty_array(type_name)
|
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}),'
|
mut out := 'new_array_from_c_array(${nodes.len},${nodes.len},sizeof(${type_name}),'
|
||||||
out += '_MOV((${type_name}[${nodes.len}]){'
|
out += '_MOV((${type_name}[${nodes.len}]){'
|
||||||
for method in nodes {
|
out += nodes.map(g.gen_reflection_fn(it)).join(',')
|
||||||
out += g.gen_reflection_fndecl(method)
|
|
||||||
out += ','
|
|
||||||
}
|
|
||||||
out += '}))'
|
out += '}))'
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// gen_reflection_enum_fields generates C code for enum fields
|
// gen_reflection_fn generates C code for Function struct
|
||||||
[inline]
|
[inline]
|
||||||
fn (g Gen) gen_reflection_enum_fields(fields []ast.EnumField) string {
|
fn (mut g Gen) gen_reflection_fn(node ast.Fn) string {
|
||||||
if fields.len == 0 {
|
mut arg_str := '((${c.cprefix}Function){'
|
||||||
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){'
|
|
||||||
v_name := node.name.all_after_last('.')
|
v_name := node.name.all_after_last('.')
|
||||||
arg_str += '.mod_name=_SLIT("${node.mod}"),'
|
arg_str += '.mod_name=_SLIT("${node.mod}"),'
|
||||||
arg_str += '.name=_SLIT("${v_name}"),'
|
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 += '.file_idx=${g.reflection_string(util.cescaped_path(node.file))},'
|
||||||
arg_str += '.line_start=${node.pos.line_nr},'
|
arg_str += '.line_start=${node.pos.line_nr},'
|
||||||
arg_str += '.line_end=${node.pos.last_line},'
|
arg_str += '.line_end=${node.pos.last_line},'
|
||||||
arg_str += '.is_variadic=${node.is_variadic},'
|
arg_str += '.is_variadic=${node.is_variadic},'
|
||||||
arg_str += '.return_typ=${node.return_type.idx()},'
|
arg_str += '.return_typ=${int(node.return_type)},'
|
||||||
arg_str += '.receiver_typ=${node.receiver.typ.idx()}'
|
arg_str += '.receiver_typ=${int(node.receiver_type)},'
|
||||||
|
arg_str += '.is_pub=${node.is_pub}'
|
||||||
arg_str += '})'
|
arg_str += '})'
|
||||||
return arg_str
|
return arg_str
|
||||||
}
|
}
|
||||||
|
|
||||||
// gen_reflection_sym generates C code for TypeSymbol struct
|
// gen_reflection_sym generates C code for TypeSymbol struct
|
||||||
[inline]
|
[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_] {
|
kind_name := if tsym.kind in [.none_, .struct_, .enum_, .interface_] {
|
||||||
tsym.kind.str() + '_'
|
tsym.kind.str() + '_'
|
||||||
} else {
|
} else {
|
||||||
tsym.kind.str()
|
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]
|
[inline]
|
||||||
fn (mut g Gen) gen_reflection_function(node ast.FnDecl) {
|
fn (g Gen) gen_attrs_array(attrs []ast.Attr) string {
|
||||||
if !g.has_reflection {
|
if attrs.len == 0 {
|
||||||
return
|
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
|
// gen_reflection_data generates code to initilized V reflection metadata
|
||||||
fn (mut g Gen) gen_reflection_data() {
|
fn (mut g Gen) gen_reflection_data() {
|
||||||
// modules declaration
|
// modules declaration
|
||||||
for mod_name in g.table.modules {
|
for mod_name in g.table.modules {
|
||||||
g.reflection_others.write_string('\tv__reflection__add_module(_SLIT("${mod_name}"));\n')
|
g.writeln('\t${c.cprefix}add_module(_SLIT("${mod_name}"));')
|
||||||
}
|
|
||||||
|
|
||||||
// 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')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// type symbols declaration
|
// type symbols declaration
|
||||||
for _, tsym in g.table.type_symbols {
|
for _, tsym in g.table.type_symbols {
|
||||||
sym := g.gen_reflection_sym(tsym)
|
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()
|
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]
|
[has_globals]
|
||||||
module reflection
|
module reflection
|
||||||
|
|
||||||
import v.ast
|
import arrays
|
||||||
|
|
||||||
__global g_reflection = Reflection{}
|
__global g_reflection = Reflection{}
|
||||||
|
|
||||||
|
@ -17,37 +17,187 @@ pub mut:
|
||||||
strings map[int]string
|
strings map[int]string
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Interface {
|
pub enum VLanguage {
|
||||||
pub:
|
v
|
||||||
name string // interface name
|
c
|
||||||
typ int // type idx
|
js
|
||||||
is_pub bool // is pub?
|
amd64 // aka x86_64
|
||||||
methods []Function // methods
|
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:
|
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 struct Enum {
|
||||||
pub:
|
pub:
|
||||||
name string // enum name
|
vals []string // enum values
|
||||||
is_pub bool // is pub?
|
is_flag bool // is flag?
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 struct TypeSymbol {
|
||||||
pub:
|
pub:
|
||||||
name string // symbol name
|
name string // symbol name
|
||||||
idx int // symbol idx
|
idx int // symbol idx
|
||||||
parent_idx int // symbol parent idx
|
parent_idx int // symbol parent idx
|
||||||
language string // language
|
language VLanguage // language
|
||||||
kind ast.Kind // kind
|
kind VKind // kind
|
||||||
|
info TypeInfo // info
|
||||||
|
methods []Function // methods
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Type {
|
pub struct Type {
|
||||||
|
@ -64,8 +214,9 @@ pub:
|
||||||
|
|
||||||
pub struct FunctionArg {
|
pub struct FunctionArg {
|
||||||
pub:
|
pub:
|
||||||
name string // argument name
|
name string // argument name
|
||||||
typ int // argument type idx
|
typ VType // argument type idx
|
||||||
|
is_mut bool // is mut?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
|
@ -73,12 +224,13 @@ pub:
|
||||||
mod_name string // module name
|
mod_name string // module name
|
||||||
name string // function/method name
|
name string // function/method name
|
||||||
args []FunctionArg // function/method args
|
args []FunctionArg // function/method args
|
||||||
file_idx int // source file name
|
file_idx int // source file name
|
||||||
line_start int // decl start line
|
line_start int // decl start line
|
||||||
line_end int // decl end line
|
line_end int // decl end line
|
||||||
is_variadic bool // is variadic?
|
is_variadic bool // is variadic?
|
||||||
return_typ int // return type idx
|
return_typ VType // return type idx
|
||||||
receiver_typ int // receiver type idx (is a method)
|
receiver_typ VType // receiver type idx (is a method)
|
||||||
|
is_pub bool // is pub?
|
||||||
}
|
}
|
||||||
|
|
||||||
// API module
|
// API module
|
||||||
|
@ -99,7 +251,14 @@ pub fn get_modules() []Module {
|
||||||
|
|
||||||
// get_functions returns the functions built with V source
|
// get_functions returns the functions built with V source
|
||||||
pub fn get_funcs() []Function {
|
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
|
// get_types returns the registered types
|
||||||
|
@ -108,8 +267,9 @@ pub fn get_types() []Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get_enums returns the registered enums
|
// get_enums returns the registered enums
|
||||||
pub fn get_enums() []Enum {
|
pub fn get_enums() []Type {
|
||||||
return g_reflection.enums
|
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
|
// get_aliases returns the registered aliases
|
||||||
|
@ -120,7 +280,8 @@ pub fn get_aliases() []Type {
|
||||||
|
|
||||||
// get_interfaces returns the registered aliases
|
// get_interfaces returns the registered aliases
|
||||||
pub fn get_interfaces() []Interface {
|
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
|
// get_sum_types returns the registered sum types
|
||||||
|
@ -170,7 +331,10 @@ fn add_func(func Function) {
|
||||||
|
|
||||||
[markused]
|
[markused]
|
||||||
fn add_type(type_ Type) {
|
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]
|
[markused]
|
||||||
|
@ -178,16 +342,6 @@ fn add_type_symbol(typesymbol TypeSymbol) {
|
||||||
g_reflection.type_symbols << 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]
|
[markused]
|
||||||
fn add_string(str string, idx int) {
|
fn add_string(str string, idx int) {
|
||||||
g_reflection.strings[idx] = str
|
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() {
|
fn test_type_symbol() {
|
||||||
ret_typ := reflection.get_funcs().filter(it.name == 'test3')[0].return_typ
|
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() {
|
fn test_method() {
|
||||||
|
@ -76,7 +76,7 @@ fn test_interfaces() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_enum_fields() {
|
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',
|
'foo',
|
||||||
'bar',
|
'bar',
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user