source: src/Validate/ImplementEnumFunc.cpp@ f06ba98

Last change on this file since f06ba98 was c2cf2d0, checked in by Andrew Beach <ajbeach@…>, 15 months ago

Made string literals constants. Preformed required updates. Resisted preforming large refactoring.

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