source: src/Validate/ImplementEnumFunc.cpp @ 048dde4

Last change on this file since 048dde4 was 90e683b, checked in by Andrew Beach <ajbeach@…>, 2 months ago

I set out to do a enum rework. It ended up being much the same and I unwound the core rework. But I hope the new names are a bit clearer and other minor fixes are helpful, so I am keeping those.

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