v4 / vlib / v3 / gen / c / str_intp.v
99 lines · 94 sloc · 2.79 KB · 351709f1031b64c6175612e9e459d8216eeca7f5
Raw
1module c
2
3import v3.flat
4import v3.types
5
6// gen_string_interp emits string interp output for c.
7fn (mut g FlatGen) gen_string_interp(node flat.Node) {
8 n := node.children_count
9 if n == 0 {
10 sid := g.intern_string('')
11 g.write('_str_${sid}')
12 return
13 }
14 g.write('string_plus_many(${n}, (string[${n}]){')
15 for i in 0 .. n {
16 if i > 0 {
17 g.write(', ')
18 }
19 child_id := g.a.child(&node, i)
20 child := g.a.nodes[int(child_id)]
21 if child.kind == .string_literal {
22 sid := g.intern_string(child.value)
23 g.write('_str_${sid}')
24 } else if child.typ == 'string' {
25 g.gen_expr(child_id)
26 } else {
27 mut typ := g.tc.resolve_type(child_id)
28 // For a bare ident, prefer the live cgen scope binding when present: it reflects
29 // locals introduced during generation (e.g. the `err` of an or-body lowered here,
30 // or for-loop vars) that resolve_type may stale-cache as `int`.
31 if child.kind == .ident {
32 if scope_typ := g.tc.cur_scope.lookup(child.value) {
33 if scope_typ !is types.Void {
34 typ = scope_typ
35 }
36 }
37 }
38 typ_name := types.Type(typ).name()
39 if typ is types.String {
40 g.gen_expr(child_id)
41 } else if typ_name == 'IError' || typ_name.ends_with('.IError') {
42 // IError may resolve as Interface/Alias/Struct depending on context; match by
43 // name and interpolate its `.message` (mirrors the transformer's IError path).
44 g.gen_expr(child_id)
45 g.write('.message')
46 } else if typ is types.Primitive {
47 prim_name := types.Type(typ).name()
48 g.write('${c_name('${prim_name}.str')}(')
49 g.gen_expr(child_id)
50 g.write(')')
51 } else if typ is types.ISize || typ is types.USize {
52 g.write('${c_name('${typ.name()}.str')}(')
53 g.gen_expr(child_id)
54 g.write(')')
55 } else if typ is types.Struct {
56 g.write('${c_name(typ.name)}__str(')
57 g.gen_expr(child_id)
58 g.write(')')
59 } else if typ is types.SumType {
60 g.write('${c_name(typ.name)}__str(')
61 g.gen_expr(child_id)
62 g.write(')')
63 } else {
64 g.write('int__str(')
65 g.gen_expr(child_id)
66 g.write(')')
67 }
68 }
69 }
70 g.write('})')
71}
72
73// is_string_node reports whether is string node applies in c.
74fn (g &FlatGen) is_string_node(id flat.NodeId) bool {
75 return g.tc.resolve_type(id) is types.String
76}
77
78// string_literals supports string literals handling for FlatGen.
79fn (mut g FlatGen) string_literals() {
80 for i, s in g.str_lits {
81 escaped := s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\t',
82 '\\t').replace('\r', '\\r')
83 g.writeln('string _str_${i} = {"${escaped}", ${s.len}, 1};')
84 }
85 if g.str_lits.len > 0 {
86 g.writeln('')
87 }
88}
89
90// intern_string supports intern string handling for FlatGen.
91fn (mut g FlatGen) intern_string(s string) int {
92 if s in g.str_lit_ids {
93 return g.str_lit_ids[s]
94 }
95 id := g.str_lits.len
96 g.str_lits << s
97 g.str_lit_ids[s] = id
98 return id
99}
100