source: src/Validate/ReplacePseudoFunc.cpp@ 32490deb

Last change on this file since 32490deb was c75b30a, checked in by JiadaL <j82liang@…>, 21 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.