source: src/Validate/ReplacePseudoFunc.cpp @ 647d633

Last change on this file since 647d633 was bbf2cb1, checked in by JiadaL <j82liang@…>, 3 months ago

Add the Working support to succ() and pred() pseudo function to Enum

  • Property mode set to 100644
File size: 22.8 KB
Line 
1#include "ReplacePseudoFunc.hpp"
2
3#include <set>
4
5#include "AST/Decl.hpp"
6#include "AST/Inspect.hpp"
7#include "AST/Pass.hpp"
8#include "AST/Print.hpp"
9#include "AST/Stmt.hpp"
10#include "Common/utility.h"
11#include "ResolvExpr/CandidateFinder.hpp"
12#include "ResolvExpr/Resolver.h"
13#include "SymTab/Mangler.h"
14
15namespace Validate {
16
17namespace {
18
19std::set<std::string> queryLabels;
20std::set<std::string> queryValues;
21
22struct ReplaceEnumInstWithPos final : public ast::WithShortCircuiting {
23    const ast::ObjectDecl* postvisit(const ast::ObjectDecl* decl) {
24        auto enumInst = decl->type.strict_as<ast::EnumInstType>();
25        auto enumPos = new ast::EnumPosType(enumInst);
26        auto ret = ast::mutate_field(decl, &ast::ObjectDecl::type, enumPos);
27        ret = ast::mutate_field(ret, &ast::ObjectDecl::mangleName,
28                                Mangle::mangle(ret));
29        return ret;
30    }
31};
32
33const inline std::string getValueArrayName(std::string enumName) {
34    return "values_" + enumName;
35}
36
37// struct AutoInit {
38//     ast::EnumDecl const* postvisit( const ast::EnumDecl* expr );
39// };
40
41struct WrapEnumValueExpr final : public ast::WithShortCircuiting,
42                                 public ast::WithSymbolTable,
43                                 public ast::WithConstTranslationUnit {
44    void previsit(const ast::DeclStmt* expr);
45    void previsit(const ast::ApplicationExpr* expr);
46    void previsit(const ast::CastExpr* expr);
47    void previsit(const ast::VariableExpr*) { visit_children = false; }
48
49    ast::Expr const* postvisit(const ast::VariableExpr* expr);
50};
51
52struct FindGenEnumArray final : public ast::WithShortCircuiting {
53    void previsit(const ast::ApplicationExpr* enumDecl);
54};
55
56struct PseudoFuncGenerateRoutine final : public ast::WithDeclsToAdd<>,
57                                         public ast::WithSymbolTable,
58                                         public ast::WithShortCircuiting,
59                                         public ast::WithConstTranslationUnit {
60    void previsit(const ast::EnumDecl* enumDecl);
61};
62
63struct ReplacePseudoFuncCore : public ast::WithShortCircuiting,
64                               public ast::WithSymbolTable,
65                               public ast::WithConstTranslationUnit {
66    ast::Expr const* postvisit(ast::ApplicationExpr const* decl);
67};
68
69// ast::EnumDecl const * AutoInit::postvisit( const ast::EnumDecl * expr ) {
70//     for ( size_t i = 0; i < expr->members.size(); i++ ) {
71//         auto mem = expr->members[i].as<ast::ObjectDecl>();
72//         assert( mem );
73//         if ( mem->init )
74//     }
75//     return expr;
76// }
77
78void WrapEnumValueExpr::previsit(const ast::ApplicationExpr* expr) {
79    auto varExpr = expr->func.as<ast::VariableExpr>();
80    auto fname = ast::getFunctionName(expr);
81    if (!varExpr || varExpr->var->linkage == ast::Linkage::Intrinsic) {
82        if (fname == "?{}" || fname == "?=?") visit_children = false;
83    }
84
85    if (fname == "labelE" || fname == "valueE" || fname == "posE" ||
86        fname == "pred" || fname == "succ") {
87        visit_children = false;
88    }
89}
90
91void WrapEnumValueExpr::previsit(const ast::DeclStmt*) {
92    visit_children = false;
93}
94
95void WrapEnumValueExpr::previsit(const ast::CastExpr* expr) {
96    if (expr->result && expr->result.as<ast::ReferenceType>()) {
97        visit_children = false;
98    }
99}
100
101ast::Expr const* WrapEnumValueExpr::postvisit(const ast::VariableExpr* expr) {
102    if (!expr->result) {
103        return expr;
104    }
105    if (auto enumInst = expr->result.as<ast::EnumInstType>()) {
106        if (enumInst->base && enumInst->base->base) {
107            auto untyped = new ast::UntypedExpr(
108                expr->location, new ast::NameExpr(expr->location, "valueE"),
109                {std::move(expr)});
110            ResolvExpr::ResolveContext context{symtab, transUnit().global};
111            auto result = ResolvExpr::findVoidExpression(untyped, context);
112            ast::ptr<ast::ApplicationExpr> ret =
113                result.strict_as<ast::ApplicationExpr>();
114            return ast::deepCopy(ret);
115        }
116    }
117    return expr;
118}
119
120void FindGenEnumArray::previsit(const ast::ApplicationExpr* expr) {
121    auto fname = ast::getFunctionName(expr);
122    if (fname == "labelE" || fname == "valueE") {
123        if (expr->args.size() != 1) {
124            SemanticError(expr, "Position Expression only take one parameter");
125        }
126        const ast::VariableExpr* arg =
127            expr->args.front().as<const ast::VariableExpr>();
128        if (!arg) {
129            SemanticError(expr, "Unimplement Pseudo Function Cases");
130        }
131        const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
132        const std::string referredName = argAsVar->name;
133        const ast::EnumInstType* argType =
134            argAsVar->type.as<const ast::EnumInstType>();
135        if (!argType) {
136            SemanticError(
137                argAsVar,
138                "Position can only be used on an enumeration instance");
139        }
140        ast::ptr<ast::EnumDecl> base = argType->base;
141        assert(base);
142        if (fname == "labelE") queryLabels.insert(base->name);
143        if (fname == "valueE") queryValues.insert(base->name);
144    }
145}
146
147const ast::Init* getAutoInit(const CodeLocation& location,
148                             const ast::Type* type,
149                             ResolvExpr::ResolveContext context,
150                             const ast::Init* prev) {
151    if (auto prevInit = dynamic_cast<const ast::SingleInit*>(prev)) {
152        auto prevInitExpr = prevInit->value;
153        if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
154            // Assume no string literal for now
155            return new ast::SingleInit(
156                location, ast::ConstantExpr::from_int(
157                              location, constInit->intValue() + 1));
158        } else {
159            auto untypedThisInit = new ast::UntypedExpr(
160                location, new ast::NameExpr(location, "?++"), {prevInitExpr});
161            auto typedInit = ResolvExpr::findSingleExpression(untypedThisInit,
162                                                              type, context);
163            return new ast::SingleInit(location, typedInit);
164        }
165    }
166    SemanticError(prev, "Auto Init a List is not implemented");
167    return prev;
168}
169
170void PseudoFuncGenerateRoutine::previsit(const ast::EnumDecl* enumDecl) {
171    visit_children = false;
172    const CodeLocation& location = enumDecl->location;
173    if (enumDecl->members.size() == 0 || !enumDecl->base) return;
174
175    std::vector<ast::ptr<ast::Init>> inits;
176    std::vector<ast::ptr<ast::Init>> labels;
177    auto type = enumDecl->base;
178
179    for (size_t i = 0; i < enumDecl->members.size(); i++) {
180        ast::ptr<ast::Decl> mem = enumDecl->members.at(i);
181        auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
182        assert(memAsObjectDecl);
183        if (memAsObjectDecl->init) {
184            inits.emplace_back(memAsObjectDecl->init);
185        } else {
186            const CodeLocation& location = mem->location;
187            if (i == 0) {
188                inits.emplace_back(new ast::SingleInit(
189                    location, ast::ConstantExpr::from_int(mem->location, 0)));
190            } else {
191                inits.emplace_back(getAutoInit(
192                    location, enumDecl->base,
193                    ResolvExpr::ResolveContext{symtab, transUnit().global},
194                    inits.at(i - 1).as<ast::SingleInit>()));
195            }
196        }
197        labels.emplace_back(new ast::SingleInit(
198            location, ast::ConstantExpr::from_string(location, mem->name)));
199    }
200    if (queryValues.count(enumDecl->name)) {
201        auto init = new ast::ListInit(location, std::move(inits));
202        const ast::ArrayType* arrT = new ast::ArrayType(
203            enumDecl->base,
204            ast::ConstantExpr::from_int(location, enumDecl->members.size()),
205            ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
206        ast::ObjectDecl* values = new ast::ObjectDecl(
207            location, "values_" + enumDecl->name, arrT, init,
208            ast::Storage::Static, ast::Linkage::AutoGen);
209        symtab.addId(values);
210        values->mangleName = Mangle::mangle(values);
211        declsToAddAfter.push_back(values);
212    }
213    if (queryLabels.count(enumDecl->name)) {
214        auto label_strings = new ast::ListInit(location, std::move(labels));
215        auto labels = new ast::ObjectDecl(
216            location, "labels_" + enumDecl->name,
217            new ast::ArrayType(
218                new ast::PointerType(new ast::BasicType{ast::BasicType::Char}),
219                ast::ConstantExpr::from_int(location, enumDecl->members.size()),
220                ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim),
221            label_strings, ast::Storage::Static, ast::Linkage::AutoGen);
222        symtab.addId(labels);
223        labels->mangleName = Mangle::mangle(labels);
224        declsToAddAfter.push_back(labels);
225    }
226}
227
228ast::ApplicationExpr const* resolveAttributeFunctions(
229    const CodeLocation location, ResolvExpr::ResolveContext context,
230    const ast::VariableExpr* arg, const ast::EnumDecl* base,
231    const std::string& name) {
232    ast::Expr* toResolve = new ast::NameExpr(location, name + base->name);
233    // Find the request arrary
234    auto arr = ResolvExpr::findVoidExpression(toResolve, context);
235    assert(arr.get());
236    auto arrAsVar = arr.strict_as<ast::VariableExpr>();
237    // change EnumInstType to EnumPosType to avoid recursive resolution
238    auto argAsDecl = arg->var.as<ast::ObjectDecl>();
239    if (argAsDecl->type.as<ast::EnumInstType>()) {
240        ast::Pass<ReplaceEnumInstWithPos> replacer;
241        auto rep = argAsDecl->accept(replacer);
242        auto mutatedArg = ast::mutate_field(arg, &ast::VariableExpr::var, rep);
243        mutatedArg = ast::mutate_field(mutatedArg, &ast::VariableExpr::result,
244                                       mutatedArg->var->get_type());
245        auto untyped =
246            new ast::UntypedExpr(location, new ast::NameExpr(location, "?[?]"),
247                                 {std::move(arrAsVar), mutatedArg});
248        auto typedResult = ResolvExpr::findVoidExpression(untyped, context);
249        ast::ptr<ast::ApplicationExpr> ret =
250            typedResult.strict_as<ast::ApplicationExpr>();
251        return ast::deepCopy(ret);
252    } else {
253        auto untyped =
254            new ast::UntypedExpr(location, new ast::NameExpr(location, "?[?]"),
255                                 {std::move(arrAsVar), arg});
256        auto typedResult = ResolvExpr::findVoidExpression(untyped, context);
257
258        ast::ptr<ast::ApplicationExpr> ret =
259            typedResult.strict_as<ast::ApplicationExpr>();
260        return ast::deepCopy(ret);
261    }
262}
263
264ast::Expr const* ReplacePseudoFuncCore::postvisit(
265    ast::ApplicationExpr const* expr) {
266    auto fname = ast::getFunctionName(expr);
267    auto location = expr->location;
268    if (fname == "posE" || fname == "valueE" || fname == "labelE") {
269        if (expr->args.size() != 1) {
270            SemanticError(expr,
271                          "Pseudo Enum Expression only take one parameter");
272        }
273        ast::ptr<ast::VariableExpr> arg =
274            expr->args.front().as<const ast::VariableExpr>();
275        if (!arg) {
276            SemanticError(expr, "Unimplement Pseudo Function Cases");
277        }
278        const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
279        const std::string referredName = argAsVar->name;
280
281        if (const ast::EnumInstType* argTypeAsEnumInst =
282                argAsVar->type.as<const ast::EnumInstType>()) {
283            const ast::EnumDecl* base = argTypeAsEnumInst->base;
284            ResolvExpr::ResolveContext context{symtab, transUnit().global};
285            // If resolvable as constant
286            for (size_t i = 0; i < base->members.size(); i++) {
287                if (base->members[i]->name == referredName) {
288                    if (fname == "posE")
289                        return ast::ConstantExpr::from_int(expr->location, i);
290                    else if (fname == "labelE")
291                        return ast::ConstantExpr::from_string(expr->location,
292                                                              referredName);
293                    else {
294                        return resolveAttributeFunctions(
295                            location, context, arg.get(), base, "values_");
296                    }
297                }
298            }
299
300            if (fname == "labelE") {
301                if (auto labelExpr = resolveAttributeFunctions(
302                        location, context, arg.get(), base, "labels_")) {
303                    return labelExpr;
304                }
305            } else if (fname == "valueE") {
306                if (auto valueExpr = resolveAttributeFunctions(
307                        location, context, arg.get(), base, "values_")) {
308                    return valueExpr;
309                }
310            } else {  // it is position; replace itself
311                return std::move(arg.get());
312            }
313        } else if (const ast::EnumPosType* argTypeAsPos =
314                       argAsVar->type.as<const ast::EnumPosType>()) {
315            const ast::EnumDecl* base = argTypeAsPos->instance->base;
316            ResolvExpr::ResolveContext context{symtab, transUnit().global};
317            if (fname == "labelE") {
318                if (auto labelExpr = resolveAttributeFunctions(
319                        location, context, arg.get(), base, "labels_")) {
320                    return labelExpr;
321                }
322            } else if (fname == "valueE") {
323                if (auto valueExpr = resolveAttributeFunctions(
324                        location, context, arg.get(), base, "values_")) {
325                    return valueExpr;
326                }
327            } else {  // it is position; replace itself
328                return std::move(arg.get());
329            }
330        } else {
331            SemanticError(argAsVar,
332                          "Pseudo Enum Expression can only be used on an "
333                          "enumeration instance");
334        }
335    }
336    return expr;
337}
338
339ast::ptr<ast::Expr> reduceCastExpr(ast::ptr<ast::Expr> expr) {
340    if (auto castExpr = expr.as<ast::CastExpr>()) {
341        return reduceCastExpr(castExpr->arg);
342    }
343    return expr;
344}
345
346struct ReplaceEnumInst final {
347    const ast::Expr* postvisit(const ast::ApplicationExpr* expr) {
348        auto fname = ast::getFunctionName(expr);
349        if (fname == "?[?]") {
350            if (expr->args.size() != 2) return expr;
351
352            auto arg1AsVar =
353                reduceCastExpr(expr->args.front()).as<ast::VariableExpr>();
354            auto arg2AsVar =
355                reduceCastExpr(expr->args.back()).as<ast::VariableExpr>();
356
357            if (!arg1AsVar || !arg2AsVar) return expr;
358
359            auto arg1AsDecl = arg1AsVar->var.as<ast::ObjectDecl>();
360            auto arg2AsDecl = arg2AsVar->var.as<ast::ObjectDecl>();
361
362            if (!arg1AsDecl || !arg2AsDecl) return expr;
363            auto arrInst = arg1AsDecl->type.as<ast::ArrayType>();
364            auto pointerInst = arg1AsDecl->type.as<ast::PointerType>();
365            if (!arrInst && !pointerInst) {
366                return expr;
367            }
368            auto enumInst = arg2AsDecl->type.as<ast::EnumInstType>();
369            if (!enumInst) return expr;
370
371            const std::string arrName = arg1AsDecl->name;
372            if (arrName != getValueArrayName(enumInst->base->name)) return expr;
373            ast::Pass<ReplaceEnumInstWithPos> replacer;
374            auto rep = arg2AsDecl->accept(replacer);
375            if (!rep) return expr;
376            auto mutObj =
377                ast::mutate_field(arg2AsVar, &ast::VariableExpr::var, rep);
378            mutObj = ast::mutate_field(mutObj, &ast::VariableExpr::result,
379                                       mutObj->var->get_type());
380            auto mut = ast::mutate_field_index(
381                expr, &ast::ApplicationExpr::args, 1, mutObj);
382            return mut;
383        }
384        // else if (fname == "succ" || fname == "pred") {
385        //     if (expr->args.size() != 1) return expr;
386        //     auto argExpr = expr->args.front();
387        //     auto argAsVar = reduceCastExpr(argExpr).as<ast::VariableExpr>();
388
389        //     if (auto argAsDecl = argAsVar->var.as<ast::ObjectDecl>()) {
390        //         if (auto enumInst = argAsDecl->type.as<ast::EnumInstType>())
391        //         {
392        //             auto enumPos = new ast::EnumPosType(enumInst);
393        //             auto castExpr =
394        //                 new ast::CastExpr(argExpr->location, argExpr,
395        //                 enumPos);
396        //             auto mut = ast::mutate_field_index(
397        //                 expr, &ast::ApplicationExpr::args, 0, castExpr);
398        //             return mut;
399        //         } else if (auto enumPos =
400        //                        argAsDecl->type.as<ast::EnumPosType>()) {
401        //             //     std::cout << "pos" << std::endl;
402        //             return expr;
403        //         }
404        //     }
405        // }
406        return expr;
407    }
408};
409
410struct ReplaceSuccAndPred final : public ast::WithSymbolTable,
411                                  public ast::WithConstTranslationUnit {
412    const ast::Expr* postvisit(const ast::ApplicationExpr* expr) {
413        auto fname = ast::getFunctionName(expr);
414        if (fname == "succ" || fname == "pred") {
415            const CodeLocation& location = expr->location;
416            if (expr->args.size() != 1) return expr;
417
418            // if (auto argAsVar = reduceCastExpr(expr->args.front())
419            //                         .as<ast::VariableExpr>()) {
420            //     if (auto argAsDecl = argAsVar->var.as<ast::ObjectDecl>()) {
421            //         auto enumPos = argAsDecl->type.as<ast::EnumPosType>();
422            //         if (!enumPos) return expr;
423            //         // ast::Pass<ReplaceEnumInstWithPos> replacer;
424            //         // auto posObj = argAsDecl->accept(replacer);
425            //         // if (!posObj) return expr;
426
427            //         // auto newParam = new ast::VariableExpr( location,
428            //         posObj
429            //         // );
430
431            //         auto untyped = new ast::UntypedExpr(
432            //             location,
433            //             new ast::NameExpr(location, fname == "succ"
434            //                                             ? "_successor_"
435            //                                             : "_predessor_"),
436            //             {argAsVar});
437
438            //         ResolvExpr::ResolveContext context{symtab,
439            //                                            transUnit().global};
440
441            //         auto typedResult =
442            //             ResolvExpr::findVoidExpression(untyped, context);
443
444            //         ast::ptr<ast::ApplicationExpr> ret =
445            //             typedResult.strict_as<ast::ApplicationExpr>();
446
447            //         return ast::deepCopy(ret);
448            //     }
449            // }
450            auto param = expr->args.front();
451            if (auto argAsVar = reduceCastExpr(param).as<ast::VariableExpr>()) {
452                if (auto argAsDecl = argAsVar->var.as<ast::ObjectDecl>()) {
453                    if (auto enumInst =
454                            argAsDecl->type.as<ast::EnumInstType>()) {
455                        auto castTo = new ast::EnumPosType(enumInst);
456                        auto castExpr =
457                            new ast::CastExpr(param->location, param, castTo);
458
459                        auto untyped = new ast::UntypedExpr(
460                            expr->location,
461                            new ast::NameExpr(location, fname == "succ"
462                                                            ? "_successor_"
463                                                            : "_predessor_"),
464                            {castExpr});
465                        ResolvExpr::ResolveContext context{symtab,
466                                                           transUnit().global};
467                        auto typedResult =
468                            ResolvExpr::findVoidExpression(untyped, context);
469                        ast::ptr<ast::ApplicationExpr> ret =
470                            typedResult.strict_as<ast::ApplicationExpr>();
471                        return ast::deepCopy(ret);
472                    } else if (auto posType =
473                                   argAsDecl->type.as<ast::EnumPosType>()) {
474                        // Very nasty fix. Must be revisit
475                        if (auto paramAsVar = param.as<ast::VariableExpr>()) {
476                            if (paramAsVar->result.as<ast::EnumInstType>()) {
477                                auto paramToUse = ast::mutate_field(
478                                    paramAsVar, &ast::VariableExpr::result,
479                                    posType);
480                                auto untyped = new ast::UntypedExpr(
481                                    expr->location,
482                                    new ast::NameExpr(location,
483                                                      fname == "succ"
484                                                          ? "_successor_"
485                                                          : "_predessor_"),
486                                    {paramToUse});
487                                ResolvExpr::ResolveContext context{
488                                    symtab, transUnit().global};
489                                auto typedResult =
490                                    ResolvExpr::findVoidExpression(untyped,
491                                                                   context);
492                                ast::ptr<ast::ApplicationExpr> ret =
493                                    typedResult
494                                        .strict_as<ast::ApplicationExpr>();
495                                return ast::deepCopy(ret);
496                            }
497                        }
498                        auto untyped = new ast::UntypedExpr(
499                            expr->location,
500                            new ast::NameExpr(location, fname == "succ"
501                                                            ? "_successor_"
502                                                            : "_predessor_"),
503                            {param});
504                        ResolvExpr::ResolveContext context{symtab,
505                                                           transUnit().global};
506                        auto typedResult =
507                            ResolvExpr::findVoidExpression(untyped, context);
508                        ast::ptr<ast::ApplicationExpr> ret =
509                            typedResult.strict_as<ast::ApplicationExpr>();
510                        return ast::deepCopy(ret);
511                    }
512                }
513            }
514        }
515        return expr;
516    }
517};
518
519}  // namespace
520
521void replacePseudoFunc(ast::TranslationUnit& translationUnit) {
522    ast::Pass<WrapEnumValueExpr>::run(translationUnit);
523    ast::Pass<FindGenEnumArray>::run(translationUnit);
524
525    ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
526    ast::Pass<ReplacePseudoFuncCore>::run(translationUnit);
527    ast::Pass<ReplaceEnumInst>::run(translationUnit);
528
529    ast::Pass<ReplaceSuccAndPred>::run(translationUnit);
530}
531}  // namespace Validate
Note: See TracBrowser for help on using the repository browser.