source: src/Validate/ImplementEnumFunc.cpp@ 0dffe91

Last change on this file since 0dffe91 was 90be0cf, checked in by Andrew Beach <ajbeach@…>, 11 months ago

Moved some methods out of EnumDecl. These were calculations and the ast types are supposed to be data focused so they should either go with utility functions or to their use site. I tried the use site.

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