0
|
1 module dmd.expression.Cat;
|
|
2
|
|
3 import dmd.Type;
|
|
4 import dmd.Expression;
|
|
5 import dmd.Loc;
|
|
6 import dmd.TOK;
|
|
7 import dmd.StringExp;
|
|
8 import dmd.ArrayLiteralExp;
|
|
9 import dmd.Global;
|
|
10 import dmd.TY;
|
|
11 import dmd.Type;
|
|
12 import dmd.GlobalExpressions;
|
|
13 import dmd.ArrayTypes;
|
|
14 import dmd.TypeSArray;
|
|
15 import dmd.IntegerExp;
|
|
16
|
4
|
17 import core.memory;
|
2
|
18
|
0
|
19 import core.stdc.string;
|
|
20 import core.stdc.stdlib;
|
|
21
|
34
|
22 import std.exception;
|
0
|
23
|
|
24 /* Also return EXP_CANT_INTERPRET if this fails
|
|
25 */
|
|
26 Expression Cat(Type type, Expression e1, Expression e2)
|
|
27 {
|
|
28 Expression e = EXP_CANT_INTERPRET;
|
|
29 Loc loc = e1.loc;
|
|
30
|
|
31 Type t;
|
|
32
|
|
33 Type t1 = e1.type.toBasetype();
|
|
34 Type t2 = e2.type.toBasetype();
|
|
35
|
|
36 //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
|
|
37 //printf("\tt1 = %s, t2 = %s\n", t1.toChars(), t2.toChars());
|
|
38
|
|
39 if (e1.op == TOKnull && (e2.op == TOKint64 || e2.op == TOKstructliteral))
|
|
40 {
|
|
41 e = e2;
|
|
42 goto L2;
|
|
43 }
|
|
44 else if ((e1.op == TOKint64 || e1.op == TOKstructliteral) && e2.op == TOKnull)
|
|
45 {
|
|
46 e = e1;
|
|
47 L2:
|
|
48 Type tn = e.type.toBasetype();
|
|
49 if (tn.ty == Tchar || tn.ty == Twchar || tn.ty == Tdchar)
|
|
50 {
|
|
51 // Create a StringExp
|
|
52 size_t len = 1;
|
|
53 int sz = cast(int)tn.size();
|
|
54 ulong v = e.toInteger();
|
|
55
|
2
|
56 char* s = cast(char*)GC.malloc((len + 1) * sz);
|
0
|
57 memcpy(s, &v, sz);
|
|
58
|
|
59 // Add terminating 0
|
|
60 memset(s + len * sz, 0, sz);
|
|
61
|
|
62 StringExp es = new StringExp(loc, assumeUnique(s[0..len]));
|
|
63 es.sz = cast(ubyte)sz;
|
|
64 es.committed = 1;
|
|
65 e = es;
|
|
66 }
|
|
67 else
|
|
68 {
|
|
69 // Create an ArrayLiteralExp
|
|
70 Expressions elements = new Expressions();
|
|
71 elements.push(cast(void*)e);
|
|
72 e = new ArrayLiteralExp(e.loc, elements);
|
|
73 }
|
|
74 e.type = type;
|
|
75 return e;
|
|
76 }
|
|
77 else if (e1.op == TOKstring && e2.op == TOKstring)
|
|
78 {
|
|
79 // Concatenate the strings
|
|
80 StringExp es1 = cast(StringExp)e1;
|
|
81 StringExp es2 = cast(StringExp)e2;
|
|
82
|
|
83 size_t len = es1.len + es2.len;
|
|
84 int sz = es1.sz;
|
|
85
|
|
86 if (sz != es2.sz)
|
|
87 {
|
|
88 /* Can happen with:
|
|
89 * auto s = "foo"d ~ "bar"c;
|
|
90 */
|
|
91 assert(global.errors);
|
|
92 return e;
|
|
93 }
|
|
94
|
2
|
95 char* s = cast(char*)GC.malloc((len + 1) * sz);
|
0
|
96 memcpy(s, es1.string_, es1.len * sz);
|
|
97 memcpy(s + es1.len * sz, es2.string_, es2.len * sz);
|
|
98
|
|
99 // Add terminating 0
|
|
100 memset(s + len * sz, 0, sz);
|
|
101
|
|
102 StringExp es = new StringExp(loc, assumeUnique(s[0..len]));
|
|
103 es.sz = cast(ubyte)sz;
|
|
104 es.committed = es1.committed | es2.committed;
|
|
105
|
|
106 Type tt;
|
|
107 if (es1.committed)
|
|
108 tt = es1.type;
|
|
109 else
|
|
110 tt = es2.type;
|
|
111
|
|
112 es.type = type;
|
|
113 e = es;
|
|
114 }
|
|
115 else if (e1.op == TOKstring && e2.op == TOKint64)
|
|
116 {
|
|
117 // Concatenate the strings
|
|
118 StringExp es1 = cast(StringExp)e1;
|
|
119 size_t len = es1.len + 1;
|
|
120 int sz = es1.sz;
|
|
121 ulong v = e2.toInteger();
|
|
122
|
2
|
123 char* s = cast(char*)GC.malloc((len + 1) * sz);
|
0
|
124 memcpy(s, es1.string_, es1.len * sz);
|
|
125 memcpy(s + es1.len * sz, &v, sz);
|
|
126
|
|
127 // Add terminating 0
|
|
128 memset(s + len * sz, 0, sz);
|
|
129
|
|
130 StringExp es = new StringExp(loc, assumeUnique(s[0..len]));
|
|
131 es.sz = cast(ubyte)sz;
|
|
132 es.committed = es1.committed;
|
|
133 Type tt = es1.type;
|
|
134 es.type = type;
|
|
135 e = es;
|
|
136 }
|
|
137 else if (e1.op == TOKint64 && e2.op == TOKstring)
|
|
138 {
|
|
139 // Concatenate the strings
|
|
140 StringExp es2 = cast(StringExp)e2;
|
|
141 size_t len = 1 + es2.len;
|
|
142 int sz = es2.sz;
|
|
143 ulong v = e1.toInteger();
|
|
144
|
2
|
145 char* s = cast(char*)GC.malloc((len + 1) * sz);
|
0
|
146 memcpy(s, &v, sz);
|
|
147 memcpy(s + sz, es2.string_, es2.len * sz);
|
|
148
|
|
149 // Add terminating 0
|
|
150 memset(s + len * sz, 0, sz);
|
|
151
|
|
152 StringExp es = new StringExp(loc, assumeUnique(s[0..len]));
|
|
153 es.sz = cast(ubyte)sz;
|
|
154 es.committed = es2.committed;
|
|
155 Type tt = es2.type;
|
|
156 es.type = type;
|
|
157 e = es;
|
|
158 }
|
|
159 else if (e1.op == TOKarrayliteral && e2.op == TOKarrayliteral &&
|
|
160 t1.nextOf().equals(t2.nextOf()))
|
|
161 {
|
|
162 // Concatenate the arrays
|
|
163 ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
|
|
164 ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
|
|
165
|
|
166 es1 = new ArrayLiteralExp(es1.loc, cast(Expressions)es1.elements.copy());
|
|
167 es1.elements.insert(es1.elements.dim, es2.elements);
|
|
168 e = es1;
|
|
169
|
|
170 if (type.toBasetype().ty == Tsarray)
|
|
171 {
|
|
172 e.type = new TypeSArray(t1.nextOf(), new IntegerExp(loc, es1.elements.dim, Type.tindex));
|
|
173 e.type = e.type.semantic(loc, null);
|
|
174 }
|
|
175 else
|
|
176 e.type = type;
|
|
177 }
|
|
178 else if (e1.op == TOKarrayliteral && e2.op == TOKnull &&
|
|
179 t1.nextOf().equals(t2.nextOf()))
|
|
180 {
|
|
181 e = e1;
|
|
182 goto L3;
|
|
183 }
|
|
184 else if (e1.op == TOKnull && e2.op == TOKarrayliteral &&
|
|
185 t1.nextOf().equals(t2.nextOf()))
|
|
186 {
|
|
187 e = e2;
|
|
188 L3:
|
|
189 // Concatenate the array with null
|
|
190 ArrayLiteralExp es = cast(ArrayLiteralExp)e;
|
|
191
|
|
192 es = new ArrayLiteralExp(es.loc, cast(Expressions)es.elements.copy());
|
|
193 e = es;
|
|
194
|
|
195 if (type.toBasetype().ty == Tsarray)
|
|
196 {
|
|
197 e.type = new TypeSArray(t1.nextOf(), new IntegerExp(loc, es.elements.dim, Type.tindex));
|
|
198 e.type = e.type.semantic(loc, null);
|
|
199 }
|
|
200 else
|
|
201 e.type = type;
|
|
202 }
|
|
203 else if ((e1.op == TOKarrayliteral || e1.op == TOKnull) &&
|
|
204 e1.type.toBasetype().nextOf().equals(e2.type))
|
|
205 {
|
|
206 ArrayLiteralExp es1;
|
|
207 if (e1.op == TOKarrayliteral)
|
|
208 { es1 = cast(ArrayLiteralExp)e1;
|
|
209 es1 = new ArrayLiteralExp(es1.loc, cast(Expressions)es1.elements.copy());
|
|
210 es1.elements.push(cast(void*)e2);
|
|
211 }
|
|
212 else
|
|
213 {
|
|
214 es1 = new ArrayLiteralExp(e1.loc, e2);
|
|
215 }
|
|
216 e = es1;
|
|
217
|
|
218 if (type.toBasetype().ty == Tsarray)
|
|
219 {
|
|
220 e.type = new TypeSArray(e2.type, new IntegerExp(loc, es1.elements.dim, Type.tindex));
|
|
221 e.type = e.type.semantic(loc, null);
|
|
222 }
|
|
223 else
|
|
224 e.type = type;
|
|
225 }
|
|
226 else if (e2.op == TOKarrayliteral &&
|
|
227 e2.type.toBasetype().nextOf().equals(e1.type))
|
|
228 {
|
|
229 ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
|
|
230
|
|
231 es2 = new ArrayLiteralExp(es2.loc, cast(Expressions)es2.elements.copy());
|
|
232 es2.elements.shift(cast(void*)e1);
|
|
233 e = es2;
|
|
234
|
|
235 if (type.toBasetype().ty == Tsarray)
|
|
236 {
|
|
237 e.type = new TypeSArray(e1.type, new IntegerExp(loc, es2.elements.dim, Type.tindex));
|
|
238 e.type = e.type.semantic(loc, null);
|
|
239 }
|
|
240 else
|
|
241 e.type = type;
|
|
242 }
|
|
243 else if (e1.op == TOKnull && e2.op == TOKstring)
|
|
244 {
|
|
245 t = e1.type;
|
|
246 e = e2;
|
|
247 goto L1;
|
|
248 }
|
|
249 else if (e1.op == TOKstring && e2.op == TOKnull)
|
|
250 {
|
|
251 e = e1;
|
|
252 t = e2.type;
|
|
253 L1:
|
|
254 Type tb = t.toBasetype();
|
|
255 if (tb.ty == Tarray && tb.nextOf().equals(e.type))
|
|
256 {
|
|
257 Expressions expressions = new Expressions();
|
|
258 expressions.push(cast(void*)e);
|
|
259 e = new ArrayLiteralExp(loc, expressions);
|
|
260 e.type = t;
|
|
261 }
|
|
262 if (!e.type.equals(type))
|
|
263 {
|
|
264 StringExp se = cast(StringExp)e.copy();
|
|
265 e = se.castTo(null, type);
|
|
266 }
|
|
267 }
|
|
268 return e;
|
|
269 } |