source: src/Validate/ReplacePseudoFunc.cpp @ a4da45e

Last change on this file since a4da45e was 0522ebe, checked in by JiadaL <j82liang@…>, 3 months ago

Add EnumPosType? to type system

  • Property mode set to 100644
File size: 15.6 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    void previsit(const ast::ObjectDecl*) { visit_children = false; }
24    const ast::ObjectDecl* postvisit(const ast::ObjectDecl* decl) {
25        auto enumInst = decl->type.strict_as<ast::EnumInstType>();
26        auto enumPos = new ast::EnumPosType(enumInst);
27        auto ret = ast::mutate_field(decl, &ast::ObjectDecl::type, enumPos);
28        ret = ast::mutate_field(ret, &ast::ObjectDecl::mangleName,
29                                Mangle::mangle(ret));
30        return ret;
31    }
32};
33
34const inline std::string getValueArrayName(std::string enumName) {
35    return "values_" + enumName;
36}
37
38// struct AutoInit {
39//     ast::EnumDecl const* postvisit( const ast::EnumDecl* expr );
40// };
41
42struct WrapEnumValueExpr final : public ast::WithShortCircuiting,
43                                 public ast::WithSymbolTable,
44                                 public ast::WithConstTranslationUnit {
45    void previsit(const ast::DeclStmt* expr);
46    void previsit(const ast::ApplicationExpr* expr);
47    void previsit(const ast::CastExpr* expr);
48    void previsit(const ast::VariableExpr*) { visit_children = false; }
49
50    ast::Expr const* postvisit(const ast::VariableExpr* expr);
51};
52
53struct FindGenEnumArray final : public ast::WithShortCircuiting {
54    void previsit(const ast::ApplicationExpr* enumDecl);
55};
56
57struct PseudoFuncGenerateRoutine final : public ast::WithDeclsToAdd<>,
58                                         public ast::WithSymbolTable,
59                                         public ast::WithShortCircuiting,
60                                         public ast::WithConstTranslationUnit {
61    void previsit(const ast::EnumDecl* enumDecl);
62};
63
64struct ReplacePseudoFuncCore : public ast::WithShortCircuiting,
65                               public ast::WithSymbolTable,
66                               public ast::WithConstTranslationUnit {
67    ast::Expr const* postvisit(ast::ApplicationExpr const* decl);
68};
69
70// ast::EnumDecl const * AutoInit::postvisit( const ast::EnumDecl * expr ) {
71//     for ( size_t i = 0; i < expr->members.size(); i++ ) {
72//         auto mem = expr->members[i].as<ast::ObjectDecl>();
73//         assert( mem );
74//         if ( mem->init )
75//     }
76//     return expr;
77// }
78
79void WrapEnumValueExpr::previsit(const ast::ApplicationExpr* expr) {
80    auto varExpr = expr->func.as<ast::VariableExpr>();
81    auto fname = ast::getFunctionName(expr);
82    if (!varExpr || varExpr->var->linkage == ast::Linkage::Intrinsic) {
83        if (fname == "?{}" || fname == "?=?") visit_children = false;
84    }
85
86    if (fname == "labelE" || fname == "valueE" || fname == "posE") {
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* getPseudoFuncApplication(
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        auto untyped =
244            new ast::UntypedExpr(location, new ast::NameExpr(location, "?[?]"),
245                                 {std::move(arrAsVar), mutatedArg});
246        auto typedResult = ResolvExpr::findVoidExpression(untyped, context);
247        ast::ptr<ast::ApplicationExpr> ret =
248            typedResult.strict_as<ast::ApplicationExpr>();
249        return ast::deepCopy(ret);
250    } else {
251        auto untyped =
252            new ast::UntypedExpr(location, new ast::NameExpr(location, "?[?]"),
253                                 {std::move(arrAsVar), arg});
254        auto typedResult = ResolvExpr::findVoidExpression(untyped, context);
255
256        ast::ptr<ast::ApplicationExpr> ret =
257            typedResult.strict_as<ast::ApplicationExpr>();
258        return ast::deepCopy(ret);
259    }
260}
261
262ast::Expr const* ReplacePseudoFuncCore::postvisit(
263    ast::ApplicationExpr const* expr) {
264    auto fname = ast::getFunctionName(expr);
265    auto location = expr->location;
266    if (fname == "posE" || fname == "valueE" || fname == "labelE") {
267        if (expr->args.size() != 1) {
268            SemanticError(expr,
269                          "Pseudo Enum Expression only take one parameter");
270        }
271        ast::ptr<ast::VariableExpr> arg =
272            expr->args.front().as<const ast::VariableExpr>();
273        if (!arg) {
274            SemanticError(expr, "Unimplement Pseudo Function Cases");
275        }
276        const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
277        const std::string referredName = argAsVar->name;
278
279        if (const ast::EnumInstType* argTypeAsEnumInst =
280                argAsVar->type.as<const ast::EnumInstType>()) {
281            const ast::EnumDecl* base = argTypeAsEnumInst->base;
282            ResolvExpr::ResolveContext context{symtab, transUnit().global};
283            // If resolvable as constant
284            for (size_t i = 0; i < base->members.size(); i++) {
285                if (base->members[i]->name == referredName) {
286                    if (fname == "posE")
287                        return ast::ConstantExpr::from_int(expr->location, i);
288                    else if (fname == "labelE")
289                        return ast::ConstantExpr::from_string(expr->location,
290                                                              referredName);
291                    else {
292                        return getPseudoFuncApplication(
293                            location, context, arg.get(), base, "values_");
294                    }
295                }
296            }
297
298            if (fname == "labelE") {
299                if (auto labelExpr = getPseudoFuncApplication(
300                        location, context, arg.get(), base, "labels_")) {
301                    return labelExpr;
302                }
303            } else if (fname == "valueE") {
304                if (auto valueExpr = getPseudoFuncApplication(
305                        location, context, arg.get(), base, "values_")) {
306                    return valueExpr;
307                }
308            } else {  // it is position; replace itself
309                return std::move(arg.get());
310            }
311        } else if (const ast::EnumPosType* argTypeAsPos =
312                       argAsVar->type.as<const ast::EnumPosType>()) {
313            const ast::EnumDecl* base = argTypeAsPos->instance->base;
314            ResolvExpr::ResolveContext context{symtab, transUnit().global};
315            if (fname == "labelE") {
316                if (auto labelExpr = getPseudoFuncApplication(
317                        location, context, arg.get(), base, "labels_")) {
318                    return labelExpr;
319                }
320            } else if (fname == "valueE") {
321                if (auto valueExpr = getPseudoFuncApplication(
322                        location, context, arg.get(), base, "values_")) {
323                    return valueExpr;
324                }
325            } else {  // it is position; replace itself
326                return std::move(arg.get());
327            }
328        } else {
329            SemanticError(argAsVar,
330                          "Pseudo Enum Expression can only be used on an "
331                          "enumeration instance");
332        }
333    }
334    return expr;
335}
336
337ast::ptr<ast::Expr> reduceCastExpr(ast::ptr<ast::Expr> expr) {
338    if (auto castExpr = expr.as<ast::CastExpr>()) {
339        return reduceCastExpr(castExpr->arg);
340    }
341    return expr;
342}
343
344struct ReplaceEnumInst final {
345    const ast::Expr* postvisit(const ast::ApplicationExpr* expr) {
346        auto fname = ast::getFunctionName(expr);
347        if (fname != "?[?]") return expr;
348        if (expr->args.size() != 2) return expr;
349
350        auto arg1AsVar =
351            reduceCastExpr(expr->args.front()).as<ast::VariableExpr>();
352        auto arg2AsVar =
353            reduceCastExpr(expr->args.back()).as<ast::VariableExpr>();
354
355        if (!arg1AsVar || !arg2AsVar) return expr;
356
357        auto arg1Asecl = arg1AsVar->var.as<ast::ObjectDecl>();
358        auto arg2Asecl = arg2AsVar->var.as<ast::ObjectDecl>();
359
360        if (!arg1Asecl || !arg2Asecl) return expr;
361        auto arrInst = arg1Asecl->type.as<ast::ArrayType>();
362        auto pointerInst = arg1Asecl->type.as<ast::PointerType>();
363        if (!arrInst && !pointerInst) {
364            return expr;
365        }
366        auto enumInst = arg2Asecl->type.as<ast::EnumInstType>();
367        if (!enumInst) return expr;
368
369        const std::string arrName = arg1Asecl->name;
370        if (arrName != getValueArrayName(enumInst->base->name)) return expr;
371        ast::Pass<ReplaceEnumInstWithPos> replacer;
372        auto rep = arg2Asecl->accept(replacer);
373        if (!rep) return expr;
374        auto mutObj =
375            ast::mutate_field(arg2AsVar, &ast::VariableExpr::var, rep);
376        auto mut = ast::mutate_field_index(expr, &ast::ApplicationExpr::args, 1,
377                                           mutObj);
378        return mut;
379    }
380};
381
382}  // namespace
383
384void replacePseudoFunc(ast::TranslationUnit& translationUnit) {
385    ast::Pass<WrapEnumValueExpr>::run(translationUnit);
386    ast::Pass<FindGenEnumArray>::run(translationUnit);
387    ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
388    ast::Pass<ReplacePseudoFuncCore>::run(translationUnit);
389    ast::Pass<ReplaceEnumInst>::run(translationUnit);
390}
391}  // namespace Validate
Note: See TracBrowser for help on using the repository browser.