source: src/Validate/ImplementEnumFunc.cpp@ fbe3f03

Last change on this file since fbe3f03 was dc58e5d, checked in by JiadaL <j82liang@…>, 18 months ago

Small cleanup

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