source: src/Validate/ImplementEnumFunc.cpp @ 1e110bf

Last change on this file since 1e110bf was c2cf2d0, checked in by Andrew Beach <ajbeach@…>, 2 weeks ago

Made string literals constants. Preformed required updates. Resisted preforming large refactoring.

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