source: src/Validate/ReplacePseudoFunc.cpp@ 3f9a8d0

Last change on this file since 3f9a8d0 was 0522ebe, checked in by JiadaL <j82liang@…>, 19 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.