source: src/Validate/ImplementEnumFunc.cpp@ cdb4eaa

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

Fix Enum predecessor

  • Property mode set to 100644
File size: 19.5 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 return new ast::CompoundStmt(
159 location,
160 {new ast::ExprStmt(
161 location,
162 new ast::UntypedExpr(
163 location, new ast::NameExpr(location, "__builtin_memcpy"),
164 {
165 new ast::AddressExpr(location, new ast::VariableExpr(
166 location, dstParam)),
167 new ast::AddressExpr(location, new ast::VariableExpr(
168 location, srcParam)),
169 new ast::SizeofExpr(location, srcParam->type),
170 }))});
171 }
172
173 void genDtorBody(ast::FunctionDecl* func) {
174 const CodeLocation& location = func->location;
175 auto& params = func->params;
176 assert(1 == params.size());
177 func->stmts = new ast::CompoundStmt(location);
178 addUnusedAttribute(params.front());
179
180 // Just an extra step to make the forward and declaration match.
181 if (forwards.empty()) return;
182 ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
183 forwards.back().get_and_mutate());
184 addUnusedAttribute(fwd->params.front());
185 }
186
187 // ast::FunctionDecl*
188 // ----------------------------------------------------
189
190 ast::FunctionDecl* genSuccPredFunc(bool succ);
191
192 const ast::Init* getAutoInit(const ast::Init* prev) const;
193
194 std::vector<ast::ptr<ast::Init>> genLabelInit() const;
195
196 std::vector<ast::ptr<ast::Init>> genValueInit() const;
197 ast::ObjectDecl* genAttrArrayProto(
198 const ast::EnumAttribute attr, const CodeLocation& location,
199 std::vector<ast::ptr<ast::Init>>& inits) const;
200 void genValueOrLabelBody(ast::FunctionDecl* func,
201 ast::ObjectDecl* arrDecl) const;
202 void genPosnBody(ast::FunctionDecl* func) const;
203 void genAttributesDecls(const ast::EnumAttribute attr);
204};
205
206std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
207 std::vector<ast::ptr<ast::Init>> inits;
208 for (size_t i = 0; i < decl->members.size(); i++) {
209 ast::ptr<ast::Decl> mem = decl->members.at(i);
210 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
211 assert(memAsObjectDecl);
212 inits.emplace_back(new ast::SingleInit(
213 mem->location,
214 ast::ConstantExpr::from_string(mem->location, mem->name)));
215 }
216 return inits;
217}
218
219std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
220 std::vector<ast::ptr<ast::Init>> inits;
221 for (size_t i = 0; i < decl->members.size(); i++) {
222 ast::ptr<ast::Decl> mem = decl->members.at(i);
223 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
224 assert(memAsObjectDecl);
225 if (memAsObjectDecl->init) {
226 inits.emplace_back(memAsObjectDecl->init);
227 } else {
228 const CodeLocation& location = mem->location;
229 if (i == 0) {
230 inits.emplace_back(new ast::SingleInit(
231 location, ast::ConstantExpr::from_int(mem->location, 0)));
232 } else {
233 inits.emplace_back(getAutoInit(inits.at(i - 1)));
234 }
235 }
236 }
237 return inits;
238}
239const ast::Init* EnumAttrFuncGenerator::getAutoInit(
240 const ast::Init* prev) const {
241 if (prev == nullptr) {
242 return new ast::SingleInit(
243 getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
244 }
245 auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
246 assert(prevInit);
247 auto prevInitExpr = prevInit->value;
248 if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
249 // Assume no string literal for now
250 return new ast::SingleInit(
251 getLocation(), ast::ConstantExpr::from_int(
252 getLocation(), constInit->intValue() + 1));
253 } else {
254 auto untypedThisInit = new ast::UntypedExpr(
255 getLocation(), new ast::NameExpr(getLocation(), "?++"),
256 {prevInitExpr});
257 return new ast::SingleInit(getLocation(), untypedThisInit);
258 }
259}
260
261ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
262 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
263 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
264 ast::FunctionDecl* decl = new ast::FunctionDecl(
265 // Auto-generated routines use the type declaration's location.
266 getLocation(), std::move(name), {}, {}, std::move(params),
267 std::move(returns),
268 // Only a prototype, no body.
269 nullptr,
270 // Use static storage if we are at the top level.
271 (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
272 proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
273 // Auto-generated routines are inline to avoid conflicts.
274 ast::Function::Specs(ast::Function::Inline));
275 decl->fixUniqueId();
276 return decl;
277}
278
279void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
280 assert(nullptr != decl->stmts);
281
282 definitions.push_back(decl);
283}
284
285void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
286 if (0 != functionNesting) return;
287 ast::FunctionDecl* fwd =
288 (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
289 fwd->fixUniqueId();
290 forwards.push_back(fwd);
291}
292
293ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
294 return genProto(
295 "posE",
296 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
297 {new ast::ObjectDecl(getLocation(), "_ret",
298 new ast::EnumAttrType(new ast::EnumInstType(decl),
299 ast::EnumAttribute::Posn))});
300}
301
302ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
303 return genProto(
304 "labelE",
305 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
306 {new ast::ObjectDecl(
307 getLocation(), "_ret",
308 new ast::PointerType(new ast::BasicType{ast::BasicType::Char}))});
309}
310
311ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
312 return genProto(
313 "valueE",
314 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
315 {new ast::ObjectDecl(getLocation(), "_ret",
316 ast::deepCopy(decl->base))});
317}
318
319ast::FunctionDecl* EnumAttrFuncGenerator::genSuccProto() const {
320 return genProto(
321 "succ",
322 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
323 {new ast::ObjectDecl(getLocation(), "_ret",
324 new ast::EnumInstType(decl))});
325}
326
327ast::FunctionDecl* EnumAttrFuncGenerator::genPredProto() const {
328 return genProto(
329 "pred",
330 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
331 {new ast::ObjectDecl(getLocation(), "_ret",
332 new ast::EnumInstType(decl))});
333}
334
335inline ast::EnumAttrType * getPosnType( const ast::EnumDecl * decl ) {
336 return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
337}
338
339ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPosProto() const {
340 return genProto(
341 "_successor_",
342 {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
343 {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
344 );
345}
346
347ast::FunctionDecl* EnumAttrFuncGenerator::genPredPosProto() const {
348 return genProto(
349 "_predessor_",
350 {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
351 {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
352 );
353}
354
355ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
356 const ast::EnumAttribute attr, const CodeLocation& location,
357 std::vector<ast::ptr<ast::Init>>& inits) const {
358 ast::ArrayType* arrT = new ast::ArrayType(
359 attr == ast::EnumAttribute::Value
360 ? decl->base
361 : new ast::PointerType(new ast::BasicType{ast::BasicType::Char}),
362 ast::ConstantExpr::from_int(decl->location, decl->members.size()),
363 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
364
365 ast::ObjectDecl* objDecl =
366 new ast::ObjectDecl(decl->location, decl->getUnmangeldArrayName(attr),
367 arrT, new ast::ListInit(location, std::move(inits)),
368 ast::Storage::Static, ast::Linkage::AutoGen);
369
370 return objDecl;
371}
372
373void EnumAttrFuncGenerator::genValueOrLabelBody(
374 ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
375 ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
376 func->location, "?[?]",
377 {new ast::NameExpr(func->location, arrDecl->name),
378 new ast::CastExpr(
379 func->location,
380 new ast::VariableExpr(func->location, func->params.front()),
381 new ast::EnumAttrType(new ast::EnumInstType(decl),
382 ast::EnumAttribute::Posn))});
383 func->stmts = new ast::CompoundStmt(
384 func->location, {new ast::ReturnStmt(func->location, untyped)});
385}
386
387void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
388 auto castExpr = new ast::CastExpr(
389 func->location,
390 new ast::VariableExpr(func->location, func->params.front()),
391 new ast::EnumAttrType(new ast::EnumInstType(decl),
392 ast::EnumAttribute::Posn));
393 func->stmts = new ast::CompoundStmt(
394 func->location, {new ast::ReturnStmt(func->location, castExpr)});
395}
396
397void EnumAttrFuncGenerator::genAttributesDecls(const ast::EnumAttribute attr) {
398 if (attr == ast::EnumAttribute::Value ||
399 attr == ast::EnumAttribute::Label) {
400 std::vector<ast::ptr<ast::Init>> inits =
401 attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
402 ast::ObjectDecl* arrayProto =
403 genAttrArrayProto(attr, getLocation(), inits);
404 forwards.push_back(arrayProto);
405
406 ast::FunctionDecl* funcProto = attr == ast::EnumAttribute::Value
407 ? genValueProto()
408 : genLabelProto();
409 produceForwardDecl(funcProto);
410 genValueOrLabelBody(funcProto, arrayProto);
411 produceDecl(funcProto);
412 } else {
413 ast::FunctionDecl* funcProto = genPosnProto();
414 produceForwardDecl(funcProto);
415 genPosnBody(funcProto);
416 produceDecl(funcProto);
417 }
418}
419
420ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPredFunc(bool succ) {
421 ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
422 produceForwardDecl(funcDecl);
423
424 const CodeLocation& location = getLocation();
425
426 auto& params = funcDecl->params;
427 assert(params.size() == 1);
428 auto param = params.front().strict_as<ast::ObjectDecl>();
429
430
431 auto rets = funcDecl->returns;
432 assert(params.size() == 1);
433 auto ret = rets.front().strict_as<ast::ObjectDecl>();
434 auto retType = ret->type.strict_as<ast::EnumAttrType>();
435
436 auto addOneExpr = ast::UntypedExpr::createCall( location,
437 succ? "?+?": "?-?",
438 {new ast::VariableExpr(location, param),
439 ast::ConstantExpr::from_int(location, 1)}
440 );
441
442 funcDecl->stmts = new ast::CompoundStmt(
443 location, {
444 new ast::ReturnStmt(
445 location,
446 new ast::CastExpr(location, addOneExpr, retType)
447 )
448 }
449 );
450
451 return funcDecl;
452}
453
454void EnumAttrFuncGenerator::genAttrFunctions() {
455 if (decl->base) {
456 genAttributesDecls(ast::EnumAttribute::Value);
457 genAttributesDecls(ast::EnumAttribute::Label);
458 genAttributesDecls(ast::EnumAttribute::Posn);
459 }
460}
461
462void EnumAttrFuncGenerator::genSuccPredDecl() {
463 if (decl->base) {
464 auto succProto = genSuccProto();
465 auto predProto = genPredProto();
466
467 produceForwardDecl(succProto);
468 produceForwardDecl(predProto);
469 }
470}
471
472void EnumAttrFuncGenerator::genSuccPredPosn() {
473 if (decl->base) {
474 ast::FunctionDecl* succ = genSuccPredFunc(true);
475 ast::FunctionDecl* pred = genSuccPredFunc(false);
476
477 produceDecl(succ);
478 produceDecl(pred);
479 }
480}
481
482void EnumAttrFuncGenerator::generateAndAppendFunctions(
483 std::list<ast::ptr<ast::Decl>>& decls) {
484 // Generate the functions (they go into forwards and definitions).
485 genAttrStandardFuncs();
486 genAttrFunctions();
487 genSuccPredDecl();
488 genSuccPredPosn(); // Posn
489 // Now export the lists contents.
490 decls.splice(decls.end(), forwards);
491 decls.splice(decls.end(), definitions);
492}
493
494// ---------------------------------------------------------
495
496struct ImplementEnumFunc final : public ast::WithDeclsToAdd<>,
497 public ast::WithShortCircuiting {
498 void previsit(const ast::EnumDecl* enumDecl);
499 void previsit(const ast::FunctionDecl* functionDecl);
500 void postvisit(const ast::FunctionDecl* functionDecl);
501
502 private:
503 // Current level of nested functions.
504 unsigned int functionNesting = 0;
505};
506
507void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
508 if (!enumDecl->body) return;
509 if (!enumDecl->base) return;
510
511 ast::EnumInstType enumInst(enumDecl->name);
512 enumInst.base = enumDecl;
513
514 EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
515 gen.generateAndAppendFunctions(declsToAddAfter);
516}
517
518void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
519 functionNesting += 1;
520}
521
522void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
523 functionNesting -= 1;
524}
525
526} // namespace
527
528void implementEnumFunc(ast::TranslationUnit& translationUnit) {
529 ast::Pass<ImplementEnumFunc>::run(translationUnit);
530}
531} // namespace Validate
Note: See TracBrowser for help on using the repository browser.