source: src/Validate/ReplacePseudoFunc.cpp @ c75b30a

Last change on this file since c75b30a was c75b30a, checked in by JiadaL <j82liang@…>, 4 months ago

Introduce posE, valueE, labelE pseudo language to the language. Rework the internal representation of enumeration.

  • Property mode set to 100644
File size: 9.4 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    // Values only
131    if (queryValues.count(enumDecl->name)) {
132        auto init = new ast::ListInit(location, std::move(inits));
133        const ast::ArrayType* arrT = new ast::ArrayType(
134            enumDecl->base,
135            ast::ConstantExpr::from_int(location, enumDecl->members.size()),
136            ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
137        ast::ObjectDecl* values = new ast::ObjectDecl(
138            location, "values_" + enumDecl->name, arrT, init,
139            ast::Storage::Static, ast::Linkage::AutoGen);
140        symtab.addId(values);
141        values->mangleName = Mangle::mangle(values);
142        declsToAddAfter.push_back(values);
143    }
144    if (queryLabels.count(enumDecl->name)) {
145        auto label_strings = new ast::ListInit(location, std::move(labels));
146        auto labels = new ast::ObjectDecl(
147            location, "labels_" + enumDecl->name,
148            new ast::ArrayType(
149                new ast::PointerType(new ast::BasicType{ast::BasicType::Char}),
150                ast::ConstantExpr::from_int(location, enumDecl->members.size()),
151                ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim),
152            label_strings, ast::Storage::Static, ast::Linkage::AutoGen);
153        symtab.addId(labels);
154        labels->mangleName = Mangle::mangle(labels);
155        declsToAddAfter.push_back(labels);
156    }
157}
158
159ast::ApplicationExpr const* getPseudoFuncApplication(
160    const CodeLocation location, ResolvExpr::ResolveContext context,
161    const ast::VariableExpr* arg, const ast::EnumDecl* base, const std::string & name) {
162    ast::Expr* toResolve = new ast::NameExpr(location, name + base->name);
163    auto result = ResolvExpr::findVoidExpression(toResolve, context);
164    assert(result.get());
165    auto arrAsVar = result.strict_as<ast::VariableExpr>();
166    auto untyped = new ast::UntypedExpr(
167        location, new ast::NameExpr(location, "?[?]"),
168        {new ast::VariableExpr(*arrAsVar), new ast::VariableExpr(*arg)});
169    auto typedResult = ResolvExpr::findVoidExpression(untyped, context);
170
171    ast::ptr<ast::ApplicationExpr> ret =
172        typedResult.strict_as<ast::ApplicationExpr>();
173    return ast::deepCopy(ret);
174}
175
176ast::Expr const* ReplacePseudoFuncCore::postvisit(
177    ast::ApplicationExpr const* expr) {
178    auto fname = ast::getFunctionName(expr);
179    auto location = expr->location;
180    if (fname == "posE" || fname == "valueE" || fname == "labelE") {
181        if (expr->args.size() != 1) {
182            SemanticError(expr,
183                          "Pseudo Enum Expression only take one parameter");
184        }
185        ast::ptr<ast::VariableExpr> arg =
186            expr->args.front().as<const ast::VariableExpr>();
187        if (!arg) {
188            SemanticError(expr, "Unimplement Pseudo Function Cases");
189        }
190        const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
191        const std::string referredName = argAsVar->name;
192        const ast::EnumInstType* argType =
193            argAsVar->type.as<const ast::EnumInstType>();
194        if (!argType) {
195            SemanticError(argAsVar,
196                          "Pseudo Enum Expression can only be used on an "
197                          "enumeration instance");
198        }
199        const ast::EnumDecl* base = argType->base;
200        ResolvExpr::ResolveContext context{symtab, transUnit().global};
201        // If resolvable as constant
202        for (size_t i = 0; i < base->members.size(); i++) {
203            if (base->members[i]->name == referredName) {
204                if (fname == "posE")
205                    return ast::ConstantExpr::from_int(expr->location, i);
206                else if (fname == "labelE")
207                    return ast::ConstantExpr::from_string(expr->location,
208                                                          referredName);
209                else
210                    return getPseudoFuncApplication(location, context, arg.get(),
211                                               base, "values_");
212            }
213        }
214
215        if (fname == "labelE") {
216            if (auto labelExpr =
217                    getPseudoFuncApplication(location, context, arg.get(), base, "labels_")) {
218                return labelExpr;
219            }
220        } else if (fname == "valueE") {
221            if (auto valueExpr =
222                    getPseudoFuncApplication(location, context, arg.get(), base, "values_")) {
223                return valueExpr;
224            }
225        } else { // it is position; replace itself
226            return std::move( arg.get() );
227        }
228    }
229    return expr;
230}
231
232}  // namespace
233
234void replacePseudoFunc(ast::TranslationUnit& translationUnit) {
235    ast::Pass<WrapEnumValueExpr>::run(translationUnit);
236    ast::Pass<FindGenEnumArray>::run(translationUnit);
237    ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
238    ast::Pass<ReplacePseudoFuncCore>::run(translationUnit);
239}
240}  // namespace Validate
Note: See TracBrowser for help on using the repository browser.