source: src/Validate/ReplacePseudoFunc.cpp @ b6a71bc

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

Remove conversion part of the EnumPosType?. It can be resolved by the current unifier

  • Property mode set to 100644
File size: 18.5 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 ReplaceSuccAndPred final : public ast::WithSymbolTable,
347                                  public ast::WithConstTranslationUnit {
348    const ast::Expr* postvisit(const ast::ApplicationExpr* expr) {
349        auto fname = ast::getFunctionName(expr);
350        if (fname == "succ" || fname == "pred") {
351            const CodeLocation& location = expr->location;
352            if (expr->args.size() != 1) return expr;
353
354            auto param = expr->args.front();
355            if (auto argAsVar = reduceCastExpr(param).as<ast::VariableExpr>()) {
356                if (auto argAsDecl = argAsVar->var.as<ast::ObjectDecl>()) {
357                    if (auto enumInst =
358                            argAsDecl->type.as<ast::EnumInstType>()) {
359                        auto castTo = new ast::EnumPosType(enumInst);
360                        auto castExpr =
361                            new ast::CastExpr(param->location, param, castTo);
362
363                        auto untyped = new ast::UntypedExpr(
364                            expr->location,
365                            new ast::NameExpr(location, fname == "succ"
366                                                            ? "_successor_"
367                                                            : "_predessor_"),
368                            {castExpr});
369                        ResolvExpr::ResolveContext context{symtab,
370                                                           transUnit().global};
371                        auto typedResult =
372                            ResolvExpr::findVoidExpression(untyped, context);
373                        ast::ptr<ast::ApplicationExpr> ret =
374                            typedResult.strict_as<ast::ApplicationExpr>();
375                        return ast::deepCopy(ret);
376                    } else if (auto posType =
377                                   argAsDecl->type.as<ast::EnumPosType>()) {
378                        // Very nasty fix. Must be revisit
379                        if (auto paramAsVar = param.as<ast::VariableExpr>()) {
380                            if (paramAsVar->result.as<ast::EnumInstType>()) {
381                                auto paramToUse = ast::mutate_field(
382                                    paramAsVar, &ast::VariableExpr::result,
383                                    posType);
384                                auto untyped = new ast::UntypedExpr(
385                                    expr->location,
386                                    new ast::NameExpr(location,
387                                                      fname == "succ"
388                                                          ? "_successor_"
389                                                          : "_predessor_"),
390                                    {paramToUse});
391                                ResolvExpr::ResolveContext context{
392                                    symtab, transUnit().global};
393                                auto typedResult =
394                                    ResolvExpr::findVoidExpression(untyped,
395                                                                   context);
396                                ast::ptr<ast::ApplicationExpr> ret =
397                                    typedResult
398                                        .strict_as<ast::ApplicationExpr>();
399                                return ast::deepCopy(ret);
400                            }
401                        }
402                        auto untyped = new ast::UntypedExpr(
403                            expr->location,
404                            new ast::NameExpr(location, fname == "succ"
405                                                            ? "_successor_"
406                                                            : "_predessor_"),
407                            {param});
408                        ResolvExpr::ResolveContext context{symtab,
409                                                           transUnit().global};
410                        auto typedResult =
411                            ResolvExpr::findVoidExpression(untyped, context);
412                        ast::ptr<ast::ApplicationExpr> ret =
413                            typedResult.strict_as<ast::ApplicationExpr>();
414                        return ast::deepCopy(ret);
415                    }
416                }
417            }
418        }
419        return expr;
420    }
421};
422
423}  // namespace
424
425void replacePseudoFunc(ast::TranslationUnit& translationUnit) {
426    ast::Pass<WrapEnumValueExpr>::run(translationUnit);
427    ast::Pass<FindGenEnumArray>::run(translationUnit);
428
429    ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
430    ast::Pass<ReplacePseudoFuncCore>::run(translationUnit);
431
432    ast::Pass<ReplaceSuccAndPred>::run(translationUnit);
433}
434}  // namespace Validate
Note: See TracBrowser for help on using the repository browser.