source: src/Validate/ImplementEnumFunc.cpp @ 76c7addb

Last change on this file since 76c7addb was 76c7addb, checked in by JiadaL <j82liang@…>, 6 months ago

Fix Enum predecessor

  • Property mode set to 100644
File size: 19.5 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        return new ast::CompoundStmt(
159            location,
160            {new ast::ExprStmt(
161                location,
162                new ast::UntypedExpr(
163                    location, new ast::NameExpr(location, "__builtin_memcpy"),
164                    {
165                        new ast::AddressExpr(location, new ast::VariableExpr(
166                                                           location, dstParam)),
167                        new ast::AddressExpr(location, new ast::VariableExpr(
168                                                           location, srcParam)),
169                        new ast::SizeofExpr(location, srcParam->type),
170                    }))});
171    }
172
173    void genDtorBody(ast::FunctionDecl* func) {
174        const CodeLocation& location = func->location;
175        auto& params = func->params;
176        assert(1 == params.size());
177        func->stmts = new ast::CompoundStmt(location);
178        addUnusedAttribute(params.front());
179
180        // Just an extra step to make the forward and declaration match.
181        if (forwards.empty()) return;
182        ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
183            forwards.back().get_and_mutate());
184        addUnusedAttribute(fwd->params.front());
185    }
186
187    // ast::FunctionDecl*
188    // ----------------------------------------------------
189
190    ast::FunctionDecl* genSuccPredFunc(bool succ);
191
192    const ast::Init* getAutoInit(const ast::Init* prev) const;
193
194    std::vector<ast::ptr<ast::Init>> genLabelInit() const;
195
196    std::vector<ast::ptr<ast::Init>> genValueInit() const;
197    ast::ObjectDecl* genAttrArrayProto(
198        const ast::EnumAttribute attr, const CodeLocation& location,
199        std::vector<ast::ptr<ast::Init>>& inits) const;
200    void genValueOrLabelBody(ast::FunctionDecl* func,
201                             ast::ObjectDecl* arrDecl) const;
202    void genPosnBody(ast::FunctionDecl* func) const;
203    void genAttributesDecls(const ast::EnumAttribute attr);
204};
205
206std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
207    std::vector<ast::ptr<ast::Init>> inits;
208    for (size_t i = 0; i < decl->members.size(); i++) {
209        ast::ptr<ast::Decl> mem = decl->members.at(i);
210        auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
211        assert(memAsObjectDecl);
212        inits.emplace_back(new ast::SingleInit(
213            mem->location,
214            ast::ConstantExpr::from_string(mem->location, mem->name)));
215    }
216    return inits;
217}
218
219std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
220    std::vector<ast::ptr<ast::Init>> inits;
221    for (size_t i = 0; i < decl->members.size(); i++) {
222        ast::ptr<ast::Decl> mem = decl->members.at(i);
223        auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
224        assert(memAsObjectDecl);
225        if (memAsObjectDecl->init) {
226            inits.emplace_back(memAsObjectDecl->init);
227        } else {
228            const CodeLocation& location = mem->location;
229            if (i == 0) {
230                inits.emplace_back(new ast::SingleInit(
231                    location, ast::ConstantExpr::from_int(mem->location, 0)));
232            } else {
233                inits.emplace_back(getAutoInit(inits.at(i - 1)));
234            }
235        }
236    }
237    return inits;
238}
239const ast::Init* EnumAttrFuncGenerator::getAutoInit(
240    const ast::Init* prev) const {
241    if (prev == nullptr) {
242        return new ast::SingleInit(
243            getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
244    }
245    auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
246    assert(prevInit);
247    auto prevInitExpr = prevInit->value;
248    if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
249        // Assume no string literal for now
250        return new ast::SingleInit(
251            getLocation(), ast::ConstantExpr::from_int(
252                               getLocation(), constInit->intValue() + 1));
253    } else {
254        auto untypedThisInit = new ast::UntypedExpr(
255            getLocation(), new ast::NameExpr(getLocation(), "?++"),
256            {prevInitExpr});
257        return new ast::SingleInit(getLocation(), untypedThisInit);
258    }
259}
260
261ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
262    std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
263    std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
264    ast::FunctionDecl* decl = new ast::FunctionDecl(
265        // Auto-generated routines use the type declaration's location.
266        getLocation(), std::move(name), {}, {}, std::move(params),
267        std::move(returns),
268        // Only a prototype, no body.
269        nullptr,
270        // Use static storage if we are at the top level.
271        (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
272        proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
273        // Auto-generated routines are inline to avoid conflicts.
274        ast::Function::Specs(ast::Function::Inline));
275    decl->fixUniqueId();
276    return decl;
277}
278
279void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
280    assert(nullptr != decl->stmts);
281
282    definitions.push_back(decl);
283}
284
285void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
286    if (0 != functionNesting) return;
287    ast::FunctionDecl* fwd =
288        (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
289    fwd->fixUniqueId();
290    forwards.push_back(fwd);
291}
292
293ast::FunctionDecl* EnumAttrFuncGenerator::genPosnProto() const {
294    return genProto(
295        "posE",
296        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
297        {new ast::ObjectDecl(getLocation(), "_ret",
298                             new ast::EnumAttrType(new ast::EnumInstType(decl),
299                                                   ast::EnumAttribute::Posn))});
300}
301
302ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
303    return genProto(
304        "labelE",
305        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
306        {new ast::ObjectDecl(
307            getLocation(), "_ret",
308            new ast::PointerType(new ast::BasicType{ast::BasicType::Char}))});
309}
310
311ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
312    return genProto(
313        "valueE",
314        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
315        {new ast::ObjectDecl(getLocation(), "_ret",
316                             ast::deepCopy(decl->base))});
317}
318
319ast::FunctionDecl* EnumAttrFuncGenerator::genSuccProto() const {
320    return genProto(
321        "succ",
322        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
323        {new ast::ObjectDecl(getLocation(), "_ret",
324                             new ast::EnumInstType(decl))});
325}
326
327ast::FunctionDecl* EnumAttrFuncGenerator::genPredProto() const {
328    return genProto(
329        "pred",
330        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
331        {new ast::ObjectDecl(getLocation(), "_ret",
332                             new ast::EnumInstType(decl))});
333}
334
335inline ast::EnumAttrType * getPosnType( const ast::EnumDecl * decl ) {
336    return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
337}
338
339ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPosProto() const {
340    return genProto(
341        "_successor_",
342        {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
343        {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
344    );
345}
346
347ast::FunctionDecl* EnumAttrFuncGenerator::genPredPosProto() const {
348    return genProto(
349        "_predessor_",
350        {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
351        {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
352    );
353}
354
355ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
356    const ast::EnumAttribute attr, const CodeLocation& location,
357    std::vector<ast::ptr<ast::Init>>& inits) const {
358    ast::ArrayType* arrT = new ast::ArrayType(
359        attr == ast::EnumAttribute::Value
360            ? decl->base
361            : new ast::PointerType(new ast::BasicType{ast::BasicType::Char}),
362        ast::ConstantExpr::from_int(decl->location, decl->members.size()),
363        ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
364
365    ast::ObjectDecl* objDecl =
366        new ast::ObjectDecl(decl->location, decl->getUnmangeldArrayName(attr),
367                            arrT, new ast::ListInit(location, std::move(inits)),
368                            ast::Storage::Static, ast::Linkage::AutoGen);
369
370    return objDecl;
371}
372
373void EnumAttrFuncGenerator::genValueOrLabelBody(
374    ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
375    ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
376        func->location, "?[?]",
377        {new ast::NameExpr(func->location, arrDecl->name),
378         new ast::CastExpr(
379             func->location,
380             new ast::VariableExpr(func->location, func->params.front()),
381             new ast::EnumAttrType(new ast::EnumInstType(decl),
382                                   ast::EnumAttribute::Posn))});
383    func->stmts = new ast::CompoundStmt(
384        func->location, {new ast::ReturnStmt(func->location, untyped)});
385}
386
387void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
388    auto castExpr = new ast::CastExpr(
389        func->location,
390        new ast::VariableExpr(func->location, func->params.front()),
391        new ast::EnumAttrType(new ast::EnumInstType(decl),
392                              ast::EnumAttribute::Posn));
393    func->stmts = new ast::CompoundStmt(
394        func->location, {new ast::ReturnStmt(func->location, castExpr)});
395}
396
397void EnumAttrFuncGenerator::genAttributesDecls(const ast::EnumAttribute attr) {
398    if (attr == ast::EnumAttribute::Value ||
399        attr == ast::EnumAttribute::Label) {
400        std::vector<ast::ptr<ast::Init>> inits =
401            attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
402        ast::ObjectDecl* arrayProto =
403            genAttrArrayProto(attr, getLocation(), inits);
404        forwards.push_back(arrayProto);
405
406        ast::FunctionDecl* funcProto = attr == ast::EnumAttribute::Value
407                                           ? genValueProto()
408                                           : genLabelProto();
409        produceForwardDecl(funcProto);
410        genValueOrLabelBody(funcProto, arrayProto);
411        produceDecl(funcProto);
412    } else {
413        ast::FunctionDecl* funcProto = genPosnProto();
414        produceForwardDecl(funcProto);
415        genPosnBody(funcProto);
416        produceDecl(funcProto);
417    }
418}
419
420ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPredFunc(bool succ) {
421    ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
422    produceForwardDecl(funcDecl);
423
424    const CodeLocation& location = getLocation();
425
426    auto& params = funcDecl->params;
427    assert(params.size() == 1);
428    auto param = params.front().strict_as<ast::ObjectDecl>();
429
430
431    auto rets = funcDecl->returns;
432    assert(params.size() == 1);
433    auto ret = rets.front().strict_as<ast::ObjectDecl>();
434    auto retType = ret->type.strict_as<ast::EnumAttrType>();
435
436    auto addOneExpr = ast::UntypedExpr::createCall( location,
437        succ? "?+?": "?-?",
438        {new ast::VariableExpr(location, param),
439        ast::ConstantExpr::from_int(location, 1)}
440    );
441
442    funcDecl->stmts = new ast::CompoundStmt(
443        location, {
444            new ast::ReturnStmt(
445                location, 
446                new ast::CastExpr(location, addOneExpr, retType) 
447            )
448        }
449    );
450
451    return funcDecl;
452}
453
454void EnumAttrFuncGenerator::genAttrFunctions() {
455    if (decl->base) {
456        genAttributesDecls(ast::EnumAttribute::Value);
457        genAttributesDecls(ast::EnumAttribute::Label);
458        genAttributesDecls(ast::EnumAttribute::Posn);
459    }
460}
461
462void EnumAttrFuncGenerator::genSuccPredDecl() {
463    if (decl->base) {
464        auto succProto = genSuccProto();
465        auto predProto = genPredProto();
466
467        produceForwardDecl(succProto);
468        produceForwardDecl(predProto);
469    }
470}
471
472void EnumAttrFuncGenerator::genSuccPredPosn() {
473    if (decl->base) {
474        ast::FunctionDecl* succ = genSuccPredFunc(true);
475        ast::FunctionDecl* pred = genSuccPredFunc(false);
476
477        produceDecl(succ);
478        produceDecl(pred);
479    }
480}
481
482void EnumAttrFuncGenerator::generateAndAppendFunctions(
483    std::list<ast::ptr<ast::Decl>>& decls) {
484    // Generate the functions (they go into forwards and definitions).
485    genAttrStandardFuncs();
486    genAttrFunctions();
487    genSuccPredDecl();
488    genSuccPredPosn(); // Posn
489    // Now export the lists contents.
490    decls.splice(decls.end(), forwards);
491    decls.splice(decls.end(), definitions);
492}
493
494// ---------------------------------------------------------
495
496struct ImplementEnumFunc final : public ast::WithDeclsToAdd<>,
497                                 public ast::WithShortCircuiting {
498    void previsit(const ast::EnumDecl* enumDecl);
499    void previsit(const ast::FunctionDecl* functionDecl);
500    void postvisit(const ast::FunctionDecl* functionDecl);
501
502   private:
503    // Current level of nested functions.
504    unsigned int functionNesting = 0;
505};
506
507void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
508    if (!enumDecl->body) return;
509    if (!enumDecl->base) return;
510
511    ast::EnumInstType enumInst(enumDecl->name);
512    enumInst.base = enumDecl;
513
514    EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
515    gen.generateAndAppendFunctions(declsToAddAfter);
516}
517
518void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
519    functionNesting += 1;
520}
521
522void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
523    functionNesting -= 1;
524}
525
526}  // namespace
527
528void implementEnumFunc(ast::TranslationUnit& translationUnit) {
529    ast::Pass<ImplementEnumFunc>::run(translationUnit);
530}
531}  // namespace Validate
Note: See TracBrowser for help on using the repository browser.