source: src/Validate/ImplementEnumFunc.cpp@ fc276f3

Last change on this file since fc276f3 was ed96731, checked in by Andrew Beach <ajbeach@…>, 10 months ago

With{Stmts,Decls}ToAdd how has an -X version like WithSymbolTableX. Although these -X versions might be useful can could possibly be removed in the future. (This is a therapy commit.)

  • 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.