source: src/ControlStruct/TranslateEnumRange.cpp @ 115ac1ce

Last change on this file since 115ac1ce was 5ccc733, checked in by JiadaL <j82liang@…>, 3 months ago

Fix the bug that C style enum cannot to use as an lvalue

  • Property mode set to 100644
File size: 4.5 KB
Line 
1#include "TranslateEnumRange.hpp"
2
3#include "AST/Pass.hpp"
4#include "AST/TranslationUnit.hpp"
5
6namespace ControlStruct {
7
8struct addInitType {
9    const ast::Stmt * postvisit( const ast::ForStmt * stmt );
10};
11
12struct addInit {
13    const ast::Stmt * postvisit( const ast::ForStmt * stmt );
14};
15
16struct translateEnumRangeCore {
17    const ast::Stmt * postvisit( const ast::ForStmt * stmt );
18};
19
20const ast::Stmt* addInitType::postvisit( const ast::ForStmt * stmt ) {
21    if ( stmt->range_over ) {
22        auto typeExpr = stmt->range_over.strict_as<ast::TypeExpr>();
23        auto type = typeExpr->type;
24        auto inits = stmt->inits;
25        auto enumInst = type.strict_as<ast::EnumInstType>();
26        auto enumDecl = enumInst->base;
27
28        auto objInit = stmt->inits.front();
29
30        auto initLocation = objInit->location;
31        auto rangeLocation = stmt->range_over->location;
32        assert( stmt->inits.size() == 1 );
33
34        if (auto declStmt = objInit.as<ast::DeclStmt>()) {
35            auto decl = declStmt->decl;
36            if ( auto objDecl = decl.as<ast::ObjectDecl>()) {
37                if ( !objDecl->type && type ) {
38                    auto objDeclWithType = ast::mutate_field( objDecl, &ast::ObjectDecl::type, type );
39                    auto declWithType = ast::mutate_field( declStmt, &ast::DeclStmt::decl, objDeclWithType );
40                    stmt = ast::mutate_field_index( stmt, &ast::ForStmt::inits, 0, declWithType );
41                }
42            }
43        }
44    }
45    return stmt;
46}
47
48const ast::Stmt* addInit::postvisit( const ast::ForStmt * stmt ) {
49    if ( stmt->range_over ) {
50        auto typeExpr = stmt->range_over.strict_as<ast::TypeExpr>();
51        auto type = typeExpr->type;
52        auto inits = stmt->inits;
53        auto enumInst = type.strict_as<ast::EnumInstType>();
54        auto enumDecl = enumInst->base;
55
56        auto init = stmt->inits.front();
57
58        if (auto declStmt = init.as<ast::DeclStmt>()) {
59            auto decl = declStmt->decl;
60            if ( auto objDecl = decl.as<ast::ObjectDecl>()) {
61                if ( !objDecl->init ) {
62                    auto location = stmt->location;
63                    ast::SingleInit * newInit;
64                    newInit = new ast::SingleInit( location, 
65                        new ast::NameExpr( location, 
66                        stmt->is_inc? enumDecl->members.front()->name: enumDecl->members.back()->name ) );
67                    auto objDeclWithInit = ast::mutate_field( objDecl, &ast::ObjectDecl::init, newInit );
68                    auto declWithInit = ast::mutate_field( declStmt, &ast::DeclStmt::decl, objDeclWithInit );
69                    stmt = ast::mutate_field_index( stmt, &ast::ForStmt::inits, 0, declWithInit );
70                }
71            }
72        }
73    }
74    return stmt;
75}
76
77const ast::Stmt* translateEnumRangeCore::postvisit( const ast::ForStmt * stmt ) {
78    if ( !stmt->range_over ) return stmt;
79    auto location = stmt->location;
80    auto declStmt = stmt->inits.front().strict_as<ast::DeclStmt>();
81    auto initDecl = declStmt->decl.strict_as<ast::ObjectDecl>();
82    auto indexName = initDecl->name;
83   
84    auto typeExpr = stmt->range_over.strict_as<ast::TypeExpr>();
85    auto enumInst = typeExpr->type.strict_as<ast::EnumInstType>();
86    auto enumDecl = enumInst->base;
87   
88    // Both inc and dec check if the current posn less than the number of enumerator
89    // for dec, it keeps call pred until it passes 0 (the first enumerator) and underflow,
90    // it wraps around and become unsigned max
91    ast::UntypedExpr * condition = ast::UntypedExpr::createCall( location,
92        "?<=?",
93        {new ast::CastExpr(location,
94            new ast::NameExpr( location, indexName ),
95            new ast::BasicType( ast::BasicKind::UnsignedInt ),
96            ast::GeneratedFlag::ExplicitCast),
97        ast::ConstantExpr::from_ulong( location, enumDecl->members.size()-1 ) });
98
99    auto increment = ast::UntypedExpr::createCall( location, 
100        stmt->is_inc? "?++": "?--",
101        { new ast::NameExpr( location, indexName ) });
102   
103    auto assig = ast::UntypedExpr::createAssign( location, new ast::NameExpr( location, indexName ), increment );
104    auto mut = ast::mutate_field( stmt, &ast::ForStmt::cond, condition );
105    mut = ast::mutate_field(stmt, &ast::ForStmt::inc, assig );
106    return mut;
107}
108
109void translateEnumRange( ast::TranslationUnit & translationUnit ) {
110    ast::Pass<addInitType>::run( translationUnit );
111    ast::Pass<addInit>::run( translationUnit );
112    ast::Pass<translateEnumRangeCore>::run( translationUnit );
113}
114}
Note: See TracBrowser for help on using the repository browser.