v4 / vlib / v3 / transform / or.v
565 lines · 530 sloc · 17.79 KB · 288feee4702b35beadb4037d02b96b5c8674156b
Raw
1module transform
2
3import v3.flat
4import v3.types
5
6// ArrayIndexInfo stores array index info metadata used by transform.
7struct ArrayIndexInfo {
8 base_id flat.NodeId
9 index_id flat.NodeId
10 base_type string
11 value_type string
12}
13
14// EnumFromStringInfo stores enum from string info metadata used by transform.
15struct EnumFromStringInfo {
16 enum_type string
17 fields []string
18 arg_id flat.NodeId
19}
20
21// optional_base_type supports optional base type handling for Transformer.
22fn (t &Transformer) optional_base_type(typ string) string {
23 if typ.len > 1 && (typ[0] == `?` || typ[0] == `!`) {
24 return typ[1..]
25 }
26 return typ
27}
28
29// array_index_info supports array index info handling for Transformer.
30fn (mut t Transformer) array_index_info(index_id flat.NodeId) ?ArrayIndexInfo {
31 if int(index_id) < 0 {
32 return none
33 }
34 expr := t.a.nodes[int(index_id)]
35 if expr.kind != .index || expr.children_count < 2 || expr.value == 'range' {
36 return none
37 }
38 base_id := t.a.child(&expr, 0)
39 index_expr_id := t.a.child(&expr, 1)
40 base_type := t.resolve_expr_type(base_id)
41 if !base_type.starts_with('[]') {
42 return none
43 }
44 value_type := t.normalize_type_alias(base_type[2..])
45 if value_type.len == 0 {
46 return none
47 }
48 return ArrayIndexInfo{
49 base_id: base_id
50 index_id: index_expr_id
51 base_type: base_type
52 value_type: value_type
53 }
54}
55
56// is_array_index_or_expr reports whether is array index or expr applies in transform.
57fn (mut t Transformer) is_array_index_or_expr(node flat.Node) bool {
58 if node.kind != .or_expr || node.children_count < 2 {
59 return false
60 }
61 _ := t.array_index_info(t.a.child(&node, 0)) or { return false }
62 return true
63}
64
65// transform_array_index_or_expr transforms transform array index or expr data for transform.
66fn (mut t Transformer) transform_array_index_or_expr(id flat.NodeId, node flat.Node) flat.NodeId {
67 if node.children_count < 2 {
68 return id
69 }
70 expr_id := t.a.child(&node, 0)
71 body_id := t.a.child(&node, 1)
72 info := t.array_index_info(expr_id) or { return id }
73 base_expr := t.stable_expr_for_reuse(info.base_id)
74 index_name := t.new_temp('arr_idx')
75 val_name := t.new_temp('arr_val')
76 outer_pending := t.pending_stmts.clone()
77 t.pending_stmts.clear()
78 index_expr := t.transform_expr(info.index_id)
79 mut prelude := []flat.NodeId{}
80 t.drain_pending(mut prelude)
81 prelude << t.make_decl_assign_typed(index_name, index_expr, 'int')
82 prelude << t.make_decl_assign_typed(val_name, t.zero_value_for_type(info.value_type),
83 info.value_type)
84
85 idx_ident := t.make_ident(index_name)
86 lower_ok := t.make_infix(.ge, idx_ident, t.make_int_literal(0))
87 upper_ok := t.make_infix(.lt, t.make_ident(index_name),
88 t.make_selector(base_expr, 'len', 'int'))
89 found_cond := t.make_infix(.logical_and, lower_ok, upper_ok)
90 index_value := t.make_index(base_expr, t.make_ident(index_name), info.value_type)
91 then_block := t.make_block(arr1(t.make_assign(t.make_ident(val_name), index_value)))
92 else_block := t.make_block(t.lower_or_body_to_stmts(body_id, val_name, info.value_type,
93 node.value, ''))
94 t.pending_stmts = outer_pending
95 for stmt in prelude {
96 t.pending_stmts << stmt
97 }
98 t.pending_stmts << t.make_if(found_cond, then_block, else_block)
99 return t.make_ident(val_name)
100}
101
102// or_body_is_nil supports or body is nil handling for Transformer.
103fn (t &Transformer) or_body_is_nil(body_id flat.NodeId) bool {
104 if int(body_id) < 0 {
105 return false
106 }
107 body := t.a.nodes[int(body_id)]
108 if body.kind == .nil_literal {
109 return true
110 }
111 if body.kind != .block || body.children_count != 1 {
112 return false
113 }
114 stmt_id := t.a.child(&body, 0)
115 stmt := t.a.nodes[int(stmt_id)]
116 if stmt.kind == .expr_stmt && stmt.children_count == 1 {
117 return t.a.nodes[int(t.a.child(&stmt, 0))].kind == .nil_literal
118 }
119 return stmt.kind == .nil_literal
120}
121
122// enum_from_string_info converts enum from string info data for transform.
123fn (t &Transformer) enum_from_string_info(expr_id flat.NodeId) ?EnumFromStringInfo {
124 if int(expr_id) < 0 {
125 return none
126 }
127 expr := t.a.nodes[int(expr_id)]
128 if expr.kind != .call || expr.children_count < 2 {
129 return none
130 }
131 fn_id := t.a.child(&expr, 0)
132 fn_node := t.a.nodes[int(fn_id)]
133 if fn_node.kind != .selector || fn_node.value != 'from_string' || fn_node.children_count == 0 {
134 return none
135 }
136 enum_id := t.a.child(&fn_node, 0)
137 enum_type := t.enum_type_from_node(enum_id) or { return none }
138 fields := t.enum_types[enum_type] or { return none }
139 if fields.len == 0 {
140 return none
141 }
142 return EnumFromStringInfo{
143 enum_type: enum_type
144 fields: fields.clone()
145 arg_id: t.a.child(&expr, 1)
146 }
147}
148
149// enum_type_from_node converts enum type from node data for transform.
150fn (t &Transformer) enum_type_from_node(id flat.NodeId) ?string {
151 if int(id) < 0 {
152 return none
153 }
154 node := t.a.nodes[int(id)]
155 if node.kind == .ident {
156 if node.value in t.enum_types {
157 return node.value
158 }
159 if t.cur_module.len > 0 && t.cur_module != 'main' && t.cur_module != 'builtin' {
160 qname := '${t.cur_module}.${node.value}'
161 if qname in t.enum_types {
162 return qname
163 }
164 }
165 for key, _ in t.enum_types {
166 if key.all_after_last('.') == node.value {
167 return key
168 }
169 }
170 }
171 if node.kind == .selector && node.children_count > 0 {
172 base := t.a.child_node(&node, 0)
173 if base.kind == .ident {
174 qname := '${base.value}.${node.value}'
175 if qname in t.enum_types {
176 return qname
177 }
178 }
179 }
180 return none
181}
182
183// is_enum_from_string_or_expr reports whether is enum from string or expr applies in transform.
184fn (mut t Transformer) is_enum_from_string_or_expr(node flat.Node) bool {
185 if node.kind != .or_expr || node.children_count < 2 {
186 return false
187 }
188 _ := t.enum_from_string_info(t.a.child(&node, 0)) or { return false }
189 return true
190}
191
192// transform_enum_from_string_or_expr supports transform_enum_from_string_or_expr handling.
193fn (mut t Transformer) transform_enum_from_string_or_expr(id flat.NodeId, node flat.Node) flat.NodeId {
194 if node.children_count < 2 {
195 return id
196 }
197 expr_id := t.a.child(&node, 0)
198 body_id := t.a.child(&node, 1)
199 info := t.enum_from_string_info(expr_id) or { return id }
200 str_name := t.new_temp('enum_str')
201 val_name := t.new_temp('enum_val')
202 outer_pending := t.pending_stmts.clone()
203 t.pending_stmts.clear()
204 arg_expr := t.transform_expr(info.arg_id)
205 mut prelude := []flat.NodeId{}
206 t.drain_pending(mut prelude)
207 prelude << t.make_decl_assign_typed(str_name, arg_expr, 'string')
208 prelude << t.make_decl_assign_typed(val_name, t.zero_value_for_type(info.enum_type),
209 info.enum_type)
210
211 mut else_block := t.make_block(t.lower_or_body_to_stmts(body_id, val_name, info.enum_type,
212 node.value, ''))
213 for i := info.fields.len - 1; i >= 0; i-- {
214 cond := t.make_call_typed('string__eq', arr2(t.make_ident(str_name),
215 t.make_string_literal(info.fields[i])), 'bool')
216 assign := t.make_assign(t.make_ident(val_name), t.make_int_literal(i))
217 then_block := t.make_block(arr1(assign))
218 else_block = t.make_if(cond, then_block, else_block)
219 }
220 t.pending_stmts = outer_pending
221 for stmt in prelude {
222 t.pending_stmts << stmt
223 }
224 t.pending_stmts << else_block
225 return t.make_ident(val_name)
226}
227
228// or_expr_types supports or expr types handling for Transformer.
229fn (t &Transformer) or_expr_types(expr_id flat.NodeId, fallback_type string) (string, string) {
230 if !isnil(t.tc) {
231 if typ := t.tc.expr_type(expr_id) {
232 if typ is types.OptionType {
233 base_name := t.value_type_name(typ.base_type)
234 source_name := if base_name == 'int' && typ.base_type is types.Void {
235 '?void'
236 } else {
237 '?${base_name}'
238 }
239 return source_name, base_name
240 }
241 if typ is types.ResultType {
242 base_name := t.value_type_name(typ.base_type)
243 source_name := if base_name == 'int' && typ.base_type is types.Void {
244 '!void'
245 } else {
246 '!${base_name}'
247 }
248 return source_name, base_name
249 }
250 }
251 }
252 mut expr_type := t.node_type(expr_id)
253 if expr_type.len == 0 || expr_type == 'Optional' {
254 if fallback_type.len > 0 && !t.is_optional_type_name(fallback_type) {
255 expr_type = '?${fallback_type}'
256 } else {
257 expr_type = fallback_type
258 }
259 }
260 base_type := t.optional_base_type(expr_type)
261 mut value_type := if base_type.len > 0 { base_type } else { fallback_type }
262 if value_type.len == 0 || value_type == 'void' || value_type == '!' || value_type == '?' {
263 value_type = 'int'
264 }
265 return expr_type, value_type
266}
267
268// value_type_name returns value type name data for Transformer.
269fn (t &Transformer) value_type_name(typ types.Type) string {
270 if typ is types.Void {
271 return 'void'
272 }
273 return typ.name()
274}
275
276// is_optional_type_name reports whether is optional type name applies in transform.
277fn (t &Transformer) is_optional_type_name(typ string) bool {
278 return typ.len > 0 && (typ[0] == `?` || typ[0] == `!`)
279}
280
281// qualify_optional_type supports qualify optional type handling for Transformer.
282fn (t &Transformer) qualify_optional_type(typ string) string {
283 if typ.len < 2 || (typ[0] != `?` && typ[0] != `!`) {
284 return typ
285 }
286 base := typ[1..]
287 if base.contains('.') || base.len == 0 {
288 return typ
289 }
290 qualified := t.qualify_type(base)
291 if qualified != base {
292 return typ[..1] + qualified
293 }
294 return typ
295}
296
297// qualify_type supports qualify type handling for Transformer.
298fn (t &Transformer) qualify_type(name string) string {
299 if name.contains('.') || name.len == 0 {
300 return name
301 }
302 if t.cur_module.len > 0 && t.cur_module != 'main' && t.cur_module != 'builtin' {
303 qname := '${t.cur_module}.${name}'
304 if qname in t.sum_types || qname in t.structs {
305 return qname
306 }
307 }
308 if qualified := t.qualified_types[name] {
309 return qualified
310 }
311 return name
312}
313
314// make_decl_assign_typed builds make decl assign typed data for transform.
315fn (mut t Transformer) make_decl_assign_typed(name string, rhs flat.NodeId, typ string) flat.NodeId {
316 decl := t.make_decl_assign(name, rhs)
317 if typ.len > 0 {
318 t.a.nodes[int(decl)].typ = typ
319 t.set_var_type(name, typ)
320 }
321 return decl
322}
323
324// zero_value_for_type supports zero value for type handling for Transformer.
325fn (mut t Transformer) zero_value_for_type(typ string) flat.NodeId {
326 mut clean := typ
327 if clean.starts_with('&') {
328 return t.a.add(.nil_literal)
329 }
330 if clean.len > 1 && (clean[0] == `?` || clean[0] == `!`) {
331 return t.make_optional_none(clean)
332 }
333 clean = t.normalize_type_alias(clean)
334 if clean.starts_with('fn(') || clean.starts_with('fn (') || clean.starts_with('fn_ptr:') {
335 return t.make_cast(clean, t.make_int_literal(0), clean)
336 }
337 if clean.starts_with('[]') {
338 return t.make_array_init(clean[2..])
339 }
340 if clean.starts_with('map[') {
341 return t.make_map_init(clean)
342 }
343 if clean == 'string' {
344 return t.make_string_literal('')
345 }
346 if clean == 'bool' {
347 return t.make_bool_literal(false)
348 }
349 if clean in ['f32', 'f64'] {
350 return t.make_float_literal('0.0')
351 }
352 if clean in ['void', ''] {
353 return t.make_int_literal(0)
354 }
355 if clean in ['int', 'i8', 'i16', 'i32', 'i64', 'isize', 'usize', 'u8', 'byte', 'u16', 'u32', 'u64', 'rune', 'char']
356 || clean in t.enum_types {
357 return t.make_int_literal(0)
358 }
359 return t.make_struct_init(clean)
360}
361
362// make_panic_stmt builds make panic stmt data for transform.
363fn (mut t Transformer) make_panic_stmt(message string) flat.NodeId {
364 call := t.make_call('panic', arr1(t.make_string_literal(message)))
365 return t.make_expr_stmt(call)
366}
367
368// make_none_return_stmt builds make none return stmt data for transform.
369fn (mut t Transformer) make_none_return_stmt() flat.NodeId {
370 return t.make_return(t.a.add(.none_expr), t.cur_fn_ret_type)
371}
372
373// make_none_return_stmt_with_err builds make none return stmt with err data for transform.
374fn (mut t Transformer) make_none_return_stmt_with_err(err_source string) flat.NodeId {
375 if err_source.len == 0 {
376 return t.make_none_return_stmt()
377 }
378 err_expr := t.make_selector(t.make_ident(err_source), 'err', 'IError')
379 return t.make_none_return_stmt_with_err_expr(err_expr)
380}
381
382fn (mut t Transformer) make_none_return_stmt_with_err_expr(err_expr flat.NodeId) flat.NodeId {
383 if int(err_expr) < 0 {
384 return t.make_none_return_stmt()
385 }
386 return t.make_return(t.make_optional_none_with_err(t.cur_fn_ret_type, err_expr),
387 t.cur_fn_ret_type)
388}
389
390// lower_or_expr_to_temp converts lower or expr to temp data for transform.
391fn (mut t Transformer) lower_or_expr_to_temp(id flat.NodeId, node flat.Node) flat.NodeId {
392 if node.children_count < 2 {
393 return id
394 }
395 expr_id := t.a.child(&node, 0)
396 body_id := t.a.child(&node, 1)
397 expr_type, value_type := t.or_expr_types(expr_id, node.typ)
398 if !t.is_optional_type_name(expr_type) {
399 return t.transform_expr(expr_id)
400 }
401 is_void := value_type.len == 0 || value_type == 'void'
402
403 opt_tmp := t.new_temp('or_opt')
404 val_tmp := t.new_temp('or_val')
405
406 outer_pending := t.pending_stmts.clone()
407 t.pending_stmts.clear()
408 new_expr := t.transform_expr(expr_id)
409 mut prelude := []flat.NodeId{}
410 t.drain_pending(mut prelude)
411
412 if is_void {
413 prelude << t.make_decl_assign_typed(opt_tmp, new_expr, expr_type)
414 opt_ident := t.make_ident(opt_tmp)
415 not_ok := t.make_prefix(.not, t.make_selector(opt_ident, 'ok', 'bool'))
416 else_block := t.make_block(t.lower_or_body_to_stmts(body_id, '', '', node.value, opt_tmp))
417 if_stmt := t.make_if(not_ok, else_block, t.make_empty())
418 t.pending_stmts = outer_pending
419 for stmt in prelude {
420 t.pending_stmts << stmt
421 }
422 t.pending_stmts << if_stmt
423 return t.make_int_literal(0)
424 }
425
426 prelude << t.make_decl_assign_typed(opt_tmp, new_expr, expr_type)
427 prelude << t.make_decl_assign_typed(val_tmp, t.zero_value_for_type(value_type), value_type)
428
429 opt_ident := t.make_ident(opt_tmp)
430 ok_cond := t.make_selector(opt_ident, 'ok', 'bool')
431 value_expr := t.make_selector(t.make_ident(opt_tmp), 'value', value_type)
432 then_assign := t.make_assign(t.make_ident(val_tmp), value_expr)
433 then_block := t.make_block(arr1(then_assign))
434 else_block := t.make_block(t.lower_or_body_to_stmts(body_id, val_tmp, value_type, node.value,
435 opt_tmp))
436 if_stmt := t.make_if(ok_cond, then_block, else_block)
437 t.pending_stmts = outer_pending
438 for stmt in prelude {
439 t.pending_stmts << stmt
440 }
441 t.pending_stmts << if_stmt
442 return t.make_ident(val_tmp)
443}
444
445// lower_or_body_to_stmts converts lower or body to stmts data for transform.
446fn (mut t Transformer) lower_or_body_to_stmts(body_id flat.NodeId, target_name string, target_type string, mode string, err_source string) []flat.NodeId {
447 err_expr := if err_source.len > 0 {
448 t.make_selector(t.make_ident(err_source), 'err', 'IError')
449 } else {
450 flat.empty_node
451 }
452 return t.lower_or_body_to_stmts_with_err_expr(body_id, target_name, target_type, mode, err_expr)
453}
454
455fn (mut t Transformer) lower_or_body_to_stmts_with_err_expr(body_id flat.NodeId, target_name string, target_type string, mode string, err_expr flat.NodeId) []flat.NodeId {
456 if mode == '!' || mode == '?' {
457 if t.is_optional_type_name(t.cur_fn_ret_type) {
458 return arr1(t.make_none_return_stmt_with_err_expr(err_expr))
459 }
460 return arr1(t.make_panic_stmt('option/result propagation failed'))
461 }
462 if int(body_id) < 0 {
463 return []flat.NodeId{}
464 }
465 body := t.a.nodes[int(body_id)]
466 if body.kind != .block {
467 if body.kind == .none_expr && t.is_optional_type_name(t.cur_fn_ret_type) {
468 return arr1(t.make_none_return_stmt())
469 }
470 if target_name.len == 0 {
471 value := t.transform_expr(body_id)
472 mut result := []flat.NodeId{}
473 t.drain_pending(mut result)
474 if t.node_type(body_id) != 'void' {
475 result << t.make_expr_stmt(value)
476 }
477 return result
478 }
479 return arr1(t.make_assign(t.make_ident(target_name), t.transform_expr(body_id)))
480 }
481 mut result := []flat.NodeId{}
482 if body.children_count == 0 {
483 return result
484 }
485 // The or-body is its own scope: `err` (and any locals it declares) are bound only
486 // for its lowering and restored afterwards, so the previous binding (e.g. an outer
487 // `err := 1`) survives and a subsequent `${err}` is not mis-typed as `IError`.
488 // Mirrors transform_if_guard_else_block.
489 saved_var_types := t.var_types.clone()
490 t.set_var_type('err', 'IError')
491 err_value := if int(err_expr) >= 0 {
492 err_expr
493 } else {
494 t.make_struct_init('IError')
495 }
496 result << t.make_decl_assign_typed('err', err_value, 'IError')
497 for i in 0 .. body.children_count {
498 child_id := t.a.child(&body, i)
499 child := t.a.nodes[int(child_id)]
500 is_last := i == body.children_count - 1
501 if is_last && child.kind == .expr_stmt && child.children_count > 0 {
502 inner_id := t.a.child(&child, 0)
503 inner := t.a.nodes[int(inner_id)]
504 if inner.kind == .call && t.is_noreturn_call(inner) {
505 expanded := t.transform_stmt(child_id)
506 t.drain_pending(mut result)
507 for eid in expanded {
508 result << eid
509 }
510 } else if inner.kind == .call && t.is_error_call(inner)
511 && t.is_optional_type_name(t.cur_fn_ret_type) {
512 result << t.make_return(inner_id, t.cur_fn_ret_type)
513 } else if inner.kind == .none_expr && t.is_optional_type_name(t.cur_fn_ret_type) {
514 result << t.make_none_return_stmt()
515 } else if t.node_type(inner_id) == 'void' {
516 expanded := t.transform_stmt(child_id)
517 t.drain_pending(mut result)
518 for eid in expanded {
519 result << eid
520 }
521 } else if target_name.len == 0 {
522 expanded := t.transform_stmt(child_id)
523 t.drain_pending(mut result)
524 for eid in expanded {
525 result << eid
526 }
527 } else {
528 value := if target_type in t.sum_types
529 || t.resolve_sum_name(target_type) in t.sum_types {
530 t.wrap_sum_value(inner_id, target_type)
531 } else {
532 t.transform_expr_for_type(inner_id, target_type)
533 }
534 t.drain_pending(mut result)
535 result << t.make_assign(t.make_ident(target_name), value)
536 }
537 } else {
538 expanded := t.transform_stmt(child_id)
539 t.drain_pending(mut result)
540 for eid in expanded {
541 result << eid
542 }
543 }
544 }
545 _ = target_type
546 t.var_types = saved_var_types
547 return result
548}
549
550fn (t &Transformer) is_error_call(node flat.Node) bool {
551 if node.kind != .call || node.children_count == 0 {
552 return false
553 }
554 fn_node := t.a.child_node(&node, 0)
555 return fn_node.value == 'error' || fn_node.value == 'error_with_code'
556}
557
558// is_noreturn_call reports whether is noreturn call applies in transform.
559fn (t &Transformer) is_noreturn_call(node flat.Node) bool {
560 if node.kind != .call || node.children_count == 0 {
561 return false
562 }
563 fn_node := t.a.child_node(&node, 0)
564 return fn_node.value in ['panic', 'exit']
565}
566