source: src/Validate/ImplementEnumFunc.cpp@ 89da3a9

Last change on this file since 89da3a9 was fc1a3e2, checked in by Andrew Beach <ajbeach@…>, 17 months ago

Style update. Focused on indentation and trailing whitespace.

  • 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.h" // for isCtorDtor, isCtorDtorAssign
5#include "InitTweak/InitTweak.h" // 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
30 void genAttrFunctions();
31 void genSuccPredPosn();
32 void genSuccPredDecl();
33
34 void appendReturnThis(ast::FunctionDecl* decl) {
35 assert(1 <= decl->params.size());
36 assert(1 == decl->returns.size());
37 assert(decl->stmts);
38
39 const CodeLocation& location = (decl->stmts->kids.empty())
40 ? decl->stmts->location
41 : decl->stmts->kids.back()->location;
42 const ast::DeclWithType* thisParam = decl->params.front();
43 decl->stmts.get_and_mutate()->push_back(new ast::ReturnStmt(
44 location, new ast::VariableExpr(location, thisParam)));
45 }
46 void genAttrStandardFuncs() {
47 ast::FunctionDecl* (EnumAttrFuncGenerator::*standardProtos[4])()
48 const = {&EnumAttrFuncGenerator::genCtorProto,
49 &EnumAttrFuncGenerator::genCopyProto,
50 &EnumAttrFuncGenerator::genDtorProto,
51 &EnumAttrFuncGenerator::genAssignProto};
52 for (auto& generator : standardProtos) {
53 ast::FunctionDecl* decl = (this->*generator)();
54 produceForwardDecl(decl);
55 genFuncBody(decl);
56 if (CodeGen::isAssignment(decl->name)) {
57 appendReturnThis(decl);
58 }
59 produceDecl(decl);
60 }
61 }
62
63private:
64 const CodeLocation& getLocation() const { return decl->location; }
65
66 ast::FunctionDecl* genProto(
67 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
68 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
69
70 void produceDecl(const ast::FunctionDecl* decl);
71 void produceForwardDecl(const ast::FunctionDecl* decl);
72
73 const ast::Decl* getDecl() const { return decl; }
74
75 ast::FunctionDecl* genPosnProto() const;
76 ast::FunctionDecl* genLabelProto() const;
77 ast::FunctionDecl* genValueProto() const;
78 ast::FunctionDecl* genSuccProto() const;
79 ast::FunctionDecl* genPredProto() const;
80
81 ast::FunctionDecl* genSuccPosProto() const;
82 ast::FunctionDecl* genPredPosProto() const;
83
84 // ---------------------------------------------------
85 // ast::FunctionDecl* genAttrCtorProto() const;
86 /// Changes the node inside a pointer so that it has the unused attribute.
87 void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
88 ast::DeclWithType* decl = declPtr.get_and_mutate();
89 decl->attributes.push_back(new ast::Attribute("unused"));
90 }
91
92 ast::ObjectDecl* dstParam() const {
93 return new ast::ObjectDecl(getLocation(), "_dst",
94 new ast::ReferenceType(new ast::EnumAttrType(
95 ast::deepCopy(instType))));
96 }
97
98 ast::ObjectDecl* srcParam() const {
99 return new ast::ObjectDecl(
100 getLocation(), "_src",
101 new ast::EnumAttrType(ast::deepCopy(instType)));
102 }
103
104 /// E = EnumAttrType<T>`
105 /// `void ?{}(E & _dst)`.
106 ast::FunctionDecl* genCtorProto() const {
107 return genProto("?{}", {dstParam()}, {});
108 }
109
110 /// void ?{}(E & _dst, E _src)`.
111 ast::FunctionDecl* genCopyProto() const {
112 return genProto("?{}", {dstParam(), srcParam()}, {});
113 }
114
115 ///`void ^?{}(E & _dst)`.
116 ast::FunctionDecl* genDtorProto() const {
117 // The destructor must be mutex on a concurrent type.
118 return genProto("^?{}", {dstParam()}, {});
119 }
120
121 /// `E ?{}(E & _dst, E _src)`.
122 ast::FunctionDecl* genAssignProto() const {
123 // Only the name is different, so just reuse the generation function.
124 auto retval = srcParam();
125 retval->name = "_ret";
126 return genProto("?=?", {dstParam(), srcParam()}, {retval});
127 }
128
129 void genFuncBody(ast::FunctionDecl* func) {
130 const CodeLocation& location = func->location;
131 auto& params = func->params;
132 if (InitTweak::isCopyConstructor(func) ||
133 InitTweak::isAssignment(func)) {
134 assert(2 == params.size());
135 auto dstParam = params.front().strict_as<ast::ObjectDecl>();
136 auto srcParam = params.back().strict_as<ast::ObjectDecl>();
137 func->stmts = genCopyBody(location, dstParam, srcParam);
138 } else {
139 assert(1 == params.size());
140 // Default constructor and destructor is empty.
141 func->stmts = new ast::CompoundStmt(location);
142 // Add unused attribute to parameter to silence warnings.
143 addUnusedAttribute(params.front());
144
145 // Just an extra step to make the forward and declaration match.
146 if (forwards.empty()) return;
147 ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
148 forwards.back().get_and_mutate());
149 addUnusedAttribute(fwd->params.front());
150 }
151 }
152
153 const ast::CompoundStmt* genCopyBody( const CodeLocation& location,
154 const ast::ObjectDecl* dstParam, const ast::ObjectDecl* srcParam) {
155 return new ast::CompoundStmt(
156 location,
157 {new ast::ExprStmt(
158 location,
159 new ast::UntypedExpr(
160 location, new ast::NameExpr(location, "__builtin_memcpy"),
161 {
162 new ast::AddressExpr( location,
163 new ast::VariableExpr( location, dstParam ) ),
164 new ast::AddressExpr( location,
165 new ast::VariableExpr( location, srcParam ) ),
166 new ast::SizeofExpr( location, srcParam->type ),
167 }))});
168 }
169
170 void genDtorBody(ast::FunctionDecl* func) {
171 const CodeLocation& location = func->location;
172 auto& params = func->params;
173 assert(1 == params.size());
174 func->stmts = new ast::CompoundStmt(location);
175 addUnusedAttribute(params.front());
176
177 // Just an extra step to make the forward and declaration match.
178 if (forwards.empty()) return;
179 ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
180 forwards.back().get_and_mutate());
181 addUnusedAttribute(fwd->params.front());
182 }
183
184 // ast::FunctionDecl*
185 // ----------------------------------------------------
186
187 ast::FunctionDecl* genSuccPredFunc(bool succ);
188
189 const ast::Init* getAutoInit(const ast::Init* prev) const;
190
191 std::vector<ast::ptr<ast::Init>> genLabelInit() const;
192
193 std::vector<ast::ptr<ast::Init>> genValueInit() const;
194 ast::ObjectDecl* genAttrArrayProto(
195 const ast::EnumAttribute attr, const CodeLocation& location,
196 std::vector<ast::ptr<ast::Init>>& inits) const;
197 void genValueOrLabelBody(
198 ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
199 void genPosnBody(ast::FunctionDecl* func) const;
200 void genAttributesDecls(const ast::EnumAttribute attr);
201};
202
203std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
204 std::vector<ast::ptr<ast::Init>> inits;
205 for (size_t i = 0; i < decl->members.size(); i++) {
206 ast::ptr<ast::Decl> mem = decl->members.at(i);
207 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
208 assert(memAsObjectDecl);
209 inits.emplace_back(new ast::SingleInit(
210 mem->location,
211 ast::ConstantExpr::from_string(mem->location, mem->name)));
212 }
213 return inits;
214}
215
216std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
217 std::vector<ast::ptr<ast::Init>> inits;
218 for (size_t i = 0; i < decl->members.size(); i++) {
219 ast::ptr<ast::Decl> mem = decl->members.at(i);
220 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
221 assert(memAsObjectDecl);
222 if (memAsObjectDecl->init) {
223 inits.emplace_back(memAsObjectDecl->init);
224 } else {
225 const CodeLocation& location = mem->location;
226 if (i == 0) {
227 inits.emplace_back(new ast::SingleInit(
228 location, ast::ConstantExpr::from_int(mem->location, 0)));
229 } else {
230 inits.emplace_back(getAutoInit(inits.at(i - 1)));
231 }
232 }
233 }
234 return inits;
235}
236const ast::Init* EnumAttrFuncGenerator::getAutoInit(
237 const ast::Init* prev) const {
238 if (prev == nullptr) {
239 return new ast::SingleInit(
240 getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
241 }
242 auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
243 assert(prevInit);
244 auto prevInitExpr = prevInit->value;
245 if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
246 // Assume no string literal for now
247 return new ast::SingleInit(
248 getLocation(), ast::ConstantExpr::from_int(
249 getLocation(), constInit->intValue() + 1));
250 } else {
251 auto untypedThisInit = new ast::UntypedExpr(
252 getLocation(), new ast::NameExpr(getLocation(), "?++"),
253 {prevInitExpr});
254 return new ast::SingleInit(getLocation(), untypedThisInit);
255 }
256}
257
258ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
259 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
260 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
261 ast::FunctionDecl* decl = new ast::FunctionDecl(
262 // Auto-generated routines use the type declaration's location.
263 getLocation(), std::move(name), {}, {}, std::move(params),
264 std::move(returns),
265 // Only a prototype, no body.
266 nullptr,
267 // Use static storage if we are at the top level.
268 (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
269 proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
270 // Auto-generated routines are inline to avoid conflicts.
271 ast::Function::Specs(ast::Function::Inline));
272 decl->fixUniqueId();
273 return decl;
274}
275
276void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
277 assert(nullptr != decl->stmts);
278
279 definitions.push_back(decl);
280}
281
282void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
283 if (0 != functionNesting) return;
284 ast::FunctionDecl* fwd =
285 (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
286 fwd->fixUniqueId();
287 forwards.push_back(fwd);
288}
289
290ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
291 return genProto(
292 "posE",
293 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
294 {new ast::ObjectDecl(getLocation(), "_ret",
295 new ast::BasicType(ast::BasicKind::UnsignedInt))});
296}
297
298ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
299 return genProto(
300 "labelE",
301 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
302 {new ast::ObjectDecl(
303 getLocation(), "_ret",
304 new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
305}
306
307ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
308 return genProto(
309 "valueE",
310 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
311 {new ast::ObjectDecl(getLocation(), "_ret",
312 ast::deepCopy(decl->base))});
313}
314
315ast::FunctionDecl* EnumAttrFuncGenerator::genSuccProto() const {
316 return genProto(
317 "succ",
318 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
319 {new ast::ObjectDecl(getLocation(), "_ret",
320 new ast::EnumInstType(decl))});
321}
322
323ast::FunctionDecl* EnumAttrFuncGenerator::genPredProto() const {
324 return genProto(
325 "pred",
326 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
327 {new ast::ObjectDecl(getLocation(), "_ret",
328 new ast::EnumInstType(decl))});
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::FunctionDecl* EnumAttrFuncGenerator::genSuccPosProto() const {
336 return genProto(
337 "_successor_",
338 {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
339 {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
340 );
341}
342
343ast::FunctionDecl* EnumAttrFuncGenerator::genPredPosProto() const {
344 return genProto(
345 "_predessor_",
346 {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
347 {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
348 );
349}
350
351ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
352 const ast::EnumAttribute attr, const CodeLocation& location,
353 std::vector<ast::ptr<ast::Init>>& inits) const {
354 ast::ArrayType* arrT = new ast::ArrayType(
355 attr == ast::EnumAttribute::Value
356 ? decl->base
357 : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
358 ast::ConstantExpr::from_int(decl->location, decl->members.size()),
359 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
360
361 ast::ObjectDecl* objDecl =
362 new ast::ObjectDecl(
363 decl->location, decl->getUnmangeldArrayName( attr ),
364 arrT, new ast::ListInit( location, std::move( inits ) ),
365 ast::Storage::Static, ast::Linkage::AutoGen );
366
367 return objDecl;
368}
369
370void EnumAttrFuncGenerator::genValueOrLabelBody(
371 ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
372 ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
373 func->location, "?[?]",
374 {new ast::NameExpr(func->location, arrDecl->name),
375 new ast::CastExpr(
376 func->location,
377 new ast::VariableExpr( func->location, func->params.front() ),
378 new ast::EnumAttrType( new ast::EnumInstType(decl),
379 ast::EnumAttribute::Posn))});
380 func->stmts = new ast::CompoundStmt(
381 func->location, {new ast::ReturnStmt(func->location, untyped)});
382}
383
384void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
385 auto castExpr = new ast::CastExpr(
386 func->location,
387 new ast::VariableExpr(func->location, func->params.front()),
388 new ast::EnumAttrType(new ast::EnumInstType(decl),
389 ast::EnumAttribute::Posn));
390 func->stmts = new ast::CompoundStmt(
391 func->location, {new ast::ReturnStmt(func->location, castExpr)});
392}
393
394void EnumAttrFuncGenerator::genAttributesDecls(const ast::EnumAttribute attr) {
395 if (attr == ast::EnumAttribute::Value ||
396 attr == ast::EnumAttribute::Label) {
397 std::vector<ast::ptr<ast::Init>> inits =
398 attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
399 ast::ObjectDecl* arrayProto =
400 genAttrArrayProto(attr, getLocation(), inits);
401 forwards.push_back(arrayProto);
402
403 ast::FunctionDecl* funcProto = ( attr == ast::EnumAttribute::Value )
404 ? genValueProto()
405 : genLabelProto();
406 produceForwardDecl(funcProto);
407 genValueOrLabelBody(funcProto, arrayProto);
408 produceDecl(funcProto);
409 } else {
410 ast::FunctionDecl* funcProto = genPosnProto();
411 produceForwardDecl(funcProto);
412 genPosnBody(funcProto);
413 produceDecl(funcProto);
414 }
415}
416
417ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPredFunc(bool succ) {
418 ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
419 produceForwardDecl(funcDecl);
420
421 const CodeLocation& location = getLocation();
422
423 auto& params = funcDecl->params;
424 assert(params.size() == 1);
425 auto param = params.front().strict_as<ast::ObjectDecl>();
426
427
428 auto rets = funcDecl->returns;
429 assert(params.size() == 1);
430 auto ret = rets.front().strict_as<ast::ObjectDecl>();
431 auto retType = ret->type.strict_as<ast::EnumAttrType>();
432
433 auto addOneExpr = ast::UntypedExpr::createCall( location,
434 succ? "?+?": "?-?",
435 {new ast::VariableExpr(location, param),
436 ast::ConstantExpr::from_int(location, 1)}
437 );
438
439 funcDecl->stmts = new ast::CompoundStmt(
440 location, {
441 new ast::ReturnStmt(
442 location,
443 new ast::CastExpr(location, addOneExpr, retType)
444 )
445 }
446 );
447
448 return funcDecl;
449}
450
451void EnumAttrFuncGenerator::genAttrFunctions() {
452 if (decl->base) {
453 genAttributesDecls(ast::EnumAttribute::Value);
454 genAttributesDecls(ast::EnumAttribute::Label);
455 genAttributesDecls(ast::EnumAttribute::Posn);
456 }
457}
458
459void EnumAttrFuncGenerator::genSuccPredDecl() {
460 if (decl->base) {
461 auto succProto = genSuccProto();
462 auto predProto = genPredProto();
463
464 produceForwardDecl(succProto);
465 produceForwardDecl(predProto);
466 }
467}
468
469void EnumAttrFuncGenerator::genSuccPredPosn() {
470 if (decl->base) {
471 ast::FunctionDecl* succ = genSuccPredFunc(true);
472 ast::FunctionDecl* pred = genSuccPredFunc(false);
473
474 produceDecl(succ);
475 produceDecl(pred);
476 }
477}
478
479void EnumAttrFuncGenerator::generateAndAppendFunctions(
480 std::list<ast::ptr<ast::Decl>>& decls) {
481 // Generate the functions (they go into forwards and definitions).
482 genAttrStandardFuncs();
483 genAttrFunctions();
484 genSuccPredDecl();
485 genSuccPredPosn(); // Posn
486 // Now export the lists contents.
487 decls.splice(decls.end(), forwards);
488 decls.splice(decls.end(), definitions);
489}
490
491// ---------------------------------------------------------
492
493struct ImplementEnumFunc final :
494 public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting {
495 void previsit(const ast::EnumDecl* enumDecl);
496 void previsit(const ast::FunctionDecl* functionDecl);
497 void postvisit(const ast::FunctionDecl* functionDecl);
498
499private:
500 // Current level of nested functions.
501 unsigned int functionNesting = 0;
502};
503
504void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
505 if (!enumDecl->body) return;
506 if (!enumDecl->base) return;
507
508 ast::EnumInstType enumInst(enumDecl->name);
509 enumInst.base = enumDecl;
510
511 EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
512 gen.generateAndAppendFunctions(declsToAddAfter);
513}
514
515void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
516 functionNesting += 1;
517}
518
519void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
520 functionNesting -= 1;
521}
522
523} // namespace
524
525void implementEnumFunc(ast::TranslationUnit& translationUnit) {
526 ast::Pass<ImplementEnumFunc>::run(translationUnit);
527}
528
529} // namespace Validate
Note: See TracBrowser for help on using the repository browser.