source: src/Validate/ImplementEnumFunc.cpp @ c333ed2

Last change on this file since c333ed2 was c333ed2, checked in by JiadaL <j82liang@…>, 2 months ago

Remove intermeidate type (enum attribute type); remove replacePseudoFunc (has been migrated to resolver)

  • Property mode set to 100644
File size: 14.9 KB
Line 
1#include "AST/Create.hpp"
2#include "AST/Pass.hpp"
3#include "AST/TranslationUnit.hpp"
4#include "CodeGen/OperatorTable.h"  // for isCtorDtor, isCtorDtorAssign
5#include "InitTweak/InitTweak.h"    // for isAssignment, isCopyConstructor
6namespace Validate {
7
8namespace {
9class EnumAttrFuncGenerator {
10        const ast::EnumDecl* decl;
11        const ast::EnumInstType* instType;
12        unsigned int functionNesting;
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* instType,
24                        unsigned int functionNesting )
25                : decl(decl),
26                  instType{instType},
27                  functionNesting{functionNesting},
28                  proto_linkage{ast::Linkage::Cforall} {}
29
30private:
31        const CodeLocation& getLocation() const { return decl->location; }
32
33        ast::FunctionDecl* genProto(
34                std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
35                std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
36
37        void produceDecl(const ast::FunctionDecl* decl);
38        void produceForwardDecl(const ast::FunctionDecl* decl);
39
40        const ast::Decl* getDecl() const { return decl; }
41
42        // Implement Bounded trait
43        void genBoundedFunctions();
44        ast::FunctionDecl* genBoundedProto(const char *) const;
45        void genBoundedBody(ast::FunctionDecl* func) const;
46
47        // Implement Serial trait
48        void genSerialTraitFuncs();
49        ast::FunctionDecl* genFromIntProto() const;
50        ast::FunctionDecl* genFromInstanceProto() const;
51        ast::FunctionDecl* genInstToInstFuncProto(const char* func) const;
52        void genFromIntBody(ast::FunctionDecl *) const; 
53        void genFromInstanceBody(ast::FunctionDecl *) const;
54        void genSuccPredBody(ast::FunctionDecl *, const char *) const;
55
56        // Implement TypedEnum trait
57        void genTypedEnumFuncs();
58        void genTypedEnumFunction(const ast::EnumAttribute attr);
59        ast::FunctionDecl* genPosnProto() const;
60        ast::FunctionDecl* genLabelProto() const;
61        ast::FunctionDecl* genValueProto() const;
62        void genValueOrLabelBody(
63                ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
64        void genPosnBody(ast::FunctionDecl* func) const;
65
66        ////////////////
67
68        // ---------------------------------------------------
69        // ast::FunctionDecl* genAttrCtorProto() const;
70        /// Changes the node inside a pointer so that it has the unused attribute.
71        void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
72                ast::DeclWithType* decl = declPtr.get_and_mutate();
73                decl->attributes.push_back(new ast::Attribute("unused"));
74        }
75
76        ast::ObjectDecl* dstParam() const {
77                return new ast::ObjectDecl(getLocation(), "_dst",
78                                           new ast::ReferenceType(new ast::EnumAttrType(
79                                               ast::deepCopy(instType))));
80        }
81
82        ast::ObjectDecl* srcParam() const {
83                return new ast::ObjectDecl(
84                        getLocation(), "_src",
85                        new ast::EnumAttrType(ast::deepCopy(instType)));
86        }
87
88        // ----------------------------------------------------
89
90        const ast::Init* getAutoInit(const ast::Init* prev) const;
91
92        std::vector<ast::ptr<ast::Init>> genLabelInit() const;
93
94        std::vector<ast::ptr<ast::Init>> genValueInit() const;
95        ast::ObjectDecl* genAttrArrayProto(
96                const ast::EnumAttribute attr, const CodeLocation& location,
97                std::vector<ast::ptr<ast::Init>>& inits) const;
98};
99
100std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
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                inits.emplace_back(new ast::SingleInit(
107                        mem->location,
108                        ast::ConstantExpr::from_string(mem->location, mem->name)));
109        }
110        return inits;
111}
112
113std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
114        std::vector<ast::ptr<ast::Init>> inits;
115        for (size_t i = 0; i < decl->members.size(); i++) {
116                ast::ptr<ast::Decl> mem = decl->members.at(i);
117                auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
118                assert(memAsObjectDecl);
119                if (memAsObjectDecl->init) {
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}
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                return new ast::SingleInit(getLocation(), untypedThisInit);
152        }
153}
154
155ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
156        std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
157        std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
158        ast::FunctionDecl* decl = new ast::FunctionDecl(
159                // Auto-generated routines use the type declaration's location.
160                getLocation(), std::move(name), {}, {}, std::move(params),
161                std::move(returns),
162                // Only a prototype, no body.
163                nullptr,
164                // Use static storage if we are at the top level.
165                (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
166                proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
167                // Auto-generated routines are inline to avoid conflicts.
168                ast::Function::Specs(ast::Function::Inline));
169        decl->fixUniqueId();
170        return decl;
171}
172
173void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
174        assert(nullptr != decl->stmts);
175
176        definitions.push_back(decl);
177}
178
179void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
180        if (0 != functionNesting) return;
181        ast::FunctionDecl* fwd =
182                (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
183        fwd->fixUniqueId();
184        forwards.push_back(fwd);
185}
186
187ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
188    return genProto(
189        "posE",
190        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
191        {new ast::ObjectDecl(getLocation(), "_ret",
192            new ast::BasicType(ast::BasicKind::UnsignedInt))});
193}
194
195ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
196        return genProto(
197                "labelE",
198                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
199                {new ast::ObjectDecl(
200                        getLocation(), "_ret",
201                        new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
202}
203
204ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
205        return genProto(
206                "valueE",
207                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
208                {new ast::ObjectDecl(getLocation(), "_ret",
209                                     ast::deepCopy(decl->base))});
210}
211
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
228void EnumAttrFuncGenerator::genFromIntBody(ast::FunctionDecl* func) const {
229        auto params = func->params;
230        assert( params.size() == 1 );
231        auto param = params.front();
232        auto castExpr = new ast::CastExpr(
233                func->location,
234                new ast::VariableExpr(func->location, param),
235                new ast::EnumInstType(decl),
236                ast::GeneratedFlag::ExplicitCast
237        );
238        func->stmts = new ast::CompoundStmt(
239                func->location, {new ast::ReturnStmt(func->location, castExpr)}
240        );
241}
242
243void EnumAttrFuncGenerator::genFromInstanceBody(ast::FunctionDecl* func) const {
244        auto params = func->params;
245        assert( params.size() == 1 );
246        auto param = params.front();
247        ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
248                func->location, "posE", { new ast::VariableExpr(func->location, param) });
249        func->stmts = new ast::CompoundStmt(
250                func->location, {new ast::ReturnStmt(func->location, untyped)}
251        );
252}
253
254void EnumAttrFuncGenerator::genSuccPredBody(ast::FunctionDecl * func, const char* opt) const {
255        auto params = func->params;
256        assert( params.size() == 1 );
257        auto param = params.front();
258        auto enumToInt = new ast::CastExpr(
259                func->location,
260                new ast::VariableExpr(func->location, param),
261                new ast::BasicType(ast::BasicKind::UnsignedInt),
262                ast::GeneratedFlag::ExplicitCast
263        );
264        ast::UntypedExpr* addOneExpr = ast::UntypedExpr::createCall( func->location,
265                opt,
266                {enumToInt,
267                ast::ConstantExpr::from_int(func->location, 1)}
268        );
269        auto intToEnum = new ast::CastExpr(
270                func->location,
271                addOneExpr,
272                new ast::EnumInstType( decl ),
273                ast::GeneratedFlag::ExplicitCast
274        );
275        func->stmts = new ast::CompoundStmt(
276                func->location, {
277                        new ast::ReturnStmt(
278                                func->location,
279                                intToEnum
280                        )
281                }
282        );
283}
284
285
286void EnumAttrFuncGenerator::genSerialTraitFuncs() {
287        ast::FunctionDecl * protos[4] = {
288                genFromIntProto(),
289                genFromInstanceProto(),
290                genInstToInstFuncProto("succ"),
291                genInstToInstFuncProto("pred")
292        };
293        for (auto& proto: protos) produceForwardDecl(proto);
294        genFromIntBody(protos[0]);
295        genFromInstanceBody(protos[1]);
296        genSuccPredBody(protos[2], "?+?");
297        genSuccPredBody(protos[3], "?-?");
298}
299
300ast::FunctionDecl* EnumAttrFuncGenerator::genInstToInstFuncProto(const char * func) const {
301        return genProto(
302                func,
303                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
304                {new ast::ObjectDecl(getLocation(), "_ret",
305                                     new ast::EnumInstType(decl))});
306}
307
308ast::FunctionDecl* EnumAttrFuncGenerator::genBoundedProto(const char * func) const {
309    return genProto(func, {}, {
310        new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))
311    });
312}
313
314void EnumAttrFuncGenerator::genBoundedBody(ast::FunctionDecl* func) const {
315        const CodeLocation & loc = func->location;
316        auto mem = func->name=="lowerBound"?  decl->members.front() : decl->members.back();
317        auto expr = new ast::NameExpr( loc, mem->name );
318        func->stmts = new ast::CompoundStmt( loc, {new ast::ReturnStmt(loc, expr)});
319}
320
321void EnumAttrFuncGenerator::genBoundedFunctions() {
322        ast::FunctionDecl * boundedProtos[2] = {genBoundedProto("upperBound"), genBoundedProto("lowerBound")};
323        for (auto & protos: boundedProtos) {
324                produceForwardDecl(protos);
325                genBoundedBody(protos);
326                produceDecl(protos);
327        }
328}
329
330inline ast::EnumAttrType * getPosnType( const ast::EnumDecl * decl ) {
331        return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
332}
333
334ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
335        const ast::EnumAttribute attr, const CodeLocation& location,
336        std::vector<ast::ptr<ast::Init>>& inits) const {
337        ast::ArrayType* arrT = new ast::ArrayType(
338                attr == ast::EnumAttribute::Value
339                        ? decl->base
340                        : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
341                ast::ConstantExpr::from_int(decl->location, decl->members.size()),
342                ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
343
344        ast::ObjectDecl* objDecl =
345                new ast::ObjectDecl(
346                        decl->location, decl->getUnmangeldArrayName( attr ),
347                        arrT, new ast::ListInit( location, std::move( inits ) ),
348                        ast::Storage::Static, ast::Linkage::AutoGen );
349
350        return objDecl;
351}
352
353void EnumAttrFuncGenerator::genValueOrLabelBody(
354        ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
355        ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
356                func->location, "?[?]",
357                {new ast::NameExpr(func->location, arrDecl->name),
358                new ast::CastExpr(
359                        func->location,
360                        new ast::VariableExpr( func->location, func->params.front() ),
361                        new ast::EnumAttrType( new ast::EnumInstType(decl),
362                                ast::EnumAttribute::Posn))});
363        func->stmts = new ast::CompoundStmt(
364                func->location, {new ast::ReturnStmt(func->location, untyped)});
365}
366
367void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
368        auto castExpr = new ast::CastExpr(
369                func->location,
370                new ast::VariableExpr(func->location, func->params.front()),
371                new ast::EnumAttrType(new ast::EnumInstType(decl),
372                                                          ast::EnumAttribute::Posn));
373        func->stmts = new ast::CompoundStmt(
374                func->location, {new ast::ReturnStmt(func->location, castExpr)});
375}
376
377void EnumAttrFuncGenerator::genTypedEnumFunction(const ast::EnumAttribute attr) {
378        if (attr == ast::EnumAttribute::Value ||
379                attr == ast::EnumAttribute::Label) {
380                // TypedEnum's backing arrays
381                std::vector<ast::ptr<ast::Init>> inits =
382                        attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
383                ast::ObjectDecl* arrayProto =
384                        genAttrArrayProto(attr, getLocation(), inits);
385                forwards.push_back(arrayProto);
386
387                ast::FunctionDecl* funcProto = ( attr == ast::EnumAttribute::Value )
388                                               ? genValueProto()
389                                               : genLabelProto();
390                produceForwardDecl(funcProto);
391                genValueOrLabelBody(funcProto, arrayProto);
392                produceDecl(funcProto);
393        } else {
394                ast::FunctionDecl* funcProto = genPosnProto();
395                produceForwardDecl(funcProto);
396                genPosnBody(funcProto);
397                produceDecl(funcProto);
398        }
399}
400
401void EnumAttrFuncGenerator::genTypedEnumFuncs() {
402        if (decl->base) genTypedEnumFunction(ast::EnumAttribute::Value);
403        genTypedEnumFunction(ast::EnumAttribute::Label);
404        genTypedEnumFunction(ast::EnumAttribute::Posn); 
405}
406
407void EnumAttrFuncGenerator::generateAndAppendFunctions(
408        std::list<ast::ptr<ast::Decl>>& decls) {
409        // Generate the functions (they go into forwards and definitions).
410        genTypedEnumFuncs();
411        genSerialTraitFuncs();
412        genBoundedFunctions();
413        // Now export the lists contents.
414        decls.splice(decls.end(), forwards);
415        decls.splice(decls.end(), definitions);
416}
417
418// ---------------------------------------------------------
419
420struct ImplementEnumFunc final :
421                public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting {
422        void previsit(const ast::EnumDecl* enumDecl);
423        void previsit(const ast::FunctionDecl* functionDecl);
424        void postvisit(const ast::FunctionDecl* functionDecl);
425
426private:
427        // Current level of nested functions.
428        unsigned int functionNesting = 0;
429};
430
431void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
432        if (!enumDecl->body || !enumDecl->isTyped) return;
433        ast::EnumInstType enumInst(enumDecl->name);
434        enumInst.base = enumDecl;
435        EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
436        gen.generateAndAppendFunctions(declsToAddAfter);
437}
438
439void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
440        functionNesting += 1;
441}
442
443void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
444        functionNesting -= 1;
445}
446
447} // namespace
448
449void implementEnumFunc(ast::TranslationUnit& translationUnit) {
450        ast::Pass<ImplementEnumFunc>::run(translationUnit);
451}
452
453} // namespace Validate
Note: See TracBrowser for help on using the repository browser.