source: src/Validate/ReplacePseudoFunc.cpp@ f5212ca

Last change on this file since f5212ca was 76fe046, checked in by JiadaL <j82liang@…>, 19 months ago

Remove conversion part of the EnumPosType. It can be resolved by the current unifier

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