vxx2 / vlib / v3 / gen / c / str_intp.v
101 lines · 96 sloc · 2.87 KB · 2b81918e62db9ab38787518603a7f93bee80868c
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 g.gen_map_str_expr(child_id, typ) {
42 // emitted by gen_map_str_expr
43 } else if typ_name == 'IError' || typ_name.ends_with('.IError') {
44 // IError may resolve as Interface/Alias/Struct depending on context; match by
45 // name and interpolate its `.message` (mirrors the transformer's IError path).
46 g.gen_expr(child_id)
47 g.write('.message')
48 } else if typ is types.Primitive {
49 prim_name := types.Type(typ).name()
50 g.write('${c_name('${prim_name}.str')}(')
51 g.gen_expr(child_id)
52 g.write(')')
53 } else if typ is types.ISize || typ is types.USize {
54 g.write('${c_name('${typ.name()}.str')}(')
55 g.gen_expr(child_id)
56 g.write(')')
57 } else if typ is types.Struct {
58 g.write('${c_name(typ.name)}__str(')
59 g.gen_expr(child_id)
60 g.write(')')
61 } else if typ is types.SumType {
62 g.write('${c_name(typ.name)}__str(')
63 g.gen_expr(child_id)
64 g.write(')')
65 } else {
66 g.write('int__str(')
67 g.gen_expr(child_id)
68 g.write(')')
69 }
70 }
71 }
72 g.write('})')
73}
74
75// is_string_node reports whether is string node applies in c.
76fn (g &FlatGen) is_string_node(id flat.NodeId) bool {
77 return g.tc.resolve_type(id) is types.String
78}
79
80// string_literals supports string literals handling for FlatGen.
81fn (mut g FlatGen) string_literals() {
82 for i, s in g.str_lits {
83 escaped := s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\t',
84 '\\t').replace('\r', '\\r')
85 g.writeln('string _str_${i} = {"${escaped}", ${s.len}, 1};')
86 }
87 if g.str_lits.len > 0 {
88 g.writeln('')
89 }
90}
91
92// intern_string supports intern string handling for FlatGen.
93fn (mut g FlatGen) intern_string(s string) int {
94 if s in g.str_lit_ids {
95 return g.str_lit_ids[s]
96 }
97 id := g.str_lits.len
98 g.str_lits << s
99 g.str_lit_ids[s] = id
100 return id
101}
102