/
aliasing.d
249 lines (227 loc) · 7.53 KB
/
aliasing.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
module ast.aliasing;
import ast.base, ast.parse, ast.structure, ast.namespace, ast.properties,
tools.base: This, This_fn, rmSpace;
import dwarf2;
extern(C) Iterable convertLvToExpr(Iterable);
class ExprAlias : RelTransformable, Named, Expr {
Expr base;
string name;
mixin MyThis!("base, name"[]);
mixin DefaultDup!();
mixin defaultIterate!(base);
override {
string getIdentifier() { return name; }
Object transform(Expr relbase) {
Statement st;
if (auto sa = fastcast!(StatementAnd) (relbase)) {
st = sa.first;
relbase = sa.second;
}
void delegate(ref Iterable) dg;
auto it = fastcast!(Iterable) (base);
Expr finalize(Expr ex) {
if (!st) return ex;
return mkStatementAndExpr(st, ex);
}
bool needsTransform, needsExprConversion;
dg = (ref Iterable iter) {
iter.iterate(dg);
if (auto rt = fastcast!(RelTransformable) (iter)) {
if (fastcast!(CValue)(iter)) {
auto thing = rt.transform(relbase);
if (!fastcast!(CValue)(thing)) {
// logln("needs expr conversion because ", thing, " is not a cvalue while ", iter, " was:");
// logln(" ", it);
needsExprConversion = true;
}
}
needsTransform = true;
}
};
dg(it);
if (!needsTransform) return fastcast!(Object) (finalize(base));
it = it.dup;
if (needsExprConversion) it = convertLvToExpr(it);
dg = (ref Iterable iter) {
// logln("recurse[", needsExprConversion, "] ", iter);
iter.iterate(dg);
// logln("check[", needsExprConversion, "] ", iter);
if (auto rt = fastcast!(RelTransformable) (iter))
iter = fastcast!(Iterable) (rt.transform(relbase));
};
dg(it);
return fastcast!(Object) (finalize(fastcast!(Expr) (it)));
}
void emitLLVM(LLVMFile lf) {
fail; // Should never happen - the below foldopt should substitute them
base.emitLLVM(lf); // may work .. or not.
}
IType valueType() { return base.valueType(); }
string toString() {
return Format("expr-alias "[], name, ""[], " = "[], base);
}
}
}
class CValueAlias : ExprAlias, CValue {
mixin MyThis!("super(base, name)"[]);
override void emitLocation(LLVMFile lf) { (fastcast!(CValue)~ base).emitLocation(lf); }
override CValueAlias dup() { return fastalloc!(CValueAlias)(base.dup, name); }
}
final class LValueAlias : CValueAlias, LValue {
static const isFinal = true;
mixin MyThis!("super(base, name)"[]);
override LValueAlias dup() { return fastalloc!(LValueAlias)(base.dup, name); }
}
final class MValueAlias : ExprAlias, MValue {
static const isFinal = true;
mixin MyThis!("super(base, name)"[]);
void emitAssignment(LLVMFile lf) { (fastcast!(MValue)~ base).emitAssignment(lf); }
override MValueAlias dup() { return fastalloc!(MValueAlias)(base.dup, name); }
}
class _TypeAlias : Named, IType, SelfAdding, Dwarf2Encodable {
IType base;
bool strict;
string name;
override {
bool isComplete() {
// break circles
if (alreadyRecursing(this)) return true;
pushRecurse(this);
scope(exit) popRecurse();
return base.isComplete;
}
bool addsSelf() { return true; }
string getIdentifier() { return name; }
bool isPointerLess() { return base.isPointerLess(); }
string llvmType() { return base.llvmType(); }
string llvmSize() { return base.llvmSize(); }
string mangle() {
// breeak
if (alreadyRecursing(this)) return qformat("recursive_alias_", name.replace("-", "_dash_"));
pushRecurse(this); scope(exit) popRecurse();
return qformat("type_alias_", name.replace("-", "_dash_"), "_", base.mangle);
}
string toString() {
if (alreadyRecursing(this)) return qformat("recursive ", name);
pushRecurse(this); scope(exit) popRecurse();
return Format(name, ":", base);
}
int opEquals(IType ty) {
if (ty is this) return true;
if (alreadyRecursing(this, ty)) return true; // break loop
pushRecurse(this, ty); scope(exit) popRecurse();
auto ta2 = fastcast!(TypeAlias) (ty);
if (strict) {
if (!ta2) return false;
return name == ta2.name && base == ta2.base;
}
// try this first!
if (ta2 && name == ta2.name && base == ta2.base) return true;
// then fall back to resolved check
return resolveType(base).opEquals(resolveType(ty));
}
IType proxyType() { if (strict) return null; return base; }
bool canEncode() {
auto d2e = fastcast!(Dwarf2Encodable)(resolveType(base));
return d2e && d2e.canEncode();
}
Dwarf2Section encode(Dwarf2Controller dwarf2) {
return (fastcast!(Dwarf2Encodable) (resolveType(base))).encode(dwarf2);
}
}
}
final class TypeAlias : _TypeAlias {
static const isFinal = true;
mixin This!("base, name, strict = false"[]);
}
static this() {
foldopt ~= delegate Itr(Itr it) {
if (auto ea = fastcast!(ExprAlias) (it)) {
return fastcast!(Iterable) (ea.base.dup);
} else return null;
};
}
extern(C) IType resolveTup(IType, bool onlyIfChanged = false);
import ast.modules;
Object gotAlias(ref string text, ParseCb cont, ParseCb rest) {
auto t2 = text;
string id;
bool notDone;
redo:
Expr ex;
IType ty;
TypeAlias ta;
Object obj;
bool strict, raw;
if (t2.accept("strict"[])) strict = true;
if (t2.accept("raw"[])) raw = true;
if (!(t2.gotIdentifier(id) &&
t2.accept("="[])))
t2.failparse("Couldn't parse alias"[]);
auto t3 = t2;
bool gotTerm() {
if (t3.accept(";"[])) return true;
if (t3.accept(","[])) {
notDone = true;
return true;
}
return false;
}
if (rest(t3, "type"[], &ty) && gotTerm()) {
if (auto tup = resolveTup(ty, true)) ty = tup;
ta = fastalloc!(TypeAlias)(ty, id, strict);
t2 = t3;
} else {
t3 = t2;
string id2;
if (t3.gotIdentifier(id2, true) && gotTerm()) {
obj = namespace().lookup(id2);
if (obj) t2 = t3;
}
if (!obj) {
t3 = t2;
auto backup = *rawmode_loc.ptr();
if (raw) *rawmode_loc.ptr() = t3.ptr;
scope(exit) if (raw) *rawmode_loc.ptr() = backup;
if (rest(t3, "tree.expr"[], &obj) && gotTerm()) {
t2 = t3;
} else {
t2.failparse("Couldn't parse alias target"[]);
}
}
if (auto e = fastcast!(Expr) (obj)) { obj = null; ex = e; }
else {
namespace().__add(id, obj); // for instance, function alias
}
}
assert(ex || ta || obj);
text = t2;
auto cv = fastcast!(CValue)~ ex, mv = fastcast!(MValue)~ ex, lv = fastcast!(LValue)~ ex;
if (ex) {
if (strict) t2.failparse("no such thing as strict expr-alias"[]);
ExprAlias res;
if (lv) res = fastalloc!(LValueAlias)(lv, id);
else if (mv) res = fastalloc!(MValueAlias)(mv, id);
else if (cv) res = fastalloc!(CValueAlias)(cv, id);
else res = fastalloc!(ExprAlias)(ex, id);
namespace().add(res);
}
if (ta) namespace().add(ta);
if (notDone) {
notDone = false;
goto redo;
}
return Single!(NamedNull);
}
mixin DefaultParser!(gotAlias, "struct_member.struct_alias"[], null, "alias"[]);
mixin DefaultParser!(gotAlias, "tree.stmt.alias"[], "16"[], "alias"[]);
mixin DefaultParser!(gotAlias, "tree.toplevel.alias"[], null, "alias"[]);
import ast.casting;
static this() {
// type alias implicitly casts to parent type
implicits ~= delegate Expr(Expr ex) {
auto ta = fastcast!(TypeAlias) (ex.valueType());
if (!ta || !ta.strict) return null;
return reinterpret_cast(ta.base, ex);
};
}