source: src/Validate/ImplementEnumFunc.cpp @ 658f3179

Last change on this file since 658f3179 was 35cc6d4, checked in by Michael Brooks <mlbrooks@…>, 7 weeks ago

Mitigate several unused-declaration warnings in generated code.

See tests/nowarn/unused for the specific cases.

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