source: src/Validate/ImplementEnumFunc.cpp @ 31f4837

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

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

  • Property mode set to 100644
File size: 14.4 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        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        // ----------------------------------------------------
77
78        const ast::Init* getAutoInit(const ast::Init* prev) const;
79
80        std::vector<ast::ptr<ast::Init>> genLabelInit() const;
81
82        std::vector<ast::ptr<ast::Init>> genValueInit() const;
83        ast::ObjectDecl* genAttrArrayProto(
84                const ast::EnumAttribute attr, const CodeLocation& location,
85                std::vector<ast::ptr<ast::Init>>& inits) const;
86};
87
88std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
89        std::vector<ast::ptr<ast::Init>> inits;
90        for (size_t i = 0; i < decl->members.size(); i++) {
91                ast::ptr<ast::Decl> mem = decl->members.at(i);
92                auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
93                assert(memAsObjectDecl);
94                inits.emplace_back(new ast::SingleInit(
95                        mem->location,
96                        ast::ConstantExpr::from_string(mem->location, mem->name)));
97        }
98        return inits;
99}
100
101std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
102        std::vector<ast::ptr<ast::Init>> inits;
103        for (size_t i = 0; i < decl->members.size(); i++) {
104                ast::ptr<ast::Decl> mem = decl->members.at(i);
105                auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
106                assert(memAsObjectDecl);
107                if (memAsObjectDecl->init) {
108                        inits.emplace_back(memAsObjectDecl->init);
109                } else {
110                        const CodeLocation& location = mem->location;
111                        if (i == 0) {
112                                inits.emplace_back(new ast::SingleInit(
113                                        location, ast::ConstantExpr::from_int(mem->location, 0)));
114                        } else {
115                                inits.emplace_back(getAutoInit(inits.at(i - 1)));
116                        }
117                }
118        }
119        return inits;
120}
121const ast::Init* EnumAttrFuncGenerator::getAutoInit(
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        }
141}
142
143ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
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;
159}
160
161void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
162        assert(nullptr != decl->stmts);
163
164        definitions.push_back(decl);
165}
166
167void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
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);
173}
174
175ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
176    return genProto(
177        "posE",
178        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
179        {new ast::ObjectDecl(getLocation(), "_ret",
180            new ast::BasicType(ast::BasicKind::UnsignedInt))});
181}
182
183ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
184        return genProto(
185                "labelE",
186                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
187                {new ast::ObjectDecl(
188                        getLocation(), "_ret",
189                        new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
190}
191
192ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
193        return genProto(
194                "valueE",
195                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
196                {new ast::ObjectDecl(getLocation(), "_ret",
197                                     ast::deepCopy(decl->base))});
198}
199
200ast::FunctionDecl* EnumAttrFuncGenerator::genFromIntProto() const {
201        return genProto(
202                "fromInt",
203                {new ast::ObjectDecl(getLocation(), "_i", new ast::BasicType(ast::BasicKind::UnsignedInt))},
204                {new ast::ObjectDecl(getLocation(), "_ret", new ast::EnumInstType(decl))}
205        );
206}
207
208ast::FunctionDecl* EnumAttrFuncGenerator::genFromInstanceProto() const {
209        return genProto(
210                "fromInstance",
211                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
212                {new ast::ObjectDecl(getLocation(), "_ret", new ast::BasicType(ast::BasicKind::UnsignedInt))}
213        );
214}
215
216void EnumAttrFuncGenerator::genFromIntBody(ast::FunctionDecl* func) const {
217        auto params = func->params;
218        assert( params.size() == 1 );
219        auto param = params.front();
220        auto castExpr = new ast::CastExpr(
221                func->location,
222                new ast::VariableExpr(func->location, param),
223                new ast::EnumInstType(decl),
224                ast::GeneratedFlag::ExplicitCast
225        );
226        func->stmts = new ast::CompoundStmt(
227                func->location, {new ast::ReturnStmt(func->location, castExpr)}
228        );
229}
230
231void EnumAttrFuncGenerator::genFromInstanceBody(ast::FunctionDecl* func) const {
232        auto params = func->params;
233        assert( params.size() == 1 );
234        auto param = params.front();
235        ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
236                func->location, "posE", { new ast::VariableExpr(func->location, param) });
237        func->stmts = new ast::CompoundStmt(
238                func->location, {new ast::ReturnStmt(func->location, untyped)}
239        );
240}
241
242void EnumAttrFuncGenerator::genSuccPredBody(ast::FunctionDecl * func, const char* opt) const {
243        auto params = func->params;
244        assert( params.size() == 1 );
245        auto param = params.front();
246        auto enumToInt = new ast::CastExpr(
247                func->location,
248                new ast::VariableExpr(func->location, param),
249                new ast::BasicType(ast::BasicKind::UnsignedInt),
250                ast::GeneratedFlag::ExplicitCast
251        );
252        ast::UntypedExpr* addOneExpr = ast::UntypedExpr::createCall( func->location,
253                opt,
254                {enumToInt,
255                ast::ConstantExpr::from_int(func->location, 1)}
256        );
257        auto intToEnum = new ast::CastExpr(
258                func->location,
259                addOneExpr,
260                new ast::EnumInstType( decl ),
261                ast::GeneratedFlag::ExplicitCast
262        );
263        func->stmts = new ast::CompoundStmt(
264                func->location, {
265                        new ast::ReturnStmt(
266                                func->location,
267                                intToEnum
268                        )
269                }
270        );
271}
272
273
274void EnumAttrFuncGenerator::genSerialTraitFuncs() {
275        ast::FunctionDecl * protos[4] = {
276                genFromIntProto(),
277                genFromInstanceProto(),
278                genInstToInstFuncProto("succ"),
279                genInstToInstFuncProto("pred")
280        };
281        for (auto& proto: protos) produceForwardDecl(proto);
282        genFromIntBody(protos[0]);
283        genFromInstanceBody(protos[1]);
284        genSuccPredBody(protos[2], "?+?");
285        genSuccPredBody(protos[3], "?-?");
286        for (auto& proto: protos) produceDecl(proto);
287}
288
289ast::FunctionDecl* EnumAttrFuncGenerator::genInstToInstFuncProto(const char * func) const {
290        return genProto(
291                func,
292                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
293                {new ast::ObjectDecl(getLocation(), "_ret",
294                                     new ast::EnumInstType(decl))});
295}
296
297ast::FunctionDecl* EnumAttrFuncGenerator::genBoundedProto(const char * func) const {
298    return genProto(func, {}, {
299        new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))
300    });
301}
302
303void EnumAttrFuncGenerator::genBoundedBody(ast::FunctionDecl* func) const {
304        const CodeLocation & loc = func->location;
305        auto mem = func->name=="lowerBound"?  decl->members.front() : decl->members.back();
306        auto expr = new ast::NameExpr( loc, mem->name );
307        func->stmts = new ast::CompoundStmt( loc, {new ast::ReturnStmt(loc, expr)});
308}
309
310void EnumAttrFuncGenerator::genBoundedFunctions() {
311        ast::FunctionDecl * boundedProtos[2] = {genBoundedProto("upperBound"), genBoundedProto("lowerBound")};
312        for (auto & protos: boundedProtos) {
313                produceForwardDecl(protos);
314                genBoundedBody(protos);
315                produceDecl(protos);
316        }
317}
318
319ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
320        const ast::EnumAttribute attr, const CodeLocation& location,
321        std::vector<ast::ptr<ast::Init>>& inits) const {
322        ast::ArrayType* arrT = new ast::ArrayType(
323                attr == ast::EnumAttribute::Value
324                        ? decl->base
325                        : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
326                ast::ConstantExpr::from_int(decl->location, decl->members.size()),
327                ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
328
329        ast::ObjectDecl* objDecl =
330                new ast::ObjectDecl(
331                        decl->location, decl->getUnmangeldArrayName( attr ),
332                        arrT, new ast::ListInit( location, std::move( inits ) ),
333                        ast::Storage::Static, ast::Linkage::AutoGen );
334
335        return objDecl;
336}
337
338void EnumAttrFuncGenerator::genValueOrLabelBody(
339        ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
340        ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
341                func->location, "?[?]",
342                {new ast::NameExpr(func->location, arrDecl->name),
343                new ast::CastExpr(
344                        func->location,
345                        new ast::VariableExpr( func->location, func->params.front() ),
346                        new ast::BasicType( ast::BasicKind::UnsignedInt ),
347                        ast::GeneratedFlag::ExplicitCast
348                )});
349        func->stmts = new ast::CompoundStmt(
350                func->location, {new ast::ReturnStmt(func->location, untyped)});
351}
352
353void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
354        auto castExpr = new ast::CastExpr(
355                func->location,
356                new ast::VariableExpr(func->location, func->params.front()),
357                new ast::BasicType( ast::BasicKind::UnsignedInt ),
358                        ast::GeneratedFlag::ExplicitCast);
359        func->stmts = new ast::CompoundStmt(
360                func->location, {new ast::ReturnStmt(func->location, castExpr)});
361}
362
363void EnumAttrFuncGenerator::genTypedEnumFunction(const ast::EnumAttribute attr) {
364        if (attr == ast::EnumAttribute::Value ||
365                attr == ast::EnumAttribute::Label) {
366                // TypedEnum's backing arrays
367                std::vector<ast::ptr<ast::Init>> inits =
368                        attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
369                ast::ObjectDecl* arrayProto =
370                        genAttrArrayProto(attr, getLocation(), inits);
371                forwards.push_back(arrayProto);
372
373                ast::FunctionDecl* funcProto = ( attr == ast::EnumAttribute::Value )
374                                               ? genValueProto()
375                                               : genLabelProto();
376                produceForwardDecl(funcProto);
377                genValueOrLabelBody(funcProto, arrayProto);
378                produceDecl(funcProto);
379        } else {
380                ast::FunctionDecl* funcProto = genPosnProto();
381                produceForwardDecl(funcProto);
382                genPosnBody(funcProto);
383                produceDecl(funcProto);
384        }
385}
386
387void EnumAttrFuncGenerator::genTypedEnumFuncs() {
388        if (decl->base) genTypedEnumFunction(ast::EnumAttribute::Value);
389        genTypedEnumFunction(ast::EnumAttribute::Label);
390        genTypedEnumFunction(ast::EnumAttribute::Posn); 
391}
392
393void EnumAttrFuncGenerator::generateAndAppendFunctions(
394        std::list<ast::ptr<ast::Decl>>& decls) {
395        // Generate the functions (they go into forwards and definitions).
396        genTypedEnumFuncs();
397        genSerialTraitFuncs();
398        genBoundedFunctions();
399        // Now export the lists contents.
400        decls.splice(decls.end(), forwards);
401        decls.splice(decls.end(), definitions);
402}
403
404// ---------------------------------------------------------
405
406struct ImplementEnumFunc final :
407                public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting {
408        void previsit(const ast::EnumDecl* enumDecl);
409        void previsit(const ast::FunctionDecl* functionDecl);
410        void postvisit(const ast::FunctionDecl* functionDecl);
411
412private:
413        // Current level of nested functions.
414        unsigned int functionNesting = 0;
415};
416
417void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
418        if (!enumDecl->body || !enumDecl->isTyped) return;
419        ast::EnumInstType enumInst(enumDecl->name);
420        enumInst.base = enumDecl;
421        EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
422        gen.generateAndAppendFunctions(declsToAddAfter);
423}
424
425void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
426        functionNesting += 1;
427}
428
429void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
430        functionNesting -= 1;
431}
432
433} // namespace
434
435void implementEnumFunc(ast::TranslationUnit& translationUnit) {
436        ast::Pass<ImplementEnumFunc>::run(translationUnit);
437}
438
439} // namespace Validate
Note: See TracBrowser for help on using the repository browser.