source: src/Validate/ReplacePseudoFunc.cpp @ a55ebcc

Last change on this file since a55ebcc was a55ebcc, checked in by JiadaL <j82liang@…>, 5 months ago
  1. Add debug print option for replacePseudoFunc; 2. Change resolver handling enum types; 3. change QualifiedNameExpr? representation pre-resolver; 4. Disable able a test that currently doesn't work
  • Property mode set to 100644
File size: 11.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/Stmt.hpp"
9#include "Common/utility.h"
10#include "ResolvExpr/Resolver.h"
11#include "SymTab/Mangler.h"
12
13#include "AST/Print.hpp"
14
15#include "ResolvExpr/CandidateFinder.hpp"
16
17namespace Validate {
18
19namespace {
20
21std::set<std::string> queryLabels;
22std::set<std::string> queryValues;
23
24// struct AutoInit {
25//     ast::EnumDecl const* postvisit( const ast::EnumDecl* expr );
26// };
27
28struct WrapEnumValueExpr final : public ast::WithShortCircuiting,
29                                 public ast::WithSymbolTable,
30                                 public ast::WithConstTranslationUnit {
31    void previsit(const ast::DeclStmt* expr);
32    void previsit(const ast::ApplicationExpr* expr);
33    void previsit(const ast::CastExpr* expr);
34    void previsit(const ast::VariableExpr* ) { visit_children = false; }
35
36    ast::Expr const* postvisit(const ast::VariableExpr* expr);
37};
38
39struct FindGenEnumArray final : public ast::WithShortCircuiting {
40    void previsit(const ast::ApplicationExpr* enumDecl);
41};
42
43struct PseudoFuncGenerateRoutine final : public ast::WithDeclsToAdd<>,
44                                         public ast::WithSymbolTable,
45                                         public ast::WithShortCircuiting,
46                                         public ast::WithConstTranslationUnit {
47    void previsit(const ast::EnumDecl* enumDecl);
48};
49
50struct ReplacePseudoFuncCore : public ast::WithShortCircuiting,
51                               public ast::WithSymbolTable,
52                               public ast::WithConstTranslationUnit {
53    ast::Expr const* postvisit(ast::ApplicationExpr const* decl);
54};
55
56// ast::EnumDecl const * AutoInit::postvisit( const ast::EnumDecl * expr ) {
57//     for ( size_t i = 0; i < expr->members.size(); i++ ) {
58//         auto mem = expr->members[i].as<ast::ObjectDecl>();
59//         assert( mem );
60//         if ( mem->init )
61//     }
62//     return expr;
63// }
64
65void WrapEnumValueExpr::previsit(const ast::ApplicationExpr* expr) {
66    auto varExpr = expr->func.as<ast::VariableExpr>();
67    auto fname = ast::getFunctionName(expr);
68        if ( !varExpr || varExpr->var->linkage == ast::Linkage::Intrinsic ) {
69        if ( fname == "?{}" || fname == "?=?" )
70                    visit_children = false;
71        }
72
73    if (fname == "labelE" || fname == "valueE" || fname == "posE") {
74        visit_children = false;
75    }
76}
77
78void WrapEnumValueExpr::previsit(const ast::DeclStmt*) {
79    visit_children = false;
80}
81
82void WrapEnumValueExpr::previsit(const ast::CastExpr* expr) {
83    if (expr->result && expr->result.as<ast::ReferenceType>()) {
84        visit_children = false;
85    }
86}
87
88ast::Expr const* WrapEnumValueExpr::postvisit(const ast::VariableExpr* expr) {
89    if (!expr->result) {
90        return expr;
91    }
92    if (auto enumInst = expr->result.as<ast::EnumInstType>()) {
93        if (enumInst->base && enumInst->base->base) {
94            auto untyped = new ast::UntypedExpr(
95                expr->location, new ast::NameExpr(expr->location, "valueE"),
96                { std::move( expr ) });
97            ResolvExpr::ResolveContext context{symtab, transUnit().global};
98            auto result = ResolvExpr::findVoidExpression(untyped, context);
99            ast::ptr<ast::ApplicationExpr> ret =
100                    result.strict_as<ast::ApplicationExpr>();
101            return ast::deepCopy( ret );
102        }
103    }
104    return expr;
105}
106
107void FindGenEnumArray::previsit(const ast::ApplicationExpr* expr) {
108    auto fname = ast::getFunctionName(expr);
109    if (fname == "labelE" || fname == "valueE") {
110        if (expr->args.size() != 1) {
111            SemanticError(expr, "Position Expression only take one parameter");
112        }
113        const ast::VariableExpr* arg =
114            expr->args.front().as<const ast::VariableExpr>();
115        if (!arg) {
116            SemanticError(expr, "Unimplement Pseudo Function Cases");
117        }
118        const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
119        const std::string referredName = argAsVar->name;
120        const ast::EnumInstType* argType =
121            argAsVar->type.as<const ast::EnumInstType>();
122        if (!argType) {
123            SemanticError(
124                argAsVar,
125                "Position can only be used on an enumeration instance");
126        }
127        ast::ptr<ast::EnumDecl> base = argType->base;
128        assert(base);
129        if (fname == "labelE") queryLabels.insert(base->name);
130        if (fname == "valueE") queryValues.insert(base->name);
131    }
132}
133
134const ast::Init * getAutoInit( const CodeLocation & location,
135    const ast::Type * type, ResolvExpr::ResolveContext context, const ast::Init * prev ) {
136    if ( auto prevInit = dynamic_cast< const ast::SingleInit * >( prev ) ) {
137        auto prevInitExpr = prevInit->value;
138        if ( auto constInit = prevInitExpr.as< ast::ConstantExpr >() ) {
139            // Assume no string literal for now
140            return new ast::SingleInit(
141                location,
142                ast::ConstantExpr::from_int(
143                    location, constInit->intValue() + 1 )
144            );
145        } else {
146            auto untypedThisInit = new ast::UntypedExpr(
147                    location,
148                    new ast::NameExpr( location, "?++" ),
149                    { prevInitExpr }
150                );
151            auto typedInit = ResolvExpr::findSingleExpression(untypedThisInit, type,
152                context );
153            return new ast::SingleInit( location, typedInit );
154        }
155    }
156    SemanticError( prev, "Auto Init a List is not implemented" );
157    return prev;
158}
159
160void PseudoFuncGenerateRoutine::previsit(const ast::EnumDecl* enumDecl) {
161    visit_children = false;
162    const CodeLocation& location = enumDecl->location;
163    if (enumDecl->members.size() == 0 || !enumDecl->base) return;
164
165    std::vector<ast::ptr<ast::Init>> inits;
166    std::vector<ast::ptr<ast::Init>> labels;
167    auto type = enumDecl->base;
168
169    for ( size_t i = 0; i < enumDecl->members.size(); i++ ) {
170        ast::ptr<ast::Decl> mem = enumDecl->members.at( i );
171        auto memAsObjectDecl = mem.as< ast::ObjectDecl >();
172        assert( memAsObjectDecl );
173        if ( memAsObjectDecl->init ) {
174            inits.emplace_back( memAsObjectDecl->init );
175        } else {
176            const CodeLocation & location = mem->location;
177            if ( i == 0 ) {
178                inits.emplace_back( new ast::SingleInit( 
179                    location, 
180                    ast::ConstantExpr::from_int( mem->location, 0 )
181                ) );
182            } else {
183                inits.emplace_back( getAutoInit( location, enumDecl->base, 
184                    ResolvExpr::ResolveContext{symtab, transUnit().global}, 
185                    inits.at( i - 1 ).as<ast::SingleInit>()) );
186            }
187        }
188        labels.emplace_back(new ast::SingleInit(
189        location, ast::ConstantExpr::from_string(location, mem->name)));
190    } 
191    if (queryValues.count(enumDecl->name)) {
192        auto init = new ast::ListInit(location, std::move(inits));
193        const ast::ArrayType* arrT = new ast::ArrayType(
194            enumDecl->base,
195            ast::ConstantExpr::from_int(location, enumDecl->members.size()),
196            ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
197        ast::ObjectDecl* values = new ast::ObjectDecl(
198            location, "values_" + enumDecl->name, arrT, init,
199            ast::Storage::Static, ast::Linkage::AutoGen);
200        symtab.addId(values);
201        values->mangleName = Mangle::mangle(values);
202        declsToAddAfter.push_back(values);
203    }
204    if (queryLabels.count(enumDecl->name)) {
205        auto label_strings = new ast::ListInit(location, std::move(labels));
206        auto labels = new ast::ObjectDecl(
207            location, "labels_" + enumDecl->name,
208            new ast::ArrayType(
209                new ast::PointerType(new ast::BasicType{ast::BasicType::Char}),
210                ast::ConstantExpr::from_int(location, enumDecl->members.size()),
211                ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim),
212            label_strings, ast::Storage::Static, ast::Linkage::AutoGen);
213        symtab.addId(labels);
214        labels->mangleName = Mangle::mangle(labels);
215        declsToAddAfter.push_back(labels);
216    }
217}
218
219ast::ApplicationExpr const* getPseudoFuncApplication(
220    const CodeLocation location, ResolvExpr::ResolveContext context,
221    const ast::VariableExpr* arg, const ast::EnumDecl* base, const std::string & name) {
222    ast::Expr* toResolve = new ast::NameExpr(location, name + base->name);
223    auto result = ResolvExpr::findVoidExpression(toResolve, context);
224    assert(result.get());
225    auto arrAsVar = result.strict_as<ast::VariableExpr>();
226    auto untyped = new ast::UntypedExpr(
227        location, new ast::NameExpr(location, "?[?]"),
228        { std::move(arrAsVar), std::move(arg) });
229    auto typedResult = ResolvExpr::findVoidExpression(untyped, context);
230
231    ast::ptr<ast::ApplicationExpr> ret =
232        typedResult.strict_as<ast::ApplicationExpr>();
233    return ast::deepCopy(ret);
234}
235
236ast::Expr const* ReplacePseudoFuncCore::postvisit(
237    ast::ApplicationExpr const* expr) {
238    auto fname = ast::getFunctionName(expr);
239    auto location = expr->location;
240    if (fname == "posE" || fname == "valueE" || fname == "labelE") {
241        if (expr->args.size() != 1) {
242            SemanticError(expr,
243                          "Pseudo Enum Expression only take one parameter");
244        }
245        ast::ptr<ast::VariableExpr> arg =
246            expr->args.front().as<const ast::VariableExpr>();
247        if (!arg) {
248            SemanticError(expr, "Unimplement Pseudo Function Cases");
249        }
250        const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
251        const std::string referredName = argAsVar->name;
252        const ast::EnumInstType* argType =
253            argAsVar->type.as<const ast::EnumInstType>();
254        if (!argType) {
255            SemanticError(argAsVar,
256                          "Pseudo Enum Expression can only be used on an "
257                          "enumeration instance");
258        }
259        const ast::EnumDecl* base = argType->base;
260        ResolvExpr::ResolveContext context{symtab, transUnit().global};
261        // If resolvable as constant
262        for (size_t i = 0; i < base->members.size(); i++) {
263            if (base->members[i]->name == referredName) {
264                if (fname == "posE")
265                    return ast::ConstantExpr::from_int(expr->location, i);
266                else if (fname == "labelE")
267                    return ast::ConstantExpr::from_string(expr->location,
268                                                          referredName);
269                else {
270                    return getPseudoFuncApplication(location, context, arg.get(),
271                                               base, "values_");                   
272                }
273
274            }
275        }
276
277        if (fname == "labelE") {
278            if (auto labelExpr =
279                    getPseudoFuncApplication(location, context, arg.get(), base, "labels_")) {
280                return labelExpr;
281            }
282        } else if (fname == "valueE") {
283            if (auto valueExpr =
284                    getPseudoFuncApplication(location, context, arg.get(), base, "values_")) {
285                return valueExpr;
286            }
287        } else { // it is position; replace itself
288            return std::move( arg.get() );
289        }
290    }
291    return expr;
292}
293
294}  // namespace
295
296void replacePseudoFunc(ast::TranslationUnit& translationUnit) {
297    ast::Pass<WrapEnumValueExpr>::run(translationUnit);
298    ast::Pass<FindGenEnumArray>::run(translationUnit);
299    ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
300    ast::Pass<ReplacePseudoFuncCore>::run(translationUnit);
301}
302}  // namespace Validate
Note: See TracBrowser for help on using the repository browser.