source: src/Validate/ImplementEnumFunc.cpp @ 7a780ad

Last change on this file since 7a780ad was 7a780ad, checked in by Andrew Beach <ajbeach@…>, 3 months ago

Moved ast::BasicType::Kind to ast::BasicKind? in its own hearder. This is more consistent with other utility enums (although we still use this as a enum class) and reduces what some files need to include. Also did a upgrade in a comment with MAX_INTEGER_TYPE, it is now part of the enum.

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