source: src/Validate/ImplementEnumFunc.cpp@ 1967109

Last change on this file since 1967109 was 822332e, checked in by Andrew Beach <ajbeach@…>, 16 months ago

It seems clang uses different scoping rules for the trailing return of a scoped runction declaration. This form seems compatable with clang and gcc. Since I switched over to clang for testing I also cleaned up all errors that clang or gcc mentioned.

  • Property mode set to 100644
File size: 14.3 KB
Line 
1#include "AST/Create.hpp"
2#include "AST/Pass.hpp"
3#include "AST/TranslationUnit.hpp"
4#include "CodeGen/OperatorTable.hpp" // for isCtorDtor, isCtorDtorAssign
5#include "InitTweak/InitTweak.hpp" // for isAssignment, isCopyConstructor
6namespace Validate {
7
8namespace {
9class EnumAttrFuncGenerator {
10 const ast::EnumDecl* decl;
11 unsigned int functionNesting;
12 ast::Linkage::Spec proto_linkage;
13
14public:
15 std::list<ast::ptr<ast::Decl>> forwards;
16 std::list<ast::ptr<ast::Decl>> definitions;
17
18 void generateAndAppendFunctions(std::list<ast::ptr<ast::Decl>>&);
19
20 EnumAttrFuncGenerator(
21 const ast::EnumDecl* decl,
22 const ast::EnumInstType*,
23 unsigned int functionNesting )
24 : decl(decl),
25 functionNesting{functionNesting},
26 proto_linkage{ast::Linkage::Cforall} {}
27
28private:
29 const CodeLocation& getLocation() const { return decl->location; }
30
31 ast::FunctionDecl* genProto(
32 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
33 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
34
35 void produceDecl(const ast::FunctionDecl* decl);
36 void produceForwardDecl(const ast::FunctionDecl* decl);
37
38 const ast::Decl* getDecl() const { return decl; }
39
40 // Implement Bounded trait
41 void genBoundedFunctions();
42 ast::FunctionDecl* genBoundedProto(const char *) const;
43 void genBoundedBody(ast::FunctionDecl* func) const;
44
45 // Implement Serial trait
46 void genSerialTraitFuncs();
47 ast::FunctionDecl* genFromIntProto() const;
48 ast::FunctionDecl* genFromInstanceProto() const;
49 ast::FunctionDecl* genInstToInstFuncProto(const char* func) const;
50 void genFromIntBody(ast::FunctionDecl *) const;
51 void genFromInstanceBody(ast::FunctionDecl *) const;
52 void genSuccPredBody(ast::FunctionDecl *, const char *) const;
53
54 // Implement TypedEnum trait
55 void genTypedEnumFuncs();
56 void genTypedEnumFunction(const ast::EnumAttribute attr);
57 ast::FunctionDecl* genPosnProto() const;
58 ast::FunctionDecl* genLabelProto() const;
59 ast::FunctionDecl* genValueProto() const;
60 void genValueOrLabelBody(
61 ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
62 void genPosnBody(ast::FunctionDecl* func) const;
63
64 ////////////////
65
66 // ---------------------------------------------------
67 // ast::FunctionDecl* genAttrCtorProto() const;
68 /// Changes the node inside a pointer so that it has the unused attribute.
69 void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
70 ast::DeclWithType* decl = declPtr.get_and_mutate();
71 decl->attributes.push_back(new ast::Attribute("unused"));
72 }
73
74 // ----------------------------------------------------
75
76 const ast::Init* getAutoInit(const ast::Init* prev) const;
77
78 std::vector<ast::ptr<ast::Init>> genLabelInit() const;
79
80 std::vector<ast::ptr<ast::Init>> genValueInit() const;
81 ast::ObjectDecl* genAttrArrayProto(
82 const ast::EnumAttribute attr, const CodeLocation& location,
83 std::vector<ast::ptr<ast::Init>>& inits) const;
84};
85
86std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
87 std::vector<ast::ptr<ast::Init>> inits;
88 for (size_t i = 0; i < decl->members.size(); i++) {
89 ast::ptr<ast::Decl> mem = decl->members.at(i);
90 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
91 assert(memAsObjectDecl);
92 inits.emplace_back(new ast::SingleInit(
93 mem->location,
94 ast::ConstantExpr::from_string(mem->location, mem->name)));
95 }
96 return inits;
97}
98
99std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
100 std::vector<ast::ptr<ast::Init>> inits;
101 for (size_t i = 0; i < decl->members.size(); i++) {
102 ast::ptr<ast::Decl> mem = decl->members.at(i);
103 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
104 assert(memAsObjectDecl);
105 if (memAsObjectDecl->init) {
106 inits.emplace_back(memAsObjectDecl->init);
107 } else {
108 const CodeLocation& location = mem->location;
109 if (i == 0) {
110 inits.emplace_back(new ast::SingleInit(
111 location, ast::ConstantExpr::from_int(mem->location, 0)));
112 } else {
113 inits.emplace_back(getAutoInit(inits.at(i - 1)));
114 }
115 }
116 }
117 return inits;
118}
119const ast::Init* EnumAttrFuncGenerator::getAutoInit(
120 const ast::Init* prev) const {
121 if (prev == nullptr) {
122 return new ast::SingleInit(
123 getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
124 }
125 auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
126 assert(prevInit);
127 auto prevInitExpr = prevInit->value;
128 if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
129 // Assume no string literal for now
130 return new ast::SingleInit(
131 getLocation(), ast::ConstantExpr::from_int(
132 getLocation(), constInit->intValue() + 1));
133 } else {
134 auto untypedThisInit = new ast::UntypedExpr(
135 getLocation(), new ast::NameExpr(getLocation(), "?++"),
136 {prevInitExpr});
137 return new ast::SingleInit(getLocation(), untypedThisInit);
138 }
139}
140
141ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
142 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
143 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
144 ast::FunctionDecl* decl = new ast::FunctionDecl(
145 // Auto-generated routines use the type declaration's location.
146 getLocation(), std::move(name), {}, {}, std::move(params),
147 std::move(returns),
148 // Only a prototype, no body.
149 nullptr,
150 // Use static storage if we are at the top level.
151 (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
152 proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
153 // Auto-generated routines are inline to avoid conflicts.
154 ast::Function::Specs(ast::Function::Inline));
155 decl->fixUniqueId();
156 return decl;
157}
158
159void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
160 assert(nullptr != decl->stmts);
161
162 definitions.push_back(decl);
163}
164
165void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
166 if (0 != functionNesting) return;
167 ast::FunctionDecl* fwd =
168 (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
169 fwd->fixUniqueId();
170 forwards.push_back(fwd);
171}
172
173ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
174 return genProto(
175 "posE",
176 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
177 {new ast::ObjectDecl(getLocation(), "_ret",
178 new ast::BasicType(ast::BasicKind::UnsignedInt))});
179}
180
181ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
182 return genProto(
183 "labelE",
184 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
185 {new ast::ObjectDecl(
186 getLocation(), "_ret",
187 new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
188}
189
190ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
191 return genProto(
192 "valueE",
193 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
194 {new ast::ObjectDecl(getLocation(), "_ret",
195 ast::deepCopy(decl->base))});
196}
197
198ast::FunctionDecl* EnumAttrFuncGenerator::genFromIntProto() const {
199 return genProto(
200 "fromInt",
201 {new ast::ObjectDecl(getLocation(), "_i", new ast::BasicType(ast::BasicKind::UnsignedInt))},
202 {new ast::ObjectDecl(getLocation(), "_ret", new ast::EnumInstType(decl))}
203 );
204}
205
206ast::FunctionDecl* EnumAttrFuncGenerator::genFromInstanceProto() const {
207 return genProto(
208 "fromInstance",
209 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
210 {new ast::ObjectDecl(getLocation(), "_ret", new ast::BasicType(ast::BasicKind::UnsignedInt))}
211 );
212}
213
214void EnumAttrFuncGenerator::genFromIntBody(ast::FunctionDecl* func) const {
215 auto params = func->params;
216 assert( params.size() == 1 );
217 auto param = params.front();
218 auto castExpr = new ast::CastExpr(
219 func->location,
220 new ast::VariableExpr(func->location, param),
221 new ast::EnumInstType(decl),
222 ast::GeneratedFlag::ExplicitCast
223 );
224 func->stmts = new ast::CompoundStmt(
225 func->location, {new ast::ReturnStmt(func->location, castExpr)}
226 );
227}
228
229void EnumAttrFuncGenerator::genFromInstanceBody(ast::FunctionDecl* func) const {
230 auto params = func->params;
231 assert( params.size() == 1 );
232 auto param = params.front();
233 ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
234 func->location, "posE", { new ast::VariableExpr(func->location, param) });
235 func->stmts = new ast::CompoundStmt(
236 func->location, {new ast::ReturnStmt(func->location, untyped)}
237 );
238}
239
240void EnumAttrFuncGenerator::genSuccPredBody(ast::FunctionDecl * func, const char* opt) const {
241 auto params = func->params;
242 assert( params.size() == 1 );
243 auto param = params.front();
244 auto enumToInt = new ast::CastExpr(
245 func->location,
246 new ast::VariableExpr(func->location, param),
247 new ast::BasicType(ast::BasicKind::UnsignedInt),
248 ast::GeneratedFlag::ExplicitCast
249 );
250 ast::UntypedExpr* addOneExpr = ast::UntypedExpr::createCall( func->location,
251 opt,
252 {enumToInt,
253 ast::ConstantExpr::from_int(func->location, 1)}
254 );
255 auto intToEnum = new ast::CastExpr(
256 func->location,
257 addOneExpr,
258 new ast::EnumInstType( decl ),
259 ast::GeneratedFlag::ExplicitCast
260 );
261 func->stmts = new ast::CompoundStmt(
262 func->location, {
263 new ast::ReturnStmt(
264 func->location,
265 intToEnum
266 )
267 }
268 );
269}
270
271
272void EnumAttrFuncGenerator::genSerialTraitFuncs() {
273 ast::FunctionDecl * protos[4] = {
274 genFromIntProto(),
275 genFromInstanceProto(),
276 genInstToInstFuncProto("succ"),
277 genInstToInstFuncProto("pred")
278 };
279 for (auto& proto: protos) produceForwardDecl(proto);
280 genFromIntBody(protos[0]);
281 genFromInstanceBody(protos[1]);
282 genSuccPredBody(protos[2], "?+?");
283 genSuccPredBody(protos[3], "?-?");
284 for (auto& proto: protos) produceDecl(proto);
285}
286
287ast::FunctionDecl* EnumAttrFuncGenerator::genInstToInstFuncProto(const char * func) const {
288 return genProto(
289 func,
290 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
291 {new ast::ObjectDecl(getLocation(), "_ret",
292 new ast::EnumInstType(decl))});
293}
294
295ast::FunctionDecl* EnumAttrFuncGenerator::genBoundedProto(const char * func) const {
296 return genProto(func, {}, {
297 new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))
298 });
299}
300
301void EnumAttrFuncGenerator::genBoundedBody(ast::FunctionDecl* func) const {
302 const CodeLocation & loc = func->location;
303 auto mem = func->name=="lowerBound"? decl->members.front() : decl->members.back();
304 auto expr = new ast::NameExpr( loc, mem->name );
305 func->stmts = new ast::CompoundStmt( loc, {new ast::ReturnStmt(loc, expr)});
306}
307
308void EnumAttrFuncGenerator::genBoundedFunctions() {
309 ast::FunctionDecl * boundedProtos[2] = {genBoundedProto("upperBound"), genBoundedProto("lowerBound")};
310 for (auto & protos: boundedProtos) {
311 produceForwardDecl(protos);
312 genBoundedBody(protos);
313 produceDecl(protos);
314 }
315}
316
317ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
318 const ast::EnumAttribute attr, const CodeLocation& location,
319 std::vector<ast::ptr<ast::Init>>& inits) const {
320 ast::ArrayType* arrT = new ast::ArrayType(
321 attr == ast::EnumAttribute::Value
322 ? decl->base
323 : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
324 ast::ConstantExpr::from_int(decl->location, decl->members.size()),
325 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
326
327 ast::ObjectDecl* objDecl =
328 new ast::ObjectDecl(
329 decl->location, decl->getUnmangeldArrayName( attr ),
330 arrT, new ast::ListInit( location, std::move( inits ) ),
331 ast::Storage::Static, ast::Linkage::AutoGen );
332
333 return objDecl;
334}
335
336void EnumAttrFuncGenerator::genValueOrLabelBody(
337 ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
338 ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
339 func->location, "?[?]",
340 {new ast::NameExpr(func->location, arrDecl->name),
341 new ast::CastExpr(
342 func->location,
343 new ast::VariableExpr( func->location, func->params.front() ),
344 new ast::BasicType( ast::BasicKind::UnsignedInt ),
345 ast::GeneratedFlag::ExplicitCast
346 )});
347 func->stmts = new ast::CompoundStmt(
348 func->location, {new ast::ReturnStmt(func->location, untyped)});
349}
350
351void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
352 auto castExpr = new ast::CastExpr(
353 func->location,
354 new ast::VariableExpr(func->location, func->params.front()),
355 new ast::BasicType( ast::BasicKind::UnsignedInt ),
356 ast::GeneratedFlag::ExplicitCast);
357 func->stmts = new ast::CompoundStmt(
358 func->location, {new ast::ReturnStmt(func->location, castExpr)});
359}
360
361void EnumAttrFuncGenerator::genTypedEnumFunction(const ast::EnumAttribute attr) {
362 if (attr == ast::EnumAttribute::Value ||
363 attr == ast::EnumAttribute::Label) {
364 // TypedEnum's backing arrays
365 std::vector<ast::ptr<ast::Init>> inits =
366 attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
367 ast::ObjectDecl* arrayProto =
368 genAttrArrayProto(attr, getLocation(), inits);
369 forwards.push_back(arrayProto);
370
371 ast::FunctionDecl* funcProto = ( attr == ast::EnumAttribute::Value )
372 ? genValueProto()
373 : genLabelProto();
374 produceForwardDecl(funcProto);
375 genValueOrLabelBody(funcProto, arrayProto);
376 produceDecl(funcProto);
377 } else {
378 ast::FunctionDecl* funcProto = genPosnProto();
379 produceForwardDecl(funcProto);
380 genPosnBody(funcProto);
381 produceDecl(funcProto);
382 }
383}
384
385void EnumAttrFuncGenerator::genTypedEnumFuncs() {
386 if (decl->base) genTypedEnumFunction(ast::EnumAttribute::Value);
387 genTypedEnumFunction(ast::EnumAttribute::Label);
388 genTypedEnumFunction(ast::EnumAttribute::Posn);
389}
390
391void EnumAttrFuncGenerator::generateAndAppendFunctions(
392 std::list<ast::ptr<ast::Decl>>& decls) {
393 // Generate the functions (they go into forwards and definitions).
394 genTypedEnumFuncs();
395 genSerialTraitFuncs();
396 genBoundedFunctions();
397 // Now export the lists contents.
398 decls.splice(decls.end(), forwards);
399 decls.splice(decls.end(), definitions);
400}
401
402// ---------------------------------------------------------
403
404struct ImplementEnumFunc final :
405 public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting {
406 void previsit(const ast::EnumDecl* enumDecl);
407 void previsit(const ast::FunctionDecl* functionDecl);
408 void postvisit(const ast::FunctionDecl* functionDecl);
409
410private:
411 // Current level of nested functions.
412 unsigned int functionNesting = 0;
413};
414
415void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
416 if (!enumDecl->body || !enumDecl->isTyped) return;
417 ast::EnumInstType enumInst(enumDecl->name);
418 enumInst.base = enumDecl;
419 EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
420 gen.generateAndAppendFunctions(declsToAddAfter);
421}
422
423void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
424 functionNesting += 1;
425}
426
427void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
428 functionNesting -= 1;
429}
430
431} // namespace
432
433void implementEnumFunc(ast::TranslationUnit& translationUnit) {
434 ast::Pass<ImplementEnumFunc>::run(translationUnit);
435}
436
437} // namespace Validate
Note: See TracBrowser for help on using the repository browser.