v / vlib / v2 / gen / cleanc / orm.v
374 lines · 341 sloc · 10.37 KB · e7738c112c787d477501fa4a87edd0e1d72159bd
Raw
1// Copyright (c) 2026 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4
5module cleanc
6
7import v2.ast
8
9fn (mut g Gen) try_gen_orm_create_call(c_name string, call_args []ast.Expr) bool {
10 if call_args.len != 3 || !c_name.ends_with('__create') {
11 return false
12 }
13 if !orm_table_can_emit(call_args[1]) || !orm_table_fields_array_can_emit(call_args[2]) {
14 return false
15 }
16 g.sb.write_string('${c_name}(')
17 g.gen_call_arg(c_name, 0, call_args[0])
18 g.sb.write_string(', ')
19 g.write_orm_table_c_expr(call_args[1])
20 g.sb.write_string(', ')
21 g.write_orm_table_fields_array_c_expr(call_args[2])
22 g.sb.write_string(')')
23 if c_name != '' {
24 g.mark_called_fn_name(c_name)
25 }
26 return true
27}
28
29fn (mut g Gen) try_gen_orm_create_call_expr(node ast.CallExpr) bool {
30 if !orm_create_call_can_emit(node) {
31 return false
32 }
33 lhs := node.lhs as ast.SelectorExpr
34 name := g.orm_create_call_name(node) or { return false }
35 call_args := [
36 lhs.lhs,
37 node.args[0],
38 node.args[1],
39 ]
40 return g.try_gen_orm_create_call(name, call_args)
41}
42
43fn orm_create_call_can_emit(node ast.CallExpr) bool {
44 if node.args.len != 2 || node.lhs !is ast.SelectorExpr {
45 return false
46 }
47 lhs := node.lhs as ast.SelectorExpr
48 return lhs.rhs.name == 'create' && orm_table_can_emit(node.args[0])
49 && orm_table_fields_array_can_emit(node.args[1])
50}
51
52fn (mut g Gen) orm_create_call_name(node ast.CallExpr) ?string {
53 if node.lhs !is ast.SelectorExpr {
54 return none
55 }
56 lhs := node.lhs as ast.SelectorExpr
57 method_name := sanitize_fn_ident(lhs.rhs.name)
58 mut name := g.resolve_call_name(node.lhs, node.args.len)
59 if name != '' {
60 return name
61 }
62 mut base_type := g.method_receiver_base_type(lhs.lhs)
63 if base_type == '' {
64 base_type = g.get_expr_type(lhs.lhs).trim_space().trim_right('*')
65 }
66 if base_type == '' {
67 base_type = g.receiver_local_base_type(lhs.lhs)
68 }
69 if name == '' && base_type != '' {
70 if embedded := g.resolve_method_on_embedded_receiver(base_type, method_name) {
71 name = embedded.method_c_name
72 }
73 }
74 if name == '' && base_type != '' {
75 name = '${base_type}__${method_name}'
76 }
77 if name == '' {
78 return none
79 }
80 return name
81}
82
83fn (mut g Gen) orm_create_call_result_type(node ast.CallExpr) ?string {
84 if !orm_create_call_can_emit(node) {
85 return none
86 }
87 name := g.orm_create_call_name(node) or { return none }
88 if ret := g.fn_return_types[name] {
89 return ret
90 }
91 return none
92}
93
94fn orm_table_can_emit(expr ast.Expr) bool {
95 init := orm_init_expr(expr) or { return false }
96 name_expr := orm_init_field_value(init, 'name') or { return false }
97 attrs_expr := orm_init_field_value(init, 'attrs') or { return false }
98 return orm_string_value(name_expr) != none && orm_vattribute_array_can_emit(attrs_expr)
99}
100
101fn orm_table_fields_array_can_emit(expr ast.Expr) bool {
102 arr := orm_array_init_expr(expr) or { return false }
103 for field_expr in arr.exprs {
104 if !orm_table_field_can_emit(field_expr) {
105 return false
106 }
107 }
108 return true
109}
110
111fn orm_table_field_can_emit(expr ast.Expr) bool {
112 init := orm_init_expr(expr) or { return false }
113 name_expr := orm_init_field_value(init, 'name') or { return false }
114 typ_expr := orm_init_field_value(init, 'typ') or { return false }
115 nullable_expr := orm_init_field_value(init, 'nullable') or { return false }
116 default_val_expr := orm_init_field_value(init, 'default_val') or { return false }
117 attrs_expr := orm_init_field_value(init, 'attrs') or { return false }
118 is_arr_expr := orm_init_field_value(init, 'is_arr') or { return false }
119 return orm_string_value(name_expr) != none && orm_number_c_expr(typ_expr) != none
120 && orm_bool_c_expr(nullable_expr) != none && orm_string_value(default_val_expr) != none
121 && orm_vattribute_array_can_emit(attrs_expr) && orm_bool_c_expr(is_arr_expr) != none
122}
123
124fn orm_vattribute_array_can_emit(expr ast.Expr) bool {
125 arr := orm_array_init_expr(expr) or { return false }
126 for attr_expr in arr.exprs {
127 if !orm_vattribute_can_emit(attr_expr) {
128 return false
129 }
130 }
131 return true
132}
133
134fn orm_vattribute_can_emit(expr ast.Expr) bool {
135 init := orm_init_expr(expr) or { return false }
136 name_expr := orm_init_field_value(init, 'name') or { return false }
137 has_arg_expr := orm_init_field_value(init, 'has_arg') or { return false }
138 arg_expr := orm_init_field_value(init, 'arg') or { return false }
139 kind_expr := orm_init_field_value(init, 'kind') or { return false }
140 return orm_string_value(name_expr) != none && orm_bool_c_expr(has_arg_expr) != none
141 && orm_string_value(arg_expr) != none && orm_ident_c_expr(kind_expr) != none
142}
143
144fn (mut g Gen) write_orm_table_c_expr(expr ast.Expr) {
145 init := orm_init_expr(expr) or { return }
146 name_expr := orm_init_field_value(init, 'name') or { return }
147 attrs_expr := orm_init_field_value(init, 'attrs') or { return }
148 g.sb.write_string('((orm__Table){.name = ')
149 g.write_orm_v_string_c_expr(name_expr)
150 g.sb.write_string(',.attrs = ')
151 g.write_orm_vattribute_array_c_expr(attrs_expr)
152 g.sb.write_string('})')
153}
154
155fn (mut g Gen) write_orm_table_fields_array_c_expr(expr ast.Expr) {
156 arr := orm_array_init_expr(expr) or { return }
157 g.sb.write_string('new_array_from_c_array(${arr.exprs.len}, ${arr.exprs.len}, sizeof(orm__TableField), ')
158 if arr.exprs.len == 0 {
159 g.sb.write_string('&(array){0})')
160 return
161 }
162 g.sb.write_string('&(orm__TableField[${arr.exprs.len}]){')
163 for i, field_expr in arr.exprs {
164 if i > 0 {
165 g.sb.write_string(', ')
166 }
167 g.write_orm_table_field_c_expr(field_expr)
168 }
169 g.sb.write_string('})')
170}
171
172fn (mut g Gen) write_orm_table_field_c_expr(expr ast.Expr) {
173 init := orm_init_expr(expr) or { return }
174 name_expr := orm_init_field_value(init, 'name') or { return }
175 typ_expr := orm_init_field_value(init, 'typ') or { return }
176 nullable_expr := orm_init_field_value(init, 'nullable') or { return }
177 default_val_expr := orm_init_field_value(init, 'default_val') or { return }
178 attrs_expr := orm_init_field_value(init, 'attrs') or { return }
179 is_arr_expr := orm_init_field_value(init, 'is_arr') or { return }
180 g.sb.write_string('((orm__TableField){.name = ')
181 g.write_orm_v_string_c_expr(name_expr)
182 g.sb.write_string(',.typ = ')
183 g.sb.write_string(orm_number_c_expr(typ_expr) or { return })
184 g.sb.write_string(',.nullable = ')
185 g.sb.write_string(orm_bool_c_expr(nullable_expr) or { return })
186 g.sb.write_string(',.default_val = ')
187 g.write_orm_v_string_c_expr(default_val_expr)
188 g.sb.write_string(',.attrs = ')
189 g.write_orm_vattribute_array_c_expr(attrs_expr)
190 g.sb.write_string(',.is_arr = ')
191 g.sb.write_string(orm_bool_c_expr(is_arr_expr) or { return })
192 g.sb.write_string('})')
193}
194
195fn (mut g Gen) write_orm_vattribute_array_c_expr(expr ast.Expr) {
196 arr := orm_array_init_expr(expr) or { return }
197 if arr.exprs.len == 0 {
198 g.sb.write_string('new_array_from_c_array(0, 0, sizeof(VAttribute), &(array){0})')
199 return
200 }
201 g.sb.write_string('new_array_from_c_array(${arr.exprs.len}, ${arr.exprs.len}, sizeof(VAttribute), &(VAttribute[${arr.exprs.len}]){')
202 for i, attr_expr in arr.exprs {
203 if i > 0 {
204 g.sb.write_string(', ')
205 }
206 g.write_orm_vattribute_c_expr(attr_expr)
207 }
208 g.sb.write_string('})')
209}
210
211fn (mut g Gen) write_orm_vattribute_c_expr(expr ast.Expr) {
212 init := orm_init_expr(expr) or { return }
213 name_expr := orm_init_field_value(init, 'name') or { return }
214 has_arg_expr := orm_init_field_value(init, 'has_arg') or { return }
215 arg_expr := orm_init_field_value(init, 'arg') or { return }
216 kind_expr := orm_init_field_value(init, 'kind') or { return }
217 g.sb.write_string('((VAttribute){.name = ')
218 g.write_orm_v_string_c_expr(name_expr)
219 g.sb.write_string(',.has_arg = ')
220 g.sb.write_string(orm_bool_c_expr(has_arg_expr) or { return })
221 g.sb.write_string(',.arg = ')
222 g.write_orm_v_string_c_expr(arg_expr)
223 g.sb.write_string(',.kind = ')
224 g.sb.write_string(orm_ident_c_expr(kind_expr) or { return })
225 g.sb.write_string('})')
226}
227
228fn orm_init_expr(expr ast.Expr) ?ast.InitExpr {
229 match expr {
230 ast.InitExpr {
231 return expr
232 }
233 ast.ParenExpr {
234 return orm_init_expr(expr.expr)
235 }
236 else {}
237 }
238
239 return none
240}
241
242fn orm_array_init_expr(expr ast.Expr) ?ast.ArrayInitExpr {
243 match expr {
244 ast.ArrayInitExpr {
245 return expr
246 }
247 ast.CallExpr {
248 name := orm_call_name(expr.lhs)
249 if name in ['builtin__new_array_from_c_array_noscan', 'builtin__new_array_from_c_array', 'new_array_from_c_array']
250 && expr.args.len >= 4 {
251 return orm_array_init_expr(expr.args[3])
252 }
253 }
254 ast.PrefixExpr {
255 if expr.op == .amp {
256 return orm_array_init_expr(expr.expr)
257 }
258 }
259 ast.ParenExpr {
260 return orm_array_init_expr(expr.expr)
261 }
262 else {}
263 }
264
265 return none
266}
267
268fn orm_call_name(lhs ast.Expr) string {
269 match lhs {
270 ast.Ident {
271 return lhs.name
272 }
273 ast.SelectorExpr {
274 if lhs.lhs is ast.Ident {
275 left := lhs.lhs as ast.Ident
276 return '${left.name}__${lhs.rhs.name}'
277 }
278 }
279 else {}
280 }
281
282 return ''
283}
284
285fn orm_init_field_value(init ast.InitExpr, name string) ?ast.Expr {
286 for field in init.fields {
287 if field.name == name {
288 return field.value
289 }
290 }
291 return none
292}
293
294fn (mut g Gen) write_orm_v_string_c_expr(expr ast.Expr) {
295 raw := orm_string_value(expr) or { return }
296 g.sb.write_string(c_static_v_string_expr_from_c_literal(c_string_literal_content_to_c(raw)))
297}
298
299fn orm_string_value(expr ast.Expr) ?string {
300 match expr {
301 ast.StringLiteral {
302 mut val := strip_literal_quotes(expr.value)
303 if expr.kind == .raw {
304 val = val.replace('\\', '\\\\')
305 } else {
306 val = process_line_continuations(val)
307 }
308 return val
309 }
310 ast.BasicLiteral {
311 if expr.kind == .string {
312 return process_line_continuations(strip_literal_quotes(expr.value))
313 }
314 }
315 else {}
316 }
317
318 return none
319}
320
321fn orm_bool_c_expr(expr ast.Expr) ?string {
322 match expr {
323 ast.BasicLiteral {
324 if expr.kind == .key_true || expr.value == 'true' {
325 return 'true'
326 }
327 if expr.kind == .key_false || expr.value == 'false' {
328 return 'false'
329 }
330 }
331 ast.Ident {
332 if expr.name == 'true' || expr.name == 'false' {
333 return expr.name
334 }
335 }
336 else {}
337 }
338
339 return none
340}
341
342fn orm_number_c_expr(expr ast.Expr) ?string {
343 match expr {
344 ast.BasicLiteral {
345 return sanitize_c_number_literal(expr.value)
346 }
347 ast.PrefixExpr {
348 if expr.op == .minus && expr.expr is ast.BasicLiteral {
349 inner := expr.expr as ast.BasicLiteral
350 return '-' + sanitize_c_number_literal(inner.value)
351 }
352 }
353 else {}
354 }
355
356 return none
357}
358
359fn orm_ident_c_expr(expr ast.Expr) ?string {
360 match expr {
361 ast.Ident {
362 return expr.name
363 }
364 ast.SelectorExpr {
365 if expr.lhs is ast.Ident {
366 left := expr.lhs as ast.Ident
367 return '${left.name}__${expr.rhs.name}'
368 }
369 }
370 else {}
371 }
372
373 return none
374}
375