v2 / vlib / v / gen / c / reflection.v
240 lines · 219 sloc · 9.64 KB · e2e5cf8db56f3562c7baa735061690be936bdf3e
Raw
1module c
2
3import v.ast
4import v.util
5
6const cprefix = 'v__reflection__'
7
8// reflection_string maps string to its idx
9fn (mut g Gen) reflection_string(str string) int {
10 return unsafe {
11 g.reflection_strings[str] or {
12 g.reflection_strings[str] = g.reflection_strings.len
13 g.reflection_strings.len - 1
14 }
15 }
16}
17
18// gen_reflection_strings generates the reflectino string registration
19@[inline]
20fn (mut g Gen) gen_reflection_strings() {
21 for str, idx in g.reflection_strings {
22 g.writeln('\t${cprefix}add_string(_S("${str}"), ${idx});')
23 }
24}
25
26// gen_empty_array generates code for empty array
27@[inline]
28fn (g &Gen) gen_empty_array(type_name string) string {
29 return 'builtin____new_array_with_default(0, 0, sizeof(${type_name}), 0)'
30}
31
32// gen_functionarg_array generates the code for functionarg argument
33@[inline]
34fn (g &Gen) gen_functionarg_array(type_name string, node ast.Fn) string {
35 if node.params.len == 0 {
36 return g.gen_empty_array(type_name)
37 }
38 mut out := 'builtin__new_array_from_c_array(${node.params.len},${node.params.len},sizeof(${type_name}),'
39 out += '_MOV((${type_name}[${node.params.len}]){'
40 out +=
41 node.params.map('((${type_name}){.name=_S("${it.name}"),.typ=${int(it.typ)},.is_mut=${it.is_mut}})').join(',')
42 out += '}))'
43 return out
44}
45
46// gen_functionarg_array generates the code for functionarg argument
47@[inline]
48fn (mut g Gen) gen_function_array(nodes []ast.Fn) string {
49 type_name := '${cprefix}Function'
50
51 if nodes.len == 0 {
52 return g.gen_empty_array(type_name)
53 }
54
55 mut out := 'builtin__new_array_from_c_array(${nodes.len},${nodes.len},sizeof(${type_name}),'
56 out += '_MOV((${type_name}[${nodes.len}]){'
57 out += nodes.map(g.gen_reflection_fn(it)).join(',')
58 out += '}))'
59 return out
60}
61
62// gen_reflection_fn generates C code for Function struct
63@[inline]
64fn (mut g Gen) gen_reflection_fn(node ast.Fn) string {
65 mut arg_str := '((${cprefix}Function){'
66 v_name := node.name.all_after_last('.')
67 arg_str += '.mod_name=_S("${node.mod}"),'
68 arg_str += '.name=_S("${v_name}"),'
69 arg_str += '.args=${g.gen_functionarg_array(cprefix + 'FunctionArg', node)},'
70 arg_str += '.file_idx=${g.reflection_string(util.cescaped_path(node.file))},'
71 arg_str += '.line_start=${node.pos.line_nr},'
72 arg_str += '.line_end=${node.pos.last_line},'
73 arg_str += '.is_variadic=${node.is_variadic},'
74 arg_str += '.return_typ=${int(node.return_type)},'
75 arg_str += '.receiver_typ=${int(node.receiver_type)},'
76 arg_str += '.is_pub=${node.is_pub},'
77 arg_str += '.attrs=${g.gen_attrs_array(node.attrs)}'
78 arg_str += '})'
79 return arg_str
80}
81
82// gen_reflection_sym generates C code for TypeSymbol struct
83@[inline]
84fn (mut g Gen) gen_reflection_sym(tsym ast.TypeSymbol) string {
85 kind_name := tsym.kind.str()
86 name := tsym.name.all_after_last('.')
87 info := g.gen_reflection_sym_info(tsym)
88 methods := g.gen_function_array(tsym.methods)
89 return '(${cprefix}TypeSymbol){.name=_S("${name}"),.mod=_S("${tsym.mod}"),.idx=${tsym.idx},.parent_idx=${tsym.parent_idx},.language=${cprefix}VLanguage__${tsym.language},.kind=${cprefix}VKind__${kind_name},.info=${info},.methods=${methods}}'
90}
91
92// gen_attrs_array generates C code for []VAttribute
93@[inline]
94fn (g &Gen) gen_attrs_array(attrs []ast.Attr) string {
95 type_name := 'VAttribute'
96 if attrs.len == 0 {
97 return g.gen_empty_array(type_name)
98 }
99 mut items := []string{cap: attrs.len}
100 for attr in attrs {
101 items << '((${type_name}){.name=_S("${cescape_nonascii(util.smart_quote(attr.name, false))}"),.has_arg=${attr.has_arg},.arg=_S("${cescape_nonascii(util.smart_quote(attr.arg,
102 false))}"),.kind=${int(attr.kind)}})'
103 }
104 mut out := 'builtin__new_array_from_c_array(${attrs.len},${attrs.len},sizeof(${type_name}),'
105 out += '_MOV((${type_name}[${attrs.len}]){'
106 out += items.join(',')
107 out += '}))'
108 return out
109}
110
111// gen_fields_array generates C code for []StructField
112@[inline]
113fn (g &Gen) gen_fields_array(fields []ast.StructField) string {
114 if fields.len == 0 {
115 return g.gen_empty_array('${cprefix}StructField')
116 }
117 mut out := 'builtin__new_array_from_c_array(${fields.len},${fields.len},sizeof(${cprefix}StructField),'
118 out += '_MOV((${cprefix}StructField[${fields.len}]){'
119 out +=
120 fields.map('((${cprefix}StructField){.name=_S("${it.name}"),.typ=${int(it.typ)},.attrs=${g.gen_attrs_array(it.attrs)},.is_pub=${it.is_pub},.is_mut=${it.is_mut}})').join(',')
121 out += '}))'
122 return out
123}
124
125// gen_type_array generates C code for []Type
126@[inline]
127fn (g &Gen) gen_type_array(types []ast.Type) string {
128 if types.len == 0 {
129 return g.gen_empty_array(ast.int_type_name)
130 }
131 return 'builtin__new_array_from_c_array(${types.len},${types.len},sizeof(int),_MOV((int[${types.len}]){${types.map(int(it).str()).join(',')}}))'
132}
133
134// gen_string_array generates C code for []string
135@[inline]
136fn (g &Gen) gen_string_array(strs []string) string {
137 if strs.len == 0 {
138 return g.gen_empty_array('string')
139 }
140 items := strs.map('_S("${it}")').join(',')
141 return 'builtin__new_array_from_c_array(${strs.len},${strs.len},sizeof(string),_MOV((string[${strs.len}]){${items}}))'
142}
143
144// gen_reflection_sym_info generates C code for TypeSymbol's info sum type
145@[inline]
146fn (mut g Gen) gen_reflection_sym_info(tsym ast.TypeSymbol) string {
147 match tsym.kind {
148 .array {
149 info := tsym.info as ast.Array
150 s := 'ADDR(${cprefix}Array,(((${cprefix}Array){.nr_dims=${info.nr_dims},.elem_type=${int(info.elem_type)}})))'
151 return '(${cprefix}TypeInfo){._${cprefix}Array = builtin__memdup(${s},sizeof(${cprefix}Array)),._typ=${g.table.find_type_idx('v.reflection.Array')}}'
152 }
153 .array_fixed {
154 info := tsym.info as ast.ArrayFixed
155 s := 'ADDR(${cprefix}ArrayFixed,(((${cprefix}ArrayFixed){.size=${info.size},.elem_type=${int(info.elem_type)}})))'
156 return '(${cprefix}TypeInfo){._${cprefix}ArrayFixed=builtin__memdup(${s},sizeof(${cprefix}ArrayFixed)),._typ=${g.table.find_type_idx('v.reflection.ArrayFixed')}}'
157 }
158 .map {
159 info := tsym.info as ast.Map
160 s := 'ADDR(${cprefix}Map,(((${cprefix}Map){.key_type=${int(info.key_type)},.value_type=${int(info.value_type)}})))'
161 return '(${cprefix}TypeInfo){._${cprefix}Map=builtin__memdup(${s},sizeof(${cprefix}Map)),._typ=${g.table.find_type_idx('v.reflection.Map')}}'
162 }
163 .sum_type {
164 info := tsym.info as ast.SumType
165 s := 'ADDR(${cprefix}SumType,(((${cprefix}SumType){.parent_idx=${info.parent_type.idx()},.variants=${g.gen_type_array(info.variants)}})))'
166 return '(${cprefix}TypeInfo){._${cprefix}SumType=builtin__memdup(${s},sizeof(${cprefix}SumType)),._typ=${g.table.find_type_idx('v.reflection.SumType')}}'
167 }
168 .struct {
169 info := tsym.info as ast.Struct
170 attrs := g.gen_attrs_array(info.attrs)
171 fields := g.gen_fields_array(info.fields)
172 s := 'ADDR(${cprefix}Struct,(((${cprefix}Struct){.parent_idx=${(tsym.info as ast.Struct).parent_type.idx()},.attrs=${attrs},.fields=${fields}})))'
173 return '(${cprefix}TypeInfo){._${cprefix}Struct=builtin__memdup(${s},sizeof(${cprefix}Struct)),._typ=${g.table.find_type_idx('v.reflection.Struct')}}'
174 }
175 .enum {
176 info := tsym.info as ast.Enum
177 vals := g.gen_string_array(info.vals)
178 s := 'ADDR(${cprefix}Enum,(((${cprefix}Enum){.vals=${vals},.is_flag=${info.is_flag}})))'
179 return '(${cprefix}TypeInfo){._${cprefix}Enum=builtin__memdup(${s},sizeof(${cprefix}Enum)),._typ=${g.table.find_type_idx('v.reflection.Enum')}}'
180 }
181 .function {
182 info := tsym.info as ast.FnType
183 s := 'ADDR(${cprefix}Function,${g.gen_reflection_fn(info.func)})'
184 return '(${cprefix}TypeInfo){._${cprefix}Function=builtin__memdup(${s},sizeof(${cprefix}Function)),._typ=${g.table.find_type_idx('v.reflection.Function')}}'
185 }
186 .interface {
187 name := tsym.name.all_after_last('.')
188 info := tsym.info as ast.Interface
189 methods := g.gen_function_array(info.methods)
190 fields := g.gen_fields_array(info.fields)
191 s := 'ADDR(${cprefix}Interface,(((${cprefix}Interface){.name=_S("${name}"),.methods=${methods},.fields=${fields},.is_generic=${info.is_generic}})))'
192 return '(${cprefix}TypeInfo){._${cprefix}Interface=builtin__memdup(${s},sizeof(${cprefix}Interface)),._typ=${g.table.find_type_idx('v.reflection.Interface')}}'
193 }
194 .alias {
195 info := tsym.info as ast.Alias
196 s := 'ADDR(${cprefix}Alias,(((${cprefix}Alias){.parent_idx=${info.parent_type.idx()},.language=${cprefix}VLanguage__${info.language.str()}})))'
197 return '(${cprefix}TypeInfo){._${cprefix}Alias=builtin__memdup(${s},sizeof(${cprefix}Alias)),._typ=${g.table.find_type_idx('v.reflection.Alias')}}'
198 }
199 .multi_return {
200 info := tsym.info as ast.MultiReturn
201 s := 'ADDR(${cprefix}MultiReturn,(((${cprefix}MultiReturn){.types=${g.gen_type_array(info.types)}})))'
202 return '(${cprefix}TypeInfo){._${cprefix}MultiReturn=builtin__memdup(${s},sizeof(${cprefix}MultiReturn)),._typ=${g.table.find_type_idx('v.reflection.MultiReturn')}}'
203 }
204 else {
205 s := 'ADDR(${cprefix}None,(((${cprefix}None){.parent_idx=${tsym.parent_idx},})))'
206 return '(${cprefix}TypeInfo){._${cprefix}None=builtin__memdup(${s},sizeof(${cprefix}None)),._typ=${g.table.find_type_idx('v.reflection.None')}}'
207 }
208 }
209}
210
211// gen_reflection_data generates code to initialized V reflection metadata
212fn (mut g Gen) gen_reflection_data() {
213 // modules declaration
214 for mod_name in g.table.modules {
215 g.writeln('\t${cprefix}add_module(_S("${mod_name}"));')
216 }
217
218 // type symbols declaration
219 for _, tsym in g.table.type_symbols {
220 sym := g.gen_reflection_sym(tsym)
221 g.writeln('\t${cprefix}add_type_symbol(${sym});')
222 }
223
224 // types declaration
225 for full_name, idx in g.table.type_idxs {
226 name := full_name.all_after_last('.')
227 g.writeln('\t${cprefix}add_type((${cprefix}Type){.name=_S("${name}"),.idx=${idx}});')
228 }
229
230 // func declaration (methods come from struct methods)
231 for _, fn_ in g.table.fns {
232 if fn_.no_body || fn_.is_method || fn_.language != .v {
233 continue
234 }
235 func := g.gen_reflection_fn(fn_)
236 g.writeln('\t${cprefix}add_func(${func});')
237 }
238
239 g.gen_reflection_strings()
240}
241