source: src/Validate/ImplementEnumFunc.cpp @ ba97ebf

Last change on this file since ba97ebf was fc1a3e2, checked in by Andrew Beach <ajbeach@…>, 2 months ago

Style update. Focused on indentation and trailing whitespace.

  • Property mode set to 100644
File size: 16.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
30        void genAttrFunctions();
31        void genSuccPredPosn();
32        void genSuccPredDecl();
33
34        void appendReturnThis(ast::FunctionDecl* decl) {
35                assert(1 <= decl->params.size());
36                assert(1 == decl->returns.size());
37                assert(decl->stmts);
38
39                const CodeLocation& location = (decl->stmts->kids.empty())
40                                                   ? decl->stmts->location
41                                                   : decl->stmts->kids.back()->location;
42                const ast::DeclWithType* thisParam = decl->params.front();
43                decl->stmts.get_and_mutate()->push_back(new ast::ReturnStmt(
44                        location, new ast::VariableExpr(location, thisParam)));
45        }
46        void genAttrStandardFuncs() {
47                ast::FunctionDecl* (EnumAttrFuncGenerator::*standardProtos[4])()
48                        const = {&EnumAttrFuncGenerator::genCtorProto,
49                                         &EnumAttrFuncGenerator::genCopyProto,
50                                         &EnumAttrFuncGenerator::genDtorProto,
51                                         &EnumAttrFuncGenerator::genAssignProto};
52                for (auto& generator : standardProtos) {
53                        ast::FunctionDecl* decl = (this->*generator)();
54                        produceForwardDecl(decl);
55                        genFuncBody(decl);
56                        if (CodeGen::isAssignment(decl->name)) {
57                                appendReturnThis(decl);
58                        }
59                        produceDecl(decl);
60                }
61        }
62
63private:
64        const CodeLocation& getLocation() const { return decl->location; }
65
66        ast::FunctionDecl* genProto(
67                std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
68                std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
69
70        void produceDecl(const ast::FunctionDecl* decl);
71        void produceForwardDecl(const ast::FunctionDecl* decl);
72
73        const ast::Decl* getDecl() const { return decl; }
74
75        ast::FunctionDecl* genPosnProto() const;
76        ast::FunctionDecl* genLabelProto() const;
77        ast::FunctionDecl* genValueProto() const;
78        ast::FunctionDecl* genSuccProto() const;
79        ast::FunctionDecl* genPredProto() const;
80
81        ast::FunctionDecl* genSuccPosProto() const;
82        ast::FunctionDecl* genPredPosProto() const;
83
84        // ---------------------------------------------------
85        // ast::FunctionDecl* genAttrCtorProto() const;
86        /// Changes the node inside a pointer so that it has the unused attribute.
87        void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
88                ast::DeclWithType* decl = declPtr.get_and_mutate();
89                decl->attributes.push_back(new ast::Attribute("unused"));
90        }
91
92        ast::ObjectDecl* dstParam() const {
93                return new ast::ObjectDecl(getLocation(), "_dst",
94                                           new ast::ReferenceType(new ast::EnumAttrType(
95                                               ast::deepCopy(instType))));
96        }
97
98        ast::ObjectDecl* srcParam() const {
99                return new ast::ObjectDecl(
100                        getLocation(), "_src",
101                        new ast::EnumAttrType(ast::deepCopy(instType)));
102        }
103
104        /// E = EnumAttrType<T>`
105        /// `void ?{}(E & _dst)`.
106        ast::FunctionDecl* genCtorProto() const {
107                return genProto("?{}", {dstParam()}, {});
108        }
109
110        /// void ?{}(E & _dst, E _src)`.
111        ast::FunctionDecl* genCopyProto() const {
112                return genProto("?{}", {dstParam(), srcParam()}, {});
113        }
114
115        ///`void ^?{}(E & _dst)`.
116        ast::FunctionDecl* genDtorProto() const {
117                // The destructor must be mutex on a concurrent type.
118                return genProto("^?{}", {dstParam()}, {});
119        }
120
121        /// `E ?{}(E & _dst, E _src)`.
122        ast::FunctionDecl* genAssignProto() const {
123                // Only the name is different, so just reuse the generation function.
124                auto retval = srcParam();
125                retval->name = "_ret";
126                return genProto("?=?", {dstParam(), srcParam()}, {retval});
127        }
128
129        void genFuncBody(ast::FunctionDecl* func) {
130                const CodeLocation& location = func->location;
131                auto& params = func->params;
132                if (InitTweak::isCopyConstructor(func) ||
133                        InitTweak::isAssignment(func)) {
134                        assert(2 == params.size());
135                        auto dstParam = params.front().strict_as<ast::ObjectDecl>();
136                        auto srcParam = params.back().strict_as<ast::ObjectDecl>();
137                        func->stmts = genCopyBody(location, dstParam, srcParam);
138                } else {
139                        assert(1 == params.size());
140                        // Default constructor and destructor is empty.
141                        func->stmts = new ast::CompoundStmt(location);
142                        // Add unused attribute to parameter to silence warnings.
143                        addUnusedAttribute(params.front());
144
145                        // Just an extra step to make the forward and declaration match.
146                        if (forwards.empty()) return;
147                        ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
148                                forwards.back().get_and_mutate());
149                        addUnusedAttribute(fwd->params.front());
150                }
151        }
152
153        const ast::CompoundStmt* genCopyBody( const CodeLocation& location,
154                        const ast::ObjectDecl* dstParam, const ast::ObjectDecl* srcParam) {
155                return new ast::CompoundStmt(
156                        location,
157                        {new ast::ExprStmt(
158                                location,
159                                new ast::UntypedExpr(
160                                        location, new ast::NameExpr(location, "__builtin_memcpy"),
161                                        {
162                                                new ast::AddressExpr( location,
163                                                        new ast::VariableExpr( location, dstParam ) ),
164                                                new ast::AddressExpr( location,
165                                                        new ast::VariableExpr( location, srcParam ) ),
166                                                new ast::SizeofExpr( location, srcParam->type ),
167                                        }))});
168        }
169
170        void genDtorBody(ast::FunctionDecl* func) {
171                const CodeLocation& location = func->location;
172                auto& params = func->params;
173                assert(1 == params.size());
174                func->stmts = new ast::CompoundStmt(location);
175                addUnusedAttribute(params.front());
176
177                // Just an extra step to make the forward and declaration match.
178                if (forwards.empty()) return;
179                ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
180                        forwards.back().get_and_mutate());
181                addUnusedAttribute(fwd->params.front());
182        }
183
184        // ast::FunctionDecl*
185        // ----------------------------------------------------
186
187        ast::FunctionDecl* genSuccPredFunc(bool succ);
188
189        const ast::Init* getAutoInit(const ast::Init* prev) const;
190
191        std::vector<ast::ptr<ast::Init>> genLabelInit() const;
192
193        std::vector<ast::ptr<ast::Init>> genValueInit() const;
194        ast::ObjectDecl* genAttrArrayProto(
195                const ast::EnumAttribute attr, const CodeLocation& location,
196                std::vector<ast::ptr<ast::Init>>& inits) const;
197        void genValueOrLabelBody(
198                ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
199        void genPosnBody(ast::FunctionDecl* func) const;
200        void genAttributesDecls(const ast::EnumAttribute attr);
201};
202
203std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
204        std::vector<ast::ptr<ast::Init>> inits;
205        for (size_t i = 0; i < decl->members.size(); i++) {
206                ast::ptr<ast::Decl> mem = decl->members.at(i);
207                auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
208                assert(memAsObjectDecl);
209                inits.emplace_back(new ast::SingleInit(
210                        mem->location,
211                        ast::ConstantExpr::from_string(mem->location, mem->name)));
212        }
213        return inits;
214}
215
216std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
217        std::vector<ast::ptr<ast::Init>> inits;
218        for (size_t i = 0; i < decl->members.size(); i++) {
219                ast::ptr<ast::Decl> mem = decl->members.at(i);
220                auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
221                assert(memAsObjectDecl);
222                if (memAsObjectDecl->init) {
223                        inits.emplace_back(memAsObjectDecl->init);
224                } else {
225                        const CodeLocation& location = mem->location;
226                        if (i == 0) {
227                                inits.emplace_back(new ast::SingleInit(
228                                        location, ast::ConstantExpr::from_int(mem->location, 0)));
229                        } else {
230                                inits.emplace_back(getAutoInit(inits.at(i - 1)));
231                        }
232                }
233        }
234        return inits;
235}
236const ast::Init* EnumAttrFuncGenerator::getAutoInit(
237        const ast::Init* prev) const {
238        if (prev == nullptr) {
239                return new ast::SingleInit(
240                        getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
241        }
242        auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
243        assert(prevInit);
244        auto prevInitExpr = prevInit->value;
245        if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
246                // Assume no string literal for now
247                return new ast::SingleInit(
248                        getLocation(), ast::ConstantExpr::from_int(
249                                getLocation(), constInit->intValue() + 1));
250        } else {
251                auto untypedThisInit = new ast::UntypedExpr(
252                        getLocation(), new ast::NameExpr(getLocation(), "?++"),
253                        {prevInitExpr});
254                return new ast::SingleInit(getLocation(), untypedThisInit);
255        }
256}
257
258ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
259        std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
260        std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
261        ast::FunctionDecl* decl = new ast::FunctionDecl(
262                // Auto-generated routines use the type declaration's location.
263                getLocation(), std::move(name), {}, {}, std::move(params),
264                std::move(returns),
265                // Only a prototype, no body.
266                nullptr,
267                // Use static storage if we are at the top level.
268                (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
269                proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
270                // Auto-generated routines are inline to avoid conflicts.
271                ast::Function::Specs(ast::Function::Inline));
272        decl->fixUniqueId();
273        return decl;
274}
275
276void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
277        assert(nullptr != decl->stmts);
278
279        definitions.push_back(decl);
280}
281
282void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
283        if (0 != functionNesting) return;
284        ast::FunctionDecl* fwd =
285                (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
286        fwd->fixUniqueId();
287        forwards.push_back(fwd);
288}
289
290ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
291        return genProto(
292                "posE",
293                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
294                {new ast::ObjectDecl(getLocation(), "_ret",
295                        new ast::BasicType(ast::BasicKind::UnsignedInt))});
296}
297
298ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
299        return genProto(
300                "labelE",
301                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
302                {new ast::ObjectDecl(
303                        getLocation(), "_ret",
304                        new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
305}
306
307ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
308        return genProto(
309                "valueE",
310                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
311                {new ast::ObjectDecl(getLocation(), "_ret",
312                                     ast::deepCopy(decl->base))});
313}
314
315ast::FunctionDecl* EnumAttrFuncGenerator::genSuccProto() const {
316        return genProto(
317                "succ",
318                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
319                {new ast::ObjectDecl(getLocation(), "_ret",
320                                     new ast::EnumInstType(decl))});
321}
322
323ast::FunctionDecl* EnumAttrFuncGenerator::genPredProto() const {
324        return genProto(
325                "pred",
326                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
327                {new ast::ObjectDecl(getLocation(), "_ret",
328                                     new ast::EnumInstType(decl))});
329}
330
331inline ast::EnumAttrType * getPosnType( const ast::EnumDecl * decl ) {
332        return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
333}
334
335ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPosProto() const {
336        return genProto(
337                "_successor_",
338                {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
339                {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
340        );
341}
342
343ast::FunctionDecl* EnumAttrFuncGenerator::genPredPosProto() const {
344        return genProto(
345                "_predessor_",
346                {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
347                {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
348        );
349}
350
351ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
352        const ast::EnumAttribute attr, const CodeLocation& location,
353        std::vector<ast::ptr<ast::Init>>& inits) const {
354        ast::ArrayType* arrT = new ast::ArrayType(
355                attr == ast::EnumAttribute::Value
356                        ? decl->base
357                        : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
358                ast::ConstantExpr::from_int(decl->location, decl->members.size()),
359                ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
360
361        ast::ObjectDecl* objDecl =
362                new ast::ObjectDecl(
363                        decl->location, decl->getUnmangeldArrayName( attr ),
364                        arrT, new ast::ListInit( location, std::move( inits ) ),
365                        ast::Storage::Static, ast::Linkage::AutoGen );
366
367        return objDecl;
368}
369
370void EnumAttrFuncGenerator::genValueOrLabelBody(
371        ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
372        ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
373                func->location, "?[?]",
374                {new ast::NameExpr(func->location, arrDecl->name),
375                        new ast::CastExpr(
376                                func->location,
377                                new ast::VariableExpr( func->location, func->params.front() ),
378                                new ast::EnumAttrType( new ast::EnumInstType(decl),
379                                        ast::EnumAttribute::Posn))});
380        func->stmts = new ast::CompoundStmt(
381                func->location, {new ast::ReturnStmt(func->location, untyped)});
382}
383
384void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
385        auto castExpr = new ast::CastExpr(
386                func->location,
387                new ast::VariableExpr(func->location, func->params.front()),
388                new ast::EnumAttrType(new ast::EnumInstType(decl),
389                                                          ast::EnumAttribute::Posn));
390        func->stmts = new ast::CompoundStmt(
391                func->location, {new ast::ReturnStmt(func->location, castExpr)});
392}
393
394void EnumAttrFuncGenerator::genAttributesDecls(const ast::EnumAttribute attr) {
395        if (attr == ast::EnumAttribute::Value ||
396                attr == ast::EnumAttribute::Label) {
397                std::vector<ast::ptr<ast::Init>> inits =
398                        attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
399                ast::ObjectDecl* arrayProto =
400                        genAttrArrayProto(attr, getLocation(), inits);
401                forwards.push_back(arrayProto);
402
403                ast::FunctionDecl* funcProto = ( attr == ast::EnumAttribute::Value )
404                                               ? genValueProto()
405                                               : genLabelProto();
406                produceForwardDecl(funcProto);
407                genValueOrLabelBody(funcProto, arrayProto);
408                produceDecl(funcProto);
409        } else {
410                ast::FunctionDecl* funcProto = genPosnProto();
411                produceForwardDecl(funcProto);
412                genPosnBody(funcProto);
413                produceDecl(funcProto);
414        }
415}
416
417ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPredFunc(bool succ) {
418        ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
419        produceForwardDecl(funcDecl);
420
421        const CodeLocation& location = getLocation();
422
423        auto& params = funcDecl->params;
424        assert(params.size() == 1);
425        auto param = params.front().strict_as<ast::ObjectDecl>();
426
427
428        auto rets = funcDecl->returns;
429        assert(params.size() == 1);
430        auto ret = rets.front().strict_as<ast::ObjectDecl>();
431        auto retType = ret->type.strict_as<ast::EnumAttrType>();
432
433        auto addOneExpr = ast::UntypedExpr::createCall( location,
434                succ? "?+?": "?-?",
435                {new ast::VariableExpr(location, param),
436                ast::ConstantExpr::from_int(location, 1)}
437        );
438
439        funcDecl->stmts = new ast::CompoundStmt(
440                location, {
441                        new ast::ReturnStmt(
442                                location,
443                                new ast::CastExpr(location, addOneExpr, retType)
444                        )
445                }
446        );
447
448        return funcDecl;
449}
450
451void EnumAttrFuncGenerator::genAttrFunctions() {
452        if (decl->base) {
453                genAttributesDecls(ast::EnumAttribute::Value);
454                genAttributesDecls(ast::EnumAttribute::Label);
455                genAttributesDecls(ast::EnumAttribute::Posn);
456        }
457}
458
459void EnumAttrFuncGenerator::genSuccPredDecl() {
460        if (decl->base) {
461                auto succProto = genSuccProto();
462                auto predProto = genPredProto();
463
464                produceForwardDecl(succProto);
465                produceForwardDecl(predProto);
466        }
467}
468
469void EnumAttrFuncGenerator::genSuccPredPosn() {
470        if (decl->base) {
471                ast::FunctionDecl* succ = genSuccPredFunc(true);
472                ast::FunctionDecl* pred = genSuccPredFunc(false);
473
474                produceDecl(succ);
475                produceDecl(pred);
476        }
477}
478
479void EnumAttrFuncGenerator::generateAndAppendFunctions(
480        std::list<ast::ptr<ast::Decl>>& decls) {
481        // Generate the functions (they go into forwards and definitions).
482        genAttrStandardFuncs();
483        genAttrFunctions();
484        genSuccPredDecl();
485        genSuccPredPosn(); // Posn
486        // Now export the lists contents.
487        decls.splice(decls.end(), forwards);
488        decls.splice(decls.end(), definitions);
489}
490
491// ---------------------------------------------------------
492
493struct ImplementEnumFunc final :
494                public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting {
495        void previsit(const ast::EnumDecl* enumDecl);
496        void previsit(const ast::FunctionDecl* functionDecl);
497        void postvisit(const ast::FunctionDecl* functionDecl);
498
499private:
500        // Current level of nested functions.
501        unsigned int functionNesting = 0;
502};
503
504void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
505        if (!enumDecl->body) return;
506        if (!enumDecl->base) return;
507
508        ast::EnumInstType enumInst(enumDecl->name);
509        enumInst.base = enumDecl;
510
511        EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
512        gen.generateAndAppendFunctions(declsToAddAfter);
513}
514
515void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
516        functionNesting += 1;
517}
518
519void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
520        functionNesting -= 1;
521}
522
523} // namespace
524
525void implementEnumFunc(ast::TranslationUnit& translationUnit) {
526        ast::Pass<ImplementEnumFunc>::run(translationUnit);
527}
528
529} // namespace Validate
Note: See TracBrowser for help on using the repository browser.