source: src/Validate/ImplementEnumFunc.cpp@ 2c8946b

Last change on this file since 2c8946b was c92bdcc, checked in by Andrew Beach <ajbeach@…>, 17 months ago

Updated the rest of the names in src/ (except for the generated files).

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