source: src/Validate/ImplementEnumFunc.cpp @ d68de59

Last change on this file since d68de59 was 822332e, checked in by Andrew Beach <ajbeach@…>, 7 weeks ago

It seems clang uses different scoping rules for the trailing return of a scoped runction declaration. This form seems compatable with clang and gcc. Since I switched over to clang for testing I also cleaned up all errors that clang or gcc mentioned.

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