source: src/Validate/ImplementEnumFunc.cpp @ d0296db6

Last change on this file since d0296db6 was 90be0cf, checked in by Andrew Beach <ajbeach@…>, 4 weeks ago

Moved some methods out of EnumDecl?. These were calculations and the ast types are supposed to be data focused so they should either go with utility functions or to their use site. I tried the use site.

  • 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(), "_i", 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.