source: src/Validate/ReplacePseudoFunc.cpp@ be4335b

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

Fix dangling reference to posE function

  • Property mode set to 100644
File size: 9.3 KB
RevLine 
[544deb9]1#include "ReplacePseudoFunc.hpp"
2
3#include <set>
4
[ac939461]5#include "AST/Decl.hpp"
[544deb9]6#include "AST/Inspect.hpp"
[ac939461]7#include "AST/Pass.hpp"
8#include "AST/Stmt.hpp"
9#include "Common/utility.h"
[544deb9]10#include "ResolvExpr/Resolver.h"
11#include "SymTab/Mangler.h" // for Mangler
[ac939461]12namespace Validate {
13
14namespace {
15
[544deb9]16std::set<std::string> queryLabels;
17std::set<std::string> queryValues;
18
[c75b30a]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
[544deb9]29struct FindGenEnumArray final : public ast::WithShortCircuiting {
30 void previsit(const ast::ApplicationExpr* enumDecl);
[ac939461]31};
[544deb9]32
[c75b30a]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
[544deb9]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 }
[ac939461]115}
116
[544deb9]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));
[c75b30a]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);
[544deb9]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));
[c75b30a]145 auto labels = new ast::ObjectDecl(
[544deb9]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);
[c75b30a]152 symtab.addId(labels);
153 labels->mangleName = Mangle::mangle(labels);
154 declsToAddAfter.push_back(labels);
[544deb9]155 }
156}
157
[c75b30a]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, "?[?]"),
[496ffc17]167 { std::move(arrAsVar), std::move(arg) });
[c75b30a]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}
[544deb9]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");
[ac939461]183 }
[544deb9]184 ast::ptr<ast::VariableExpr> arg =
185 expr->args.front().as<const ast::VariableExpr>();
186 if (!arg) {
187 SemanticError(expr, "Unimplement Pseudo Function Cases");
[ac939461]188 }
[544deb9]189 const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
[ac939461]190 const std::string referredName = argAsVar->name;
[544deb9]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;
[c75b30a]199 ResolvExpr::ResolveContext context{symtab, transUnit().global};
200 // If resolvable as constant
[544deb9]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);
[367725d]208 else
[c75b30a]209 return getPseudoFuncApplication(location, context, arg.get(),
210 base, "values_");
[544deb9]211 }
212 }
213
214 if (fname == "labelE") {
[c75b30a]215 if (auto labelExpr =
216 getPseudoFuncApplication(location, context, arg.get(), base, "labels_")) {
217 return labelExpr;
[544deb9]218 }
[c75b30a]219 } else if (fname == "valueE") {
220 if (auto valueExpr =
221 getPseudoFuncApplication(location, context, arg.get(), base, "values_")) {
222 return valueExpr;
[ac939461]223 }
[c75b30a]224 } else { // it is position; replace itself
225 return std::move( arg.get() );
[ac939461]226 }
227 }
228 return expr;
229}
230
[544deb9]231} // namespace
[ac939461]232
[544deb9]233void replacePseudoFunc(ast::TranslationUnit& translationUnit) {
[c75b30a]234 ast::Pass<WrapEnumValueExpr>::run(translationUnit);
[544deb9]235 ast::Pass<FindGenEnumArray>::run(translationUnit);
236 ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
237 ast::Pass<ReplacePseudoFuncCore>::run(translationUnit);
[ac939461]238}
[544deb9]239} // namespace Validate
Note: See TracBrowser for help on using the repository browser.