- Timestamp:
- Jun 12, 2023, 6:06:26 PM (3 years ago)
- Branches:
- ast-experimental, master
- Children:
- e172f42
- Parents:
- 24d6572 (diff), 38e266ca (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Location:
- src/AST
- Files:
-
- 6 edited
-
DeclReplacer.hpp (modified) (1 diff)
-
Pass.hpp (modified) (1 diff)
-
Pass.impl.hpp (modified) (6 diffs)
-
SymbolTable.cpp (modified) (7 diffs)
-
SymbolTable.hpp (modified) (5 diffs)
-
Util.cpp (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/AST/DeclReplacer.hpp
r24d6572 r62d62db 18 18 #include <unordered_map> 19 19 20 #include "Node.hpp" 20 namespace ast { 21 class DeclWithType; 22 class Expr; 23 class Node; 24 class TypeDecl; 25 } 21 26 22 27 namespace ast { 23 class DeclWithType;24 class TypeDecl;25 class Expr;26 28 27 namespace DeclReplacer { 28 using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >; 29 using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >; 30 using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >; 29 namespace DeclReplacer { 31 30 32 const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false ); 33 const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false ); 34 const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false ); 35 const Node * replace( const Node * node, const ExprMap & exprMap); 36 } 31 using DeclMap = std::unordered_map< const DeclWithType *, const DeclWithType * >; 32 using TypeMap = std::unordered_map< const TypeDecl *, const TypeDecl * >; 33 using ExprMap = std::unordered_map< const DeclWithType *, const Expr * >; 34 35 const Node * replace( const Node * node, const DeclMap & declMap, bool debug = false ); 36 const Node * replace( const Node * node, const TypeMap & typeMap, bool debug = false ); 37 const Node * replace( const Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug = false ); 38 const Node * replace( const Node * node, const ExprMap & exprMap); 39 40 } 41 37 42 } 38 43 -
src/AST/Pass.hpp
r24d6572 r62d62db 414 414 }; 415 415 416 /// Use when the templated visitor should update the symbol table 416 /// Use when the templated visitor should update the symbol table, 417 /// that is, when your pass core needs to query the symbol table. 418 /// Expected setups: 419 /// - For master passes that kick off at the compilation unit 420 /// - before resolver: extend WithSymbolTableX<IgnoreErrors> 421 /// - after resolver: extend WithSymbolTable and use defaults 422 /// - (FYI, for completeness, the resolver's main pass uses ValidateOnAdd when it kicks off) 423 /// - For helper passes that kick off at arbitrary points in the AST: 424 /// - take an existing symbol table as a parameter, extend WithSymbolTable, 425 /// and construct with WithSymbolTable(const SymbolTable &) 417 426 struct WithSymbolTable { 418 SymbolTable symtab; 427 WithSymbolTable(const ast::SymbolTable & from) : symtab(from) {} 428 WithSymbolTable(ast::SymbolTable::ErrorDetection errorMode = ast::SymbolTable::ErrorDetection::AssertClean) : symtab(errorMode) {} 429 ast::SymbolTable symtab; 430 }; 431 template <ast::SymbolTable::ErrorDetection errorMode> 432 struct WithSymbolTableX : WithSymbolTable { 433 WithSymbolTableX() : WithSymbolTable(errorMode) {} 419 434 }; 420 435 -
src/AST/Pass.impl.hpp
r24d6572 r62d62db 72 72 template<typename it_t, template <class...> class container_t> 73 73 static inline void take_all( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) { 74 if (empty(decls)) return;74 if ( empty( decls ) ) return; 75 75 76 76 std::transform(decls->begin(), decls->end(), it, [](const ast::Decl * decl) -> auto { … … 78 78 }); 79 79 decls->clear(); 80 if (mutated) *mutated = true;80 if ( mutated ) *mutated = true; 81 81 } 82 82 83 83 template<typename it_t, template <class...> class container_t> 84 84 static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * stmts, bool * mutated = nullptr ) { 85 if (empty(stmts)) return;85 if ( empty( stmts ) ) return; 86 86 87 87 std::move(stmts->begin(), stmts->end(), it); 88 88 stmts->clear(); 89 if (mutated) *mutated = true;89 if ( mutated ) *mutated = true; 90 90 } 91 91 … … 93 93 /// Check if should be skipped, different for pointers and containers 94 94 template<typename node_t> 95 bool skip( const ast::ptr<node_t> & val ) {95 bool skip( const ast::ptr<node_t> & val ) { 96 96 return !val; 97 97 } … … 110 110 111 111 template<typename node_t> 112 const node_t & get( const node_t & val, long ) {112 const node_t & get( const node_t & val, long ) { 113 113 return val; 114 114 } … … 126 126 } 127 127 } 128 129 template< typename core_t > 130 template< typename node_t > 131 auto ast::Pass< core_t >::call_accept( const node_t * node ) 132 -> typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type 133 { 134 __pedantic_pass_assert( __visit_children() ); 135 __pedantic_pass_assert( node ); 136 137 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR"); 138 static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR"); 139 140 auto nval = node->accept( *this ); 141 __pass::result1< 142 typename std::remove_pointer< decltype( node->accept(*this) ) >::type 143 > res; 144 res.differs = nval != node; 145 res.value = nval; 146 return res; 147 } 148 149 template< typename core_t > 150 __pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) { 151 __pedantic_pass_assert( __visit_children() ); 152 __pedantic_pass_assert( expr ); 153 154 auto nval = expr->accept( *this ); 155 return { nval != expr, nval }; 156 } 157 158 template< typename core_t > 159 __pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) { 160 __pedantic_pass_assert( __visit_children() ); 161 __pedantic_pass_assert( stmt ); 162 163 const ast::Stmt * nval = stmt->accept( *this ); 164 return { nval != stmt, nval }; 165 } 166 167 template< typename core_t > 168 __pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept_top( const ast::Expr * expr ) { 169 __pedantic_pass_assert( __visit_children() ); 170 __pedantic_pass_assert( expr ); 171 172 const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 ); 173 if ( typeSubs_ptr && expr->env ) { 174 *typeSubs_ptr = expr->env; 175 } 176 177 auto nval = expr->accept( *this ); 178 return { nval != expr, nval }; 179 } 180 181 template< typename core_t > 182 __pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) { 183 __pedantic_pass_assert( __visit_children() ); 184 __pedantic_pass_assert( stmt ); 185 186 // add a few useful symbols to the scope 187 using __pass::empty; 188 189 // get the stmts/decls that will need to be spliced in 190 auto stmts_before = __pass::stmtsToAddBefore( core, 0 ); 191 auto stmts_after = __pass::stmtsToAddAfter ( core, 0 ); 192 auto decls_before = __pass::declsToAddBefore( core, 0 ); 193 auto decls_after = __pass::declsToAddAfter ( core, 0 ); 194 195 // These may be modified by subnode but most be restored once we exit this statemnet. 196 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass::typeSubs( core, 0 ) ); 197 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 198 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); 199 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before ); 200 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after ); 201 202 // Now is the time to actually visit the node 203 const ast::Stmt * nstmt = stmt->accept( *this ); 204 205 // If the pass doesn't want to add anything then we are done 206 if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) { 207 return { nstmt != stmt, nstmt }; 208 } 209 210 // Make sure that it is either adding statements or declartions but not both 211 // this is because otherwise the order would be awkward to predict 212 assert(( empty( stmts_before ) && empty( stmts_after )) 213 || ( empty( decls_before ) && empty( decls_after )) ); 214 215 // Create a new Compound Statement to hold the new decls/stmts 216 ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location ); 217 218 // Take all the declarations that go before 219 __pass::take_all( std::back_inserter( compound->kids ), decls_before ); 220 __pass::take_all( std::back_inserter( compound->kids ), stmts_before ); 221 222 // Insert the original declaration 223 compound->kids.emplace_back( nstmt ); 224 225 // Insert all the declarations that go before 226 __pass::take_all( std::back_inserter( compound->kids ), decls_after ); 227 __pass::take_all( std::back_inserter( compound->kids ), stmts_after ); 228 229 return {true, compound}; 230 } 231 232 template< typename core_t > 233 template< template <class...> class container_t > 234 __pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) { 235 __pedantic_pass_assert( __visit_children() ); 236 if( statements.empty() ) return {}; 237 238 // We are going to aggregate errors for all these statements 239 SemanticErrorException errors; 240 241 // add a few useful symbols to the scope 242 using __pass::empty; 243 244 // get the stmts/decls that will need to be spliced in 245 auto stmts_before = __pass::stmtsToAddBefore( core, 0 ); 246 auto stmts_after = __pass::stmtsToAddAfter ( core, 0 ); 247 auto decls_before = __pass::declsToAddBefore( core, 0 ); 248 auto decls_after = __pass::declsToAddAfter ( core, 0 ); 249 250 // These may be modified by subnode but most be restored once we exit this statemnet. 251 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 252 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); 253 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before ); 254 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after ); 255 256 // update pass statitistics 257 pass_visitor_stats.depth++; 258 pass_visitor_stats.max->push(pass_visitor_stats.depth); 259 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 260 261 __pass::resultNstmt<container_t> new_kids; 262 for( auto value : enumerate( statements ) ) { 263 try { 264 size_t i = value.idx; 265 const Stmt * stmt = value.val; 266 __pedantic_pass_assert( stmt ); 267 const ast::Stmt * new_stmt = stmt->accept( *this ); 268 assert( new_stmt ); 269 if(new_stmt != stmt ) { new_kids.differs = true; } 270 271 // Make sure that it is either adding statements or declartions but not both 272 // this is because otherwise the order would be awkward to predict 273 assert(( empty( stmts_before ) && empty( stmts_after )) 274 || ( empty( decls_before ) && empty( decls_after )) ); 275 276 // Take all the statements which should have gone after, N/A for first iteration 277 new_kids.take_all( decls_before ); 278 new_kids.take_all( stmts_before ); 279 280 // Now add the statement if there is one 281 if(new_stmt != stmt) { 282 new_kids.values.emplace_back( new_stmt, i, false ); 283 } else { 284 new_kids.values.emplace_back( nullptr, i, true ); 285 } 286 287 // Take all the declarations that go before 288 new_kids.take_all( decls_after ); 289 new_kids.take_all( stmts_after ); 128 } 129 130 template< typename core_t > 131 template< typename node_t > 132 auto ast::Pass< core_t >::call_accept( const node_t * node ) -> 133 typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type 134 { 135 __pedantic_pass_assert( __visit_children() ); 136 __pedantic_pass_assert( node ); 137 138 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR" ); 139 static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR" ); 140 141 auto nval = node->accept( *this ); 142 __pass::result1< 143 typename std::remove_pointer< decltype( node->accept(*this) ) >::type 144 > res; 145 res.differs = nval != node; 146 res.value = nval; 147 return res; 148 } 149 150 template< typename core_t > 151 ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) { 152 __pedantic_pass_assert( __visit_children() ); 153 __pedantic_pass_assert( expr ); 154 155 auto nval = expr->accept( *this ); 156 return { nval != expr, nval }; 157 } 158 159 template< typename core_t > 160 ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) { 161 __pedantic_pass_assert( __visit_children() ); 162 __pedantic_pass_assert( stmt ); 163 164 const ast::Stmt * nval = stmt->accept( *this ); 165 return { nval != stmt, nval }; 166 } 167 168 template< typename core_t > 169 ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept_top( const ast::Expr * expr ) { 170 __pedantic_pass_assert( __visit_children() ); 171 __pedantic_pass_assert( expr ); 172 173 const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 ); 174 if ( typeSubs_ptr && expr->env ) { 175 *typeSubs_ptr = expr->env; 176 } 177 178 auto nval = expr->accept( *this ); 179 return { nval != expr, nval }; 180 } 181 182 template< typename core_t > 183 ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept_as_compound( const ast::Stmt * stmt ) { 184 __pedantic_pass_assert( __visit_children() ); 185 __pedantic_pass_assert( stmt ); 186 187 // add a few useful symbols to the scope 188 using __pass::empty; 189 190 // get the stmts/decls that will need to be spliced in 191 auto stmts_before = __pass::stmtsToAddBefore( core, 0 ); 192 auto stmts_after = __pass::stmtsToAddAfter ( core, 0 ); 193 auto decls_before = __pass::declsToAddBefore( core, 0 ); 194 auto decls_after = __pass::declsToAddAfter ( core, 0 ); 195 196 // These may be modified by subnode but most be restored once we exit this statemnet. 197 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass::typeSubs( core, 0 ) ); 198 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 199 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); 200 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before ); 201 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after ); 202 203 // Now is the time to actually visit the node 204 const ast::Stmt * nstmt = stmt->accept( *this ); 205 206 // If the pass doesn't want to add anything then we are done 207 if ( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) { 208 return { nstmt != stmt, nstmt }; 209 } 210 211 // Make sure that it is either adding statements or declartions but not both 212 // this is because otherwise the order would be awkward to predict 213 assert(( empty( stmts_before ) && empty( stmts_after )) 214 || ( empty( decls_before ) && empty( decls_after )) ); 215 216 // Create a new Compound Statement to hold the new decls/stmts 217 ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location ); 218 219 // Take all the declarations that go before 220 __pass::take_all( std::back_inserter( compound->kids ), decls_before ); 221 __pass::take_all( std::back_inserter( compound->kids ), stmts_before ); 222 223 // Insert the original declaration 224 compound->kids.emplace_back( nstmt ); 225 226 // Insert all the declarations that go before 227 __pass::take_all( std::back_inserter( compound->kids ), decls_after ); 228 __pass::take_all( std::back_inserter( compound->kids ), stmts_after ); 229 230 return { true, compound }; 231 } 232 233 template< typename core_t > 234 template< template <class...> class container_t > 235 ast::__pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) { 236 __pedantic_pass_assert( __visit_children() ); 237 if ( statements.empty() ) return {}; 238 239 // We are going to aggregate errors for all these statements 240 SemanticErrorException errors; 241 242 // add a few useful symbols to the scope 243 using __pass::empty; 244 245 // get the stmts/decls that will need to be spliced in 246 auto stmts_before = __pass::stmtsToAddBefore( core, 0 ); 247 auto stmts_after = __pass::stmtsToAddAfter ( core, 0 ); 248 auto decls_before = __pass::declsToAddBefore( core, 0 ); 249 auto decls_after = __pass::declsToAddAfter ( core, 0 ); 250 251 // These may be modified by subnode but most be restored once we exit this statemnet. 252 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 253 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); 254 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before ); 255 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after ); 256 257 // update pass statitistics 258 pass_visitor_stats.depth++; 259 pass_visitor_stats.max->push(pass_visitor_stats.depth); 260 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 261 262 __pass::resultNstmt<container_t> new_kids; 263 for ( auto value : enumerate( statements ) ) { 264 try { 265 size_t i = value.idx; 266 const Stmt * stmt = value.val; 267 __pedantic_pass_assert( stmt ); 268 const ast::Stmt * new_stmt = stmt->accept( *this ); 269 assert( new_stmt ); 270 if ( new_stmt != stmt ) { new_kids.differs = true; } 271 272 // Make sure that it is either adding statements or declartions but not both 273 // this is because otherwise the order would be awkward to predict 274 assert(( empty( stmts_before ) && empty( stmts_after )) 275 || ( empty( decls_before ) && empty( decls_after )) ); 276 277 // Take all the statements which should have gone after, N/A for first iteration 278 new_kids.take_all( decls_before ); 279 new_kids.take_all( stmts_before ); 280 281 // Now add the statement if there is one 282 if ( new_stmt != stmt ) { 283 new_kids.values.emplace_back( new_stmt, i, false ); 284 } else { 285 new_kids.values.emplace_back( nullptr, i, true ); 290 286 } 291 catch ( SemanticErrorException &e ) { 292 errors.append( e ); 287 288 // Take all the declarations that go before 289 new_kids.take_all( decls_after ); 290 new_kids.take_all( stmts_after ); 291 } catch ( SemanticErrorException &e ) { 292 errors.append( e ); 293 } 294 } 295 pass_visitor_stats.depth--; 296 if ( !errors.isEmpty() ) { throw errors; } 297 298 return new_kids; 299 } 300 301 template< typename core_t > 302 template< template <class...> class container_t, typename node_t > 303 ast::__pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) { 304 __pedantic_pass_assert( __visit_children() ); 305 if ( container.empty() ) return {}; 306 SemanticErrorException errors; 307 308 pass_visitor_stats.depth++; 309 pass_visitor_stats.max->push(pass_visitor_stats.depth); 310 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 311 312 bool mutated = false; 313 container_t<ptr<node_t>> new_kids; 314 for ( const node_t * node : container ) { 315 try { 316 __pedantic_pass_assert( node ); 317 const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) ); 318 if ( new_stmt != node ) { 319 mutated = true; 320 new_kids.emplace_back( new_stmt ); 321 } else { 322 new_kids.emplace_back( nullptr ); 293 323 } 294 } 295 pass_visitor_stats.depth--; 296 if ( !errors.isEmpty() ) { throw errors; } 297 298 return new_kids; 299 } 300 301 template< typename core_t > 302 template< template <class...> class container_t, typename node_t > 303 __pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) { 304 __pedantic_pass_assert( __visit_children() ); 305 if( container.empty() ) return {}; 306 SemanticErrorException errors; 307 308 pass_visitor_stats.depth++; 309 pass_visitor_stats.max->push(pass_visitor_stats.depth); 310 pass_visitor_stats.avg->push(pass_visitor_stats.depth); 311 312 bool mutated = false; 313 container_t<ptr<node_t>> new_kids; 314 for ( const node_t * node : container ) { 315 try { 316 __pedantic_pass_assert( node ); 317 const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) ); 318 if(new_stmt != node ) { 319 mutated = true; 320 new_kids.emplace_back( new_stmt ); 321 } else { 322 new_kids.emplace_back( nullptr ); 323 } 324 325 } 326 catch( SemanticErrorException &e ) { 327 errors.append( e ); 328 } 329 } 330 331 __pedantic_pass_assert( new_kids.size() == container.size() ); 332 pass_visitor_stats.depth--; 333 if ( ! errors.isEmpty() ) { throw errors; } 334 335 return ast::__pass::resultN<container_t, node_t>{ mutated, new_kids }; 336 } 337 338 template< typename core_t > 339 template<typename node_t, typename super_t, typename field_t> 340 void ast::Pass< core_t >::maybe_accept( 341 const node_t * & parent, 342 field_t super_t::*field 343 ) { 344 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 345 346 if(__pass::skip(parent->*field)) return; 347 const auto & old_val = __pass::get(parent->*field, 0); 348 349 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR"); 350 351 auto new_val = call_accept( old_val ); 352 353 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR"); 354 355 if( new_val.differs ) { 356 auto new_parent = __pass::mutate<core_t>(parent); 357 new_val.apply(new_parent, field); 358 parent = new_parent; 359 } 360 } 361 362 template< typename core_t > 363 template<typename node_t, typename super_t, typename field_t> 364 void ast::Pass< core_t >::maybe_accept_top( 365 const node_t * & parent, 366 field_t super_t::*field 367 ) { 368 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 369 370 if(__pass::skip(parent->*field)) return; 371 const auto & old_val = __pass::get(parent->*field, 0); 372 373 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR"); 374 375 auto new_val = call_accept_top( old_val ); 376 377 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR"); 378 379 if( new_val.differs ) { 380 auto new_parent = __pass::mutate<core_t>(parent); 381 new_val.apply(new_parent, field); 382 parent = new_parent; 383 } 384 } 385 386 template< typename core_t > 387 template<typename node_t, typename super_t, typename field_t> 388 void ast::Pass< core_t >::maybe_accept_as_compound( 389 const node_t * & parent, 390 field_t super_t::*child 391 ) { 392 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 393 394 if(__pass::skip(parent->*child)) return; 395 const auto & old_val = __pass::get(parent->*child, 0); 396 397 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR"); 398 399 auto new_val = call_accept_as_compound( old_val ); 400 401 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR"); 402 403 if( new_val.differs ) { 404 auto new_parent = __pass::mutate<core_t>(parent); 405 new_val.apply( new_parent, child ); 406 parent = new_parent; 407 } 408 } 409 324 } catch ( SemanticErrorException &e ) { 325 errors.append( e ); 326 } 327 } 328 329 __pedantic_pass_assert( new_kids.size() == container.size() ); 330 pass_visitor_stats.depth--; 331 if ( !errors.isEmpty() ) { throw errors; } 332 333 return ast::__pass::resultN<container_t, node_t>{ mutated, new_kids }; 334 } 335 336 template< typename core_t > 337 template<typename node_t, typename super_t, typename field_t> 338 void ast::Pass< core_t >::maybe_accept( 339 const node_t * & parent, 340 field_t super_t::*field 341 ) { 342 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 343 344 if ( __pass::skip( parent->*field ) ) return; 345 const auto & old_val = __pass::get(parent->*field, 0); 346 347 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 348 349 auto new_val = call_accept( old_val ); 350 351 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" ); 352 353 if ( new_val.differs ) { 354 auto new_parent = __pass::mutate<core_t>(parent); 355 new_val.apply(new_parent, field); 356 parent = new_parent; 357 } 358 } 359 360 template< typename core_t > 361 template<typename node_t, typename super_t, typename field_t> 362 void ast::Pass< core_t >::maybe_accept_top( 363 const node_t * & parent, 364 field_t super_t::*field 365 ) { 366 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 367 368 if ( __pass::skip( parent->*field ) ) return; 369 const auto & old_val = __pass::get(parent->*field, 0); 370 371 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 372 373 auto new_val = call_accept_top( old_val ); 374 375 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" ); 376 377 if ( new_val.differs ) { 378 auto new_parent = __pass::mutate<core_t>(parent); 379 new_val.apply(new_parent, field); 380 parent = new_parent; 381 } 382 } 383 384 template< typename core_t > 385 template<typename node_t, typename super_t, typename field_t> 386 void ast::Pass< core_t >::maybe_accept_as_compound( 387 const node_t * & parent, 388 field_t super_t::*child 389 ) { 390 static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" ); 391 392 if ( __pass::skip( parent->*child ) ) return; 393 const auto & old_val = __pass::get(parent->*child, 0); 394 395 static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" ); 396 397 auto new_val = call_accept_as_compound( old_val ); 398 399 static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR" ); 400 401 if ( new_val.differs ) { 402 auto new_parent = __pass::mutate<core_t>(parent); 403 new_val.apply( new_parent, child ); 404 parent = new_parent; 405 } 410 406 } 411 407 … … 761 757 762 758 if ( __visit_children() ) { 763 // Do not enter (or leave) a new scope if atFunctionTop. Remember to save the result. 764 auto guard1 = makeFuncGuard( [this, enterScope = !this->atFunctionTop]() { 765 if ( enterScope ) { 766 __pass::symtab::enter(core, 0); 767 } 768 }, [this, leaveScope = !this->atFunctionTop]() { 769 if ( leaveScope ) { 770 __pass::symtab::leave(core, 0); 771 } 772 }); 773 ValueGuard< bool > guard2( atFunctionTop ); 774 atFunctionTop = false; 775 guard_scope guard3 { *this }; 776 maybe_accept( node, &CompoundStmt::kids ); 759 // Do not enter (or leave) a new symbol table scope if atFunctionTop. 760 // But always enter (and leave) a new general scope. 761 if ( atFunctionTop ) { 762 ValueGuard< bool > guard1( atFunctionTop ); 763 atFunctionTop = false; 764 guard_scope guard2( *this ); 765 maybe_accept( node, &CompoundStmt::kids ); 766 } else { 767 guard_symtab guard1( *this ); 768 guard_scope guard2( *this ); 769 maybe_accept( node, &CompoundStmt::kids ); 770 } 777 771 } 778 772 -
src/AST/SymbolTable.cpp
r24d6572 r62d62db 91 91 } 92 92 93 SymbolTable::SymbolTable( )93 SymbolTable::SymbolTable( ErrorDetection errorMode ) 94 94 : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(), 95 prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }95 prevScope(), scope( 0 ), repScope( 0 ), errorMode(errorMode) { ++*stats().count; } 96 96 97 97 SymbolTable::~SymbolTable() { stats().size->push( idTable ? idTable->size() : 0 ); } 98 99 void SymbolTable::OnFindError( CodeLocation location, std::string error ) const { 100 assertf( errorMode != AssertClean, "Name collision/redefinition, found during a compilation phase where none should be possible. Detail: %s", error.c_str() ); 101 if (errorMode == ValidateOnAdd) { 102 SemanticError(location, error); 103 } 104 assertf( errorMode == IgnoreErrors, "Unrecognized symbol-table error mode %d", errorMode ); 105 } 98 106 99 107 void SymbolTable::enterScope() { … … 274 282 } 275 283 276 namespace { 277 /// true if redeclaration conflict between two types 278 bool addedTypeConflicts( const NamedTypeDecl * existing, const NamedTypeDecl * added ) { 279 if ( existing->base == nullptr ) { 280 return false; 281 } else if ( added->base == nullptr ) { 282 return true; 283 } else { 284 // typedef redeclarations are errors only if types are different 285 if ( ! ResolvExpr::typesCompatible( existing->base, added->base ) ) { 286 SemanticError( added->location, "redeclaration of " + added->name ); 287 } 288 } 289 // does not need to be added to the table if both existing and added have a base that are 290 // the same 284 bool SymbolTable::addedTypeConflicts( 285 const NamedTypeDecl * existing, const NamedTypeDecl * added ) const { 286 if ( existing->base == nullptr ) { 287 return false; 288 } else if ( added->base == nullptr ) { 291 289 return true; 292 } 293 294 /// true if redeclaration conflict between two aggregate declarations 295 bool addedDeclConflicts( const AggregateDecl * existing, const AggregateDecl * added ) { 296 if ( ! existing->body ) { 297 return false; 298 } else if ( added->body ) { 299 SemanticError( added, "redeclaration of " ); 300 } 301 return true; 302 } 290 } else { 291 // typedef redeclarations are errors only if types are different 292 if ( ! ResolvExpr::typesCompatible( existing->base, added->base ) ) { 293 OnFindError( added->location, "redeclaration of " + added->name ); 294 } 295 } 296 // does not need to be added to the table if both existing and added have a base that are 297 // the same 298 return true; 299 } 300 301 bool SymbolTable::addedDeclConflicts( 302 const AggregateDecl * existing, const AggregateDecl * added ) const { 303 if ( ! existing->body ) { 304 return false; 305 } else if ( added->body ) { 306 OnFindError( added, "redeclaration of " ); 307 } 308 return true; 303 309 } 304 310 … … 653 659 if ( deleter && ! existing.deleter ) { 654 660 if ( handleConflicts.mode == OnConflict::Error ) { 655 SemanticError( added, "deletion of defined identifier " );661 OnFindError( added, "deletion of defined identifier " ); 656 662 } 657 663 return true; 658 664 } else if ( ! deleter && existing.deleter ) { 659 665 if ( handleConflicts.mode == OnConflict::Error ) { 660 SemanticError( added, "definition of deleted identifier " );666 OnFindError( added, "definition of deleted identifier " ); 661 667 } 662 668 return true; … … 666 672 if ( isDefinition( added ) && isDefinition( existing.id ) ) { 667 673 if ( handleConflicts.mode == OnConflict::Error ) { 668 SemanticError( added,674 OnFindError( added, 669 675 isFunction( added ) ? 670 676 "duplicate function definition for " : … … 675 681 } else { 676 682 if ( handleConflicts.mode == OnConflict::Error ) { 677 SemanticError( added, "duplicate definition for " );683 OnFindError( added, "duplicate definition for " ); 678 684 } 679 685 return true; … … 727 733 // Check that a Cforall declaration doesn't override any C declaration 728 734 if ( hasCompatibleCDecl( name, mangleName ) ) { 729 SemanticError( decl, "Cforall declaration hides C function " );735 OnFindError( decl, "Cforall declaration hides C function " ); 730 736 } 731 737 } else { … … 733 739 // type-compatibility, which it may not be. 734 740 if ( hasIncompatibleCDecl( name, mangleName ) ) { 735 SemanticError( decl, "conflicting overload of C function " );741 OnFindError( decl, "conflicting overload of C function " ); 736 742 } 737 743 } -
src/AST/SymbolTable.hpp
r24d6572 r62d62db 93 93 94 94 public: 95 SymbolTable(); 95 96 /// Mode to control when (during which pass) user-caused name-declaration errors get reported. 97 /// The default setting `AssertClean` supports, "I expect all user-caused errors to have been 98 /// reported by now," or, "I wouldn't know what to do with an error; are there even any here?" 99 enum ErrorDetection { 100 AssertClean, ///< invalid user decls => assert fails during addFoo (default) 101 ValidateOnAdd, ///< invalid user decls => calls SemanticError during addFoo 102 IgnoreErrors ///< acts as if unspecified decls were removed, forcing validity 103 }; 104 105 explicit SymbolTable( 106 ErrorDetection ///< mode for the lifetime of the symbol table (whole pass) 107 ); 108 SymbolTable() : SymbolTable(AssertClean) {} 96 109 ~SymbolTable(); 110 111 ErrorDetection getErrorMode() const { 112 return errorMode; 113 } 97 114 98 115 // when using an indexer manually (e.g., within a mutator traversal), it is necessary to … … 158 175 159 176 private: 177 void OnFindError( CodeLocation location, std::string error ) const; 178 179 template< typename T > 180 void OnFindError( const T * obj, const std::string & error ) const { 181 OnFindError( obj->location, toString( error, obj ) ); 182 } 183 184 template< typename T > 185 void OnFindError( CodeLocation location, const T * obj, const std::string & error ) const { 186 OnFindError( location, toString( error, obj ) ); 187 } 188 160 189 /// Ensures that a proper backtracking scope exists before a mutation 161 190 void lazyInitScope(); … … 168 197 bool removeSpecialOverrides( IdData & decl, MangleTable::Ptr & mangleTable ); 169 198 170 /// Options for handling identifier conflicts 199 /// Error detection mode given at construction (pass-specific). 200 /// Logically const, except that the symbol table's push-pop is achieved by autogenerated 201 /// assignment onto self. The feield is left motuable to keep this code-gen simple. 202 /// Conceptual constness is preserved by all SymbolTable in a stack sharing the same mode. 203 ErrorDetection errorMode; 204 205 /// Options for handling identifier conflicts. 206 /// Varies according to AST location during traversal: captures semantics of the construct 207 /// being visited as "would shadow" vs "must not collide." 208 /// At a given AST location, is the same for every pass. 171 209 struct OnConflict { 172 210 enum { 173 Error, ///< Throw a semantic error211 Error, ///< Follow the current pass's ErrorDetection mode (may throw a semantic error) 174 212 Delete ///< Delete the earlier version with the delete statement 175 213 } mode; … … 191 229 const Decl * deleter ); 192 230 231 /// true if redeclaration conflict between two types 232 bool addedTypeConflicts( const NamedTypeDecl * existing, const NamedTypeDecl * added ) const; 233 234 /// true if redeclaration conflict between two aggregate declarations 235 bool addedDeclConflicts( const AggregateDecl * existing, const AggregateDecl * added ) const; 236 193 237 /// common code for addId, addDeletedId, etc. 194 238 void addIdCommon( … … 213 257 } 214 258 259 215 260 // Local Variables: // 216 261 // tab-width: 4 // -
src/AST/Util.cpp
r24d6572 r62d62db 83 83 } 84 84 85 /// Check that the MemberExpr has an aggregate type and matching member. 86 void memberMatchesAggregate( const MemberExpr * expr ) { 87 const Type * aggrType = expr->aggregate->result->stripReferences(); 88 const AggregateDecl * decl = nullptr; 89 if ( auto inst = dynamic_cast<const StructInstType *>( aggrType ) ) { 90 decl = inst->base; 91 } else if ( auto inst = dynamic_cast<const UnionInstType *>( aggrType ) ) { 92 decl = inst->base; 93 } 94 assertf( decl, "Aggregate of member not correct type." ); 95 96 for ( auto aggrMember : decl->members ) { 97 if ( expr->member == aggrMember ) { 98 return; 99 } 100 } 101 assertf( false, "Member not found." ); 102 } 103 85 104 struct InvariantCore { 86 105 // To save on the number of visits: this is a kind of composed core. … … 108 127 } 109 128 129 void previsit( const MemberExpr * node ) { 130 previsit( (const ParseNode *)node ); 131 memberMatchesAggregate( node ); 132 } 133 110 134 void postvisit( const Node * node ) { 111 135 no_strong_cycles.postvisit( node );
Note:
See TracChangeset
for help on using the changeset viewer.