source: src/Validate/ReplacePseudoFunc.cpp @ 9ddcee1

Last change on this file since 9ddcee1 was 496ffc17, checked in by JiadaL <j82liang@…>, 8 months ago

Fix dangling reference to posE function

  • Property mode set to 100644
File size: 9.3 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/Stmt.hpp"
9#include "Common/utility.h"
10#include "ResolvExpr/Resolver.h"
11#include "SymTab/Mangler.h"  // for Mangler
12namespace Validate {
13
14namespace {
15
16std::set<std::string> queryLabels;
17std::set<std::string> queryValues;
18
19struct WrapEnumValueExpr final : public ast::WithShortCircuiting,
20                                 public ast::WithSymbolTable,
21                                 public ast::WithConstTranslationUnit {
22    void previsit(const ast::DeclStmt* expr);
23    void previsit(const ast::ApplicationExpr* expr);
24    void previsit(const ast::CastExpr* expr);
25
26    ast::Expr const* postvisit(const ast::VariableExpr* expr);
27};
28
29struct FindGenEnumArray final : public ast::WithShortCircuiting {
30    void previsit(const ast::ApplicationExpr* enumDecl);
31};
32
33struct PseudoFuncGenerateRoutine final : public ast::WithDeclsToAdd<>,
34                                         public ast::WithSymbolTable,
35                                         public ast::WithShortCircuiting {
36    void previsit(const ast::EnumDecl* enumDecl);
37};
38
39struct ReplacePseudoFuncCore : public ast::WithShortCircuiting,
40                               public ast::WithSymbolTable,
41                               public ast::WithConstTranslationUnit {
42    ast::Expr const* postvisit(ast::ApplicationExpr const* decl);
43};
44
45void WrapEnumValueExpr::previsit(const ast::ApplicationExpr* expr) {
46
47    auto varExpr = expr->func.as<ast::VariableExpr>();
48    auto fname = ast::getFunctionName(expr);
49        if ( !varExpr || varExpr->var->linkage == ast::Linkage::Intrinsic ) {
50        if ( fname == "?{}" || fname == "?=?" )
51                    visit_children = false;
52        }
53
54    if (fname == "labelE" || fname == "valueE" || fname == "posE")
55        visit_children = false;
56}
57
58void WrapEnumValueExpr::previsit(const ast::DeclStmt*) {
59    visit_children = false;
60}
61
62void WrapEnumValueExpr::previsit(const ast::CastExpr* expr) {
63    if (expr->result && expr->result.as<ast::ReferenceType>()) {
64        visit_children = false;
65    }
66}
67
68ast::Expr const* WrapEnumValueExpr::postvisit(const ast::VariableExpr* expr) {
69    visit_children = false;
70    if (!expr->result) {
71        return expr;
72    }
73    if (auto enumInst = expr->result.as<ast::EnumInstType>()) {
74        if (enumInst->base && enumInst->base->base) {
75            auto untyped = new ast::UntypedExpr(
76                expr->location, new ast::NameExpr(expr->location, "valueE"),
77                {new ast::VariableExpr(*expr)});
78            ResolvExpr::ResolveContext context{symtab, transUnit().global};
79            auto result = ResolvExpr::findVoidExpression(untyped, context);
80            if (result.get()) {
81                ast::ptr<ast::ApplicationExpr> ret =
82                    result.strict_as<ast::ApplicationExpr>();
83                return new ast::ApplicationExpr(*ret);
84            }
85        }
86    }
87    return expr;
88}
89
90void FindGenEnumArray::previsit(const ast::ApplicationExpr* expr) {
91    auto fname = ast::getFunctionName(expr);
92    if (fname == "labelE" || fname == "valueE") {
93        if (expr->args.size() != 1) {
94            SemanticError(expr, "Position Expression only take one parameter");
95        }
96        const ast::VariableExpr* arg =
97            expr->args.front().as<const ast::VariableExpr>();
98        if (!arg) {
99            SemanticError(expr, "Unimplement Pseudo Function Cases");
100        }
101        const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
102        const std::string referredName = argAsVar->name;
103        const ast::EnumInstType* argType =
104            argAsVar->type.as<const ast::EnumInstType>();
105        if (!argType) {
106            SemanticError(
107                argAsVar,
108                "Position can only be used on an enumeration instance");
109        }
110        ast::ptr<ast::EnumDecl> base = argType->base;
111        assert(base);
112        if (fname == "labelE") queryLabels.insert(base->name);
113        if (fname == "valueE") queryValues.insert(base->name);
114    }
115}
116
117void PseudoFuncGenerateRoutine::previsit(const ast::EnumDecl* enumDecl) {
118    visit_children = false;
119    const CodeLocation& location = enumDecl->location;
120    if (enumDecl->members.size() == 0 || !enumDecl->base) return;
121
122    std::vector<ast::ptr<ast::Init>> inits;
123    std::vector<ast::ptr<ast::Init>> labels;
124    for (const ast::Decl* mem : enumDecl->members) {
125        auto memAsObjectDecl = dynamic_cast<const ast::ObjectDecl*>(mem);
126        inits.emplace_back(memAsObjectDecl->init);
127        labels.emplace_back(new ast::SingleInit(
128            location, ast::ConstantExpr::from_string(location, mem->name)));
129    }
130    if (queryValues.count(enumDecl->name)) {
131        auto init = new ast::ListInit(location, std::move(inits));
132        const ast::ArrayType* arrT = new ast::ArrayType(
133            enumDecl->base,
134            ast::ConstantExpr::from_int(location, enumDecl->members.size()),
135            ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
136        ast::ObjectDecl* values = new ast::ObjectDecl(
137            location, "values_" + enumDecl->name, arrT, init,
138            ast::Storage::Static, ast::Linkage::AutoGen);
139        symtab.addId(values);
140        values->mangleName = Mangle::mangle(values);
141        declsToAddAfter.push_back(values);
142    }
143    if (queryLabels.count(enumDecl->name)) {
144        auto label_strings = new ast::ListInit(location, std::move(labels));
145        auto labels = new ast::ObjectDecl(
146            location, "labels_" + enumDecl->name,
147            new ast::ArrayType(
148                new ast::PointerType(new ast::BasicType{ast::BasicType::Char}),
149                ast::ConstantExpr::from_int(location, enumDecl->members.size()),
150                ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim),
151            label_strings, ast::Storage::Static, ast::Linkage::AutoGen);
152        symtab.addId(labels);
153        labels->mangleName = Mangle::mangle(labels);
154        declsToAddAfter.push_back(labels);
155    }
156}
157
158ast::ApplicationExpr const* getPseudoFuncApplication(
159    const CodeLocation location, ResolvExpr::ResolveContext context,
160    const ast::VariableExpr* arg, const ast::EnumDecl* base, const std::string & name) {
161    ast::Expr* toResolve = new ast::NameExpr(location, name + base->name);
162    auto result = ResolvExpr::findVoidExpression(toResolve, context);
163    assert(result.get());
164    auto arrAsVar = result.strict_as<ast::VariableExpr>();
165    auto untyped = new ast::UntypedExpr(
166        location, new ast::NameExpr(location, "?[?]"),
167        { std::move(arrAsVar), std::move(arg) });
168    auto typedResult = ResolvExpr::findVoidExpression(untyped, context);
169
170    ast::ptr<ast::ApplicationExpr> ret =
171        typedResult.strict_as<ast::ApplicationExpr>();
172    return ast::deepCopy(ret);
173}
174
175ast::Expr const* ReplacePseudoFuncCore::postvisit(
176    ast::ApplicationExpr const* expr) {
177    auto fname = ast::getFunctionName(expr);
178    auto location = expr->location;
179    if (fname == "posE" || fname == "valueE" || fname == "labelE") {
180        if (expr->args.size() != 1) {
181            SemanticError(expr,
182                          "Pseudo Enum Expression only take one parameter");
183        }
184        ast::ptr<ast::VariableExpr> arg =
185            expr->args.front().as<const ast::VariableExpr>();
186        if (!arg) {
187            SemanticError(expr, "Unimplement Pseudo Function Cases");
188        }
189        const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
190        const std::string referredName = argAsVar->name;
191        const ast::EnumInstType* argType =
192            argAsVar->type.as<const ast::EnumInstType>();
193        if (!argType) {
194            SemanticError(argAsVar,
195                          "Pseudo Enum Expression can only be used on an "
196                          "enumeration instance");
197        }
198        const ast::EnumDecl* base = argType->base;
199        ResolvExpr::ResolveContext context{symtab, transUnit().global};
200        // If resolvable as constant
201        for (size_t i = 0; i < base->members.size(); i++) {
202            if (base->members[i]->name == referredName) {
203                if (fname == "posE")
204                    return ast::ConstantExpr::from_int(expr->location, i);
205                else if (fname == "labelE")
206                    return ast::ConstantExpr::from_string(expr->location,
207                                                          referredName);
208                else
209                    return getPseudoFuncApplication(location, context, arg.get(),
210                                               base, "values_");
211            }
212        }
213
214        if (fname == "labelE") {
215            if (auto labelExpr =
216                    getPseudoFuncApplication(location, context, arg.get(), base, "labels_")) {
217                return labelExpr;
218            }
219        } else if (fname == "valueE") {
220            if (auto valueExpr =
221                    getPseudoFuncApplication(location, context, arg.get(), base, "values_")) {
222                return valueExpr;
223            }
224        } else { // it is position; replace itself
225            return std::move( arg.get() );
226        }
227    }
228    return expr;
229}
230
231}  // namespace
232
233void replacePseudoFunc(ast::TranslationUnit& translationUnit) {
234    ast::Pass<WrapEnumValueExpr>::run(translationUnit);
235    ast::Pass<FindGenEnumArray>::run(translationUnit);
236    ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
237    ast::Pass<ReplacePseudoFuncCore>::run(translationUnit);
238}
239}  // namespace Validate
Note: See TracBrowser for help on using the repository browser.