source: src/Validate/ImplementEnumFunc.cpp @ 011c29e

Last change on this file since 011c29e was 5ccc733, checked in by JiadaL <j82liang@…>, 4 months ago

Fix the bug that C style enum cannot to use as an lvalue

  • Property mode set to 100644
File size: 16.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        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                  quasi_void_decl(new ast::StructDecl(decl->location, 
28                        "quasi_void", ast::AggregateDecl::Struct,
29                        {}, ast::Linkage::AutoGen)),
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
44        // Implement Bounded trait
45        void genBoundedFunctions();
46        ast::FunctionDecl* genBoundedProto(const char *) const;
47        void genBoundedBody(ast::FunctionDecl* func) const;
48
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;
54        void genFromIntBody(ast::FunctionDecl *) const;
55        void genFromInstanceBody(ast::FunctionDecl *) const;
56        void genSuccPredBody(ast::FunctionDecl *, const char *) const;
57
58        void genTypeNameFunc();
59
60        // Implement TypedEnum trait
61        void genTypedEnumFuncs();
62        void genTypedEnumFunction(const ast::EnumAttribute attr);
63        ast::FunctionDecl* genPosnProto() const;
64        ast::FunctionDecl* genLabelProto() const;
65        ast::FunctionDecl* genValueProto() const;
66        ast::FunctionDecl* genQuasiValueProto() const;
67        ast::FunctionDecl* genTypeNameProto() const;
68
69        void genValueOrLabelBody(
70                ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
71        void genPosnBody(ast::FunctionDecl* func) const;
72        void genQuasiValueBody(ast::FunctionDecl* func) const;
73        void genTypeNameBody(ast::FunctionDecl* func) const;
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;
85};
86
87std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
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;
98}
99
100std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() 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                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;
119}
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        "posn",
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                "label",
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        if (decl->base)
194                return genProto(
195                        "value",
196                        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
197                        {new ast::ObjectDecl(getLocation(), "_ret",
198                                                                ast::deepCopy(decl->base))});
199        else
200                return genQuasiValueProto();
201}
202
203ast::FunctionDecl* EnumAttrFuncGenerator::genQuasiValueProto() const {
204        return genProto(
205                "value",
206                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
207                {new ast::ObjectDecl(getLocation(), "_ret",
208                                                new ast::StructInstType(quasi_void_decl))});
209}
210
211ast::FunctionDecl* EnumAttrFuncGenerator::genFromIntProto() const {
212        return genProto(
213                "fromInt",
214                {new ast::ObjectDecl(getLocation(), "_i", new ast::BasicType(ast::BasicKind::UnsignedInt))},
215                {new ast::ObjectDecl(getLocation(), "_ret", new ast::EnumInstType(decl))}
216        );
217}
218
219ast::FunctionDecl* EnumAttrFuncGenerator::genFromInstanceProto() const {
220        return genProto(
221                "fromInstance",
222                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
223                {new ast::ObjectDecl(getLocation(), "_ret", new ast::BasicType(ast::BasicKind::UnsignedInt))}
224        );
225}
226
227ast::FunctionDecl* EnumAttrFuncGenerator::genTypeNameProto() const {
228        return genProto(
229                "type_name",
230                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
231                {new ast::ObjectDecl(
232                        getLocation(), "_ret",
233                        new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
234}
235
236void EnumAttrFuncGenerator::genFromIntBody(ast::FunctionDecl* func) const {
237        auto params = func->params;
238        assert( params.size() == 1 );
239        auto param = params.front();
240        auto castExpr = new ast::CastExpr(
241                func->location,
242                new ast::VariableExpr(func->location, param),
243                new ast::EnumInstType(decl),
244                ast::GeneratedFlag::ExplicitCast
245        );
246        func->stmts = new ast::CompoundStmt(
247                func->location, {new ast::ReturnStmt(func->location, castExpr)}
248        );
249}
250
251void EnumAttrFuncGenerator::genFromInstanceBody(ast::FunctionDecl* func) const {
252        auto params = func->params;
253        assert( params.size() == 1 );
254        auto param = params.front();
255        ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
256                func->location, "posn", { new ast::VariableExpr(func->location, param) });
257        func->stmts = new ast::CompoundStmt(
258                func->location, {new ast::ReturnStmt(func->location, untyped)}
259        );
260}
261
262void EnumAttrFuncGenerator::genSuccPredBody(ast::FunctionDecl * func, const char* opt) const {
263        auto params = func->params;
264        assert( params.size() == 1 );
265        auto param = params.front();
266        auto enumToInt = new ast::CastExpr(
267                func->location,
268                new ast::VariableExpr(func->location, param),
269                new ast::BasicType(ast::BasicKind::UnsignedInt),
270                ast::GeneratedFlag::ExplicitCast
271        );
272        ast::UntypedExpr* addOneExpr = ast::UntypedExpr::createCall( func->location,
273                opt,
274                {enumToInt,
275                ast::ConstantExpr::from_int(func->location, 1)}
276        );
277        auto intToEnum = new ast::CastExpr(
278                func->location,
279                addOneExpr,
280                new ast::EnumInstType( decl ),
281                ast::GeneratedFlag::ExplicitCast
282        );
283        func->stmts = new ast::CompoundStmt(
284                func->location, {
285                        new ast::ReturnStmt(
286                                func->location,
287                                intToEnum
288                        )
289                }
290        );
291}
292
293void EnumAttrFuncGenerator::genSerialTraitFuncs() {
294        ast::FunctionDecl * protos[4] = {
295                genFromIntProto(),
296                genFromInstanceProto(),
297                genInstToInstFuncProto("succ"),
298                genInstToInstFuncProto("pred")
299        };
300        for (auto& proto: protos) produceForwardDecl(proto);
301        genFromIntBody(protos[0]);
302        genFromInstanceBody(protos[1]);
303        genSuccPredBody(protos[2], "?+?");
304        genSuccPredBody(protos[3], "?-?");
305        for (auto& proto: protos) produceDecl(proto);
306}
307
308ast::FunctionDecl* EnumAttrFuncGenerator::genInstToInstFuncProto(const char * func) const {
309        return genProto(
310                func,
311                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
312                {new ast::ObjectDecl(getLocation(), "_ret",
313                                     new ast::EnumInstType(decl))});
314}
315
316ast::FunctionDecl* EnumAttrFuncGenerator::genBoundedProto(const char * func) const {
317    return genProto(func, {}, {
318        new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))
319    });
320}
321
322void EnumAttrFuncGenerator::genBoundedBody(ast::FunctionDecl* func) const {
323        const CodeLocation & loc = func->location;
324        auto mem = func->name=="lowerBound"?  decl->members.front() : decl->members.back();
325        // auto expr = new ast::NameExpr( loc, mem->name );
326        auto expr = new ast::QualifiedNameExpr( loc, decl->name, mem->name );
327        func->stmts = new ast::CompoundStmt( loc, {new ast::ReturnStmt(loc, expr)});
328}
329
330void EnumAttrFuncGenerator::genBoundedFunctions() {
331        ast::FunctionDecl * boundedProtos[2] = {genBoundedProto("upperBound"), genBoundedProto("lowerBound")};
332        for (auto & protos: boundedProtos) {
333                produceForwardDecl(protos);
334                genBoundedBody(protos);
335                produceDecl(protos);
336        }
337}
338
339ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
340        const ast::EnumAttribute attr, const CodeLocation& location,
341        std::vector<ast::ptr<ast::Init>>& inits) const {
342        ast::ArrayType* arrT = new ast::ArrayType(
343                attr == ast::EnumAttribute::Value
344                        ? decl->base
345                        : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
346                ast::ConstantExpr::from_int(decl->location, decl->members.size()),
347                ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
348
349        ast::ObjectDecl* objDecl =
350                new ast::ObjectDecl(
351                        decl->location, decl->getUnmangeldArrayName( attr ),
352                        arrT, new ast::ListInit( location, std::move( inits ) ),
353                        ast::Storage::Static, ast::Linkage::AutoGen );
354
355        return objDecl;
356}
357
358void EnumAttrFuncGenerator::genValueOrLabelBody(
359        ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
360        ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
361                func->location, "?[?]",
362                {new ast::NameExpr(func->location, arrDecl->name),
363                new ast::CastExpr(
364                        func->location,
365                        new ast::VariableExpr( func->location, func->params.front() ),
366                        new ast::BasicType( ast::BasicKind::UnsignedInt ),
367                        ast::GeneratedFlag::ExplicitCast
368                )});
369        func->stmts = new ast::CompoundStmt(
370                func->location, {new ast::ReturnStmt(func->location, untyped)});
371}
372
373void EnumAttrFuncGenerator::genQuasiValueBody(ast::FunctionDecl* func) const {
374        auto location = func->location;
375        const ast::ObjectDecl * objDecl = new ast::ObjectDecl(
376                location, "_out", new ast::StructInstType( quasi_void_decl ));
377        const ast::DeclStmt * declStmt = new ast::DeclStmt(location, objDecl);
378        const ast::VariableExpr * varExpr = new ast::VariableExpr(location, objDecl);
379        const ast::ReturnStmt * retStmt = new ast::ReturnStmt(location, varExpr);
380
381        func->stmts = new ast::CompoundStmt(
382                location, {declStmt, retStmt}
383        );
384}
385
386void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
387        auto castExpr = new ast::CastExpr(
388                func->location,
389                new ast::VariableExpr(func->location, func->params.front()),
390                new ast::BasicType( ast::BasicKind::UnsignedInt ),
391                        ast::GeneratedFlag::ExplicitCast);
392        func->stmts = new ast::CompoundStmt(
393                func->location, {new ast::ReturnStmt(func->location, castExpr)});
394}
395
396void EnumAttrFuncGenerator::genTypeNameBody(ast::FunctionDecl* func) const {
397        const ast::Expr * type_name = ast::ConstantExpr::from_string(func->location, decl->name);
398        func->stmts = new ast::CompoundStmt(
399                func->location, {new ast::ReturnStmt(func->location, type_name)}
400        );
401}
402
403void EnumAttrFuncGenerator::genTypedEnumFunction(const ast::EnumAttribute attr) {
404        if (attr == ast::EnumAttribute::Value) {
405                if (decl->base) {
406                        // TypedEnum's backing arrays
407                        std::vector<ast::ptr<ast::Init>> inits = genValueInit();
408                        ast::ObjectDecl* arrayProto =
409                                genAttrArrayProto(attr, getLocation(), inits);
410                        forwards.push_back(arrayProto);
411
412                        ast::FunctionDecl* funcProto = genValueProto();
413                        produceForwardDecl(funcProto);
414                        genValueOrLabelBody(funcProto, arrayProto);
415                        produceDecl(funcProto);
416                }  else {
417                        ast::FunctionDecl* funcProto = genQuasiValueProto();
418                        produceForwardDecl(funcProto);
419                        genQuasiValueBody(funcProto);
420                        produceDecl(funcProto);
421                }
422        } else if (attr == ast::EnumAttribute::Label) {
423                std::vector<ast::ptr<ast::Init>> inits = genLabelInit();
424                ast::ObjectDecl* arrayProto =
425                        genAttrArrayProto(attr, getLocation(), inits);
426                forwards.push_back(arrayProto);
427                ast::FunctionDecl* funcProto = genLabelProto();
428                produceForwardDecl(funcProto);
429                genValueOrLabelBody(funcProto, arrayProto);
430                produceDecl(funcProto);
431        } else {
432                ast::FunctionDecl* funcProto = genPosnProto();
433                produceForwardDecl(funcProto);
434                genPosnBody(funcProto);
435                produceDecl(funcProto);
436        }
437}
438
439void EnumAttrFuncGenerator::genTypedEnumFuncs() {
440        genTypedEnumFunction(ast::EnumAttribute::Value);
441        genTypedEnumFunction(ast::EnumAttribute::Label);
442        genTypedEnumFunction(ast::EnumAttribute::Posn);
443}
444
445void EnumAttrFuncGenerator::genTypeNameFunc() {
446        ast::FunctionDecl* funcProto = genTypeNameProto();
447        produceForwardDecl(funcProto);
448        genTypeNameBody(funcProto);
449        produceDecl(funcProto);
450}
451
452void EnumAttrFuncGenerator::generateAndAppendFunctions(
453        std::list<ast::ptr<ast::Decl>>& decls) {
454        // Generate the functions (they go into forwards and definitions).
455        genTypeNameFunc();
456        genTypedEnumFuncs();
457        genSerialTraitFuncs();
458        genBoundedFunctions();
459        // Now export the lists contents.
460        decls.splice(decls.end(), forwards);
461        decls.splice(decls.end(), definitions);
462}
463
464// ---------------------------------------------------------
465
466struct ImplementEnumFunc final :
467                public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting {
468        void previsit(const ast::EnumDecl* enumDecl);
469        void previsit(const ast::FunctionDecl* functionDecl);
470        void postvisit(const ast::FunctionDecl* functionDecl);
471
472private:
473        // Current level of nested functions.
474        unsigned int functionNesting = 0;
475};
476
477void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
478        if (!enumDecl->body || !enumDecl->isCfa) return;
479        ast::EnumInstType enumInst(enumDecl->name);
480        enumInst.base = enumDecl;
481        EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
482        gen.generateAndAppendFunctions(declsToAddAfter);
483}
484
485void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
486        functionNesting += 1;
487}
488
489void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
490        functionNesting -= 1;
491}
492
493} // namespace
494
495void implementEnumFunc(ast::TranslationUnit& translationUnit) {
496        ast::Pass<ImplementEnumFunc>::run(translationUnit);
497}
498
499} // namespace Validate
Note: See TracBrowser for help on using the repository browser.