- Timestamp:
- Jun 12, 2023, 2:45:32 PM (2 years ago)
- Branches:
- ast-experimental, master
- Children:
- 62d62db
- Parents:
- 34b4268 (diff), 251ce80 (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:
-
- 31 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Attribute.hpp
r34b4268 r24d6572 27 27 class Expr; 28 28 29 /// An entry in an attribute list: `__attribute__(( ... ))` 29 30 class Attribute final : public Node { 30 31 public: -
src/AST/Convert.cpp
r34b4268 r24d6572 559 559 auto stmt = new SuspendStmt(); 560 560 stmt->then = get<CompoundStmt>().accept1( node->then ); 561 switch (node->type) {561 switch (node->kind) { 562 562 case ast::SuspendStmt::None : stmt->type = SuspendStmt::None ; break; 563 563 case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break; … … 565 565 } 566 566 return stmtPostamble( stmt, node ); 567 } 568 569 const ast::WhenClause * visit( const ast::WhenClause * node ) override final { 570 // There is no old-AST WhenClause, so this should never be called. 571 assert( !node ); 572 return nullptr; 567 573 } 568 574 … … 573 579 for ( auto clause : node->clauses ) { 574 580 stmt->clauses.push_back({{ 575 get<Expression>().accept1( clause->target _func),581 get<Expression>().accept1( clause->target ), 576 582 get<Expression>().acceptL( clause->target_args ), 577 583 }, 578 584 get<Statement>().accept1( clause->stmt ), 579 get<Expression>().accept1( clause-> cond ),585 get<Expression>().accept1( clause->when_cond ), 580 586 }); 581 587 } … … 594 600 const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final { 595 601 // There is no old-AST WaitForClause, so this should never be called. 602 assert( !node ); 603 return nullptr; 604 } 605 606 const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final { 607 // There is no old-AST WaitUntilStmt, so this should never be called. 596 608 assert( !node ); 597 609 return nullptr; … … 1683 1695 GET_ACCEPT_V(attributes, Attribute), 1684 1696 { old->get_funcSpec().val }, 1685 old->type->isVarArgs1697 (old->type->isVarArgs) ? ast::VariableArgs : ast::FixedArgs 1686 1698 }; 1687 1699 … … 1989 2001 GET_ACCEPT_1(else_, Stmt), 1990 2002 GET_ACCEPT_V(initialization, Stmt), 1991 old->isDoWhile,2003 (old->isDoWhile) ? ast::DoWhile : ast::While, 1992 2004 GET_LABELS_V(old->labels) 1993 2005 ); … … 2131 2143 virtual void visit( const SuspendStmt * old ) override final { 2132 2144 if ( inCache( old ) ) return; 2133 ast::SuspendStmt:: Typetype;2145 ast::SuspendStmt::Kind type; 2134 2146 switch (old->type) { 2135 2147 case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break; … … 2158 2170 auto clause = new ast::WaitForClause( old->location ); 2159 2171 2160 clause->target _func= GET_ACCEPT_1(clauses[i].target.function, Expr);2172 clause->target = GET_ACCEPT_1(clauses[i].target.function, Expr); 2161 2173 clause->target_args = GET_ACCEPT_V(clauses[i].target.arguments, Expr); 2162 2174 clause->stmt = GET_ACCEPT_1(clauses[i].statement, Stmt); 2163 clause-> cond = GET_ACCEPT_1(clauses[i].condition, Expr);2175 clause->when_cond = GET_ACCEPT_1(clauses[i].condition, Expr); 2164 2176 2165 2177 stmt->clauses.push_back( clause ); -
src/AST/Create.cpp
r34b4268 r24d6572 20 20 #include "AST/Decl.hpp" 21 21 #include "AST/Type.hpp" 22 #include "Common/Iterate.hpp" 22 23 23 24 namespace ast { -
src/AST/Decl.cpp
r34b4268 r24d6572 20 20 #include <unordered_map> 21 21 22 #include "Common/ utility.h"22 #include "Common/Eval.h" // for eval 23 23 24 24 #include "Fwd.hpp" // for UniqueId … … 57 57 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 58 58 CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage, 59 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)59 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs ) 60 60 : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), 61 61 type_params(std::move(forall)), assertions(), 62 62 params(std::move(params)), returns(std::move(returns)), stmts( stmts ) { 63 FunctionType * ftype = new FunctionType( static_cast<ArgumentFlag>(isVarArgs));63 FunctionType * ftype = new FunctionType( isVarArgs ); 64 64 for (auto & param : this->params) { 65 65 ftype->params.emplace_back(param->get_type()); … … 81 81 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 82 82 CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage, 83 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)83 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs ) 84 84 : DeclWithType( location, name, storage, linkage, std::move(attrs), fs ), 85 85 type_params( std::move( forall) ), assertions( std::move( assertions ) ), 86 86 params( std::move(params) ), returns( std::move(returns) ), 87 87 type( nullptr ), stmts( stmts ) { 88 FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );88 FunctionType * type = new FunctionType( isVarArgs ); 89 89 for ( auto & param : this->params ) { 90 90 type->params.emplace_back( param->get_type() ); -
src/AST/Decl.hpp
r34b4268 r24d6572 10 10 // Created On : Thu May 9 10:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Nov 24 9:44:00 202213 // Update Count : 3 412 // Last Modified On : Wed Apr 5 10:42:00 2023 13 // Update Count : 35 14 14 // 15 15 … … 122 122 }; 123 123 124 /// Function variable arguments flag 125 enum ArgumentFlag { FixedArgs, VariableArgs }; 126 124 127 /// Object declaration `int foo()` 125 128 class FunctionDecl : public DeclWithType { … … 144 147 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 145 148 CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall, 146 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);149 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs ); 147 150 148 151 FunctionDecl( const CodeLocation & location, const std::string & name, … … 150 153 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 151 154 CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall, 152 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);155 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs ); 153 156 154 157 const Type * get_type() const override; … … 313 316 public: 314 317 bool isTyped; // isTyped indicated if the enum has a declaration like: 315 // enum (type_optional) Name {...} 318 // enum (type_optional) Name {...} 316 319 ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum 317 320 enum class EnumHiding { Visible, Hide } hide; … … 371 374 }; 372 375 376 /// Assembly declaration: `asm ... ( "..." : ... )` 373 377 class AsmDecl : public Decl { 374 378 public: -
src/AST/Expr.cpp
r34b4268 r24d6572 30 30 #include "Common/SemanticError.h" 31 31 #include "GenPoly/Lvalue.h" // for referencesPermissable 32 #include "ResolvExpr/ typeops.h"// for extractResultType32 #include "ResolvExpr/Unify.h" // for extractResultType 33 33 #include "Tuples/Tuples.h" // for makeTupleType 34 34 -
src/AST/Expr.hpp
r34b4268 r24d6572 256 256 }; 257 257 258 /// A name qualified by a namespace or type. 258 259 class QualifiedNameExpr final : public Expr { 259 260 public: … … 261 262 std::string name; 262 263 263 QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 264 QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 264 265 : Expr( loc ), type_decl( d ), name( n ) {} 265 266 … … 631 632 }; 632 633 634 /// A name that refers to a generic dimension parameter. 633 635 class DimensionExpr final : public Expr { 634 636 public: … … 920 922 }; 921 923 922 923 924 } 924 925 -
src/AST/Fwd.hpp
r34b4268 r24d6572 15 15 16 16 #pragma once 17 18 template<typename> struct bitfield; 17 19 18 20 #include "AST/Node.hpp" … … 56 58 class FinallyClause; 57 59 class SuspendStmt; 60 class WhenClause; 58 61 class WaitForStmt; 59 62 class WaitForClause; 63 class WaitUntilStmt; 60 64 class WithStmt; 61 65 class DeclStmt; … … 147 151 class TranslationGlobal; 148 152 153 // For the following types, only use the using type. 154 namespace CV { 155 struct qualifier_flags; 156 using Qualifiers = bitfield<qualifier_flags>; 149 157 } 158 namespace Function { 159 struct spec_flags; 160 using Specs = bitfield<spec_flags>; 161 } 162 namespace Storage { 163 struct class_flags; 164 using Classes = bitfield<class_flags>; 165 } 166 namespace Linkage { 167 struct spec_flags; 168 using Spec = bitfield<spec_flags>; 169 } 170 171 } -
src/AST/Init.hpp
r34b4268 r24d6572 117 117 ptr<Init> init; 118 118 119 ConstructorInit( 119 ConstructorInit( 120 120 const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init ) 121 121 : Init( loc, MaybeConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {} -
src/AST/Inspect.cpp
r34b4268 r24d6572 10 10 // Created On : Fri Jun 24 13:16:31 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Oct 3 11:04:00 202213 // Update Count : 312 // Last Modified On : Fri Apr 14 15:09:00 2023 13 // Update Count : 4 14 14 // 15 15 … … 168 168 } 169 169 170 bool isUnnamedBitfield( const ast::ObjectDecl * obj ) { 171 return obj && obj->name.empty() && obj->bitfieldWidth; 172 } 173 170 174 } // namespace ast -
src/AST/Inspect.hpp
r34b4268 r24d6572 10 10 // Created On : Fri Jun 24 13:16:31 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Sep 22 13:44:00 202213 // Update Count : 212 // Last Modified On : Fri Apr 14 15:09:00 2023 13 // Update Count : 3 14 14 // 15 15 … … 38 38 const ApplicationExpr * isIntrinsicCallExpr( const Expr * expr ); 39 39 40 /// Returns true if obj's name is the empty string and it has a bitfield width. 41 bool isUnnamedBitfield( const ObjectDecl * obj ); 42 40 43 } -
src/AST/Node.cpp
r34b4268 r24d6572 174 174 template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::weak >; 175 175 template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::strong >; 176 template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::weak >; 177 template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::strong >; 176 178 template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::weak >; 177 179 template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::strong >; 178 180 template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::weak >; 179 181 template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::strong >; 182 template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::weak >; 183 template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::strong >; 180 184 template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::weak >; 181 185 template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::strong >; -
src/AST/Node.hpp
r34b4268 r24d6572 19 19 #include <cstddef> // for nullptr_t 20 20 #include <iosfwd> 21 #include <type_traits> // for remove_reference22 21 23 22 #include "Common/ErrorObjects.h" // for SemanticErrorException … … 36 35 Node(const Node&) : strong_count(0), weak_count(0) {} 37 36 Node(Node&&) : strong_count(0), weak_count(0) {} 38 Node& operator= 39 Node& operator= 37 Node& operator=(const Node&) = delete; 38 Node& operator=(Node&&) = delete; 40 39 virtual ~Node() {} 41 40 -
src/AST/ParseNode.hpp
r34b4268 r24d6572 40 40 template<typename node_t> 41 41 friend node_t * mutate(const node_t * node); 42 template<typename node_t> 43 friend node_t * shallowCopy(const node_t * node); 42 44 }; 43 45 -
src/AST/Pass.hpp
r34b4268 r24d6572 66 66 // 67 67 // Other Special Members: 68 // | beginScope - A method with no parameters or return value, called each time the 69 // visitor enters a block. 70 // | endScope - A method with no parameters or return value, called each time the 71 // visitor leaves a block. 68 72 // | result - Either a method that takes no parameters or a field. If a method (or 69 73 // callable field) get_result calls it, otherwise the value is returned. … … 82 86 { 83 87 // After the pass is constructed, check if it wants the have a pointer to the wrapping visitor 84 type * const * visitor = __pass::visitor( core, 0);85 if (visitor) {88 type * const * visitor = __pass::visitor( core, 0 ); 89 if ( visitor ) { 86 90 *const_cast<type **>( visitor ) = this; 87 91 } … … 94 98 95 99 /// If the core defines a result, call it if possible, otherwise return it. 96 inline auto get_result() -> decltype( __pass:: get_result( core, '0' ) ) {97 return __pass:: get_result( core, '0' );100 inline auto get_result() -> decltype( __pass::result::get( core, '0' ) ) { 101 return __pass::result::get( core, '0' ); 98 102 } 99 103 … … 158 162 const ast::FinallyClause * visit( const ast::FinallyClause * ) override final; 159 163 const ast::Stmt * visit( const ast::SuspendStmt * ) override final; 164 const ast::WhenClause * visit( const ast::WhenClause * ) override final; 160 165 const ast::Stmt * visit( const ast::WaitForStmt * ) override final; 161 166 const ast::WaitForClause * visit( const ast::WaitForClause * ) override final; 167 const ast::Stmt * visit( const ast::WaitUntilStmt * ) override final; 162 168 const ast::Decl * visit( const ast::WithStmt * ) override final; 163 169 const ast::NullStmt * visit( const ast::NullStmt * ) override final; -
src/AST/Pass.impl.hpp
r34b4268 r24d6572 20 20 #include <unordered_map> 21 21 22 #include "AST/Copy.hpp" 22 23 #include "AST/TranslationUnit.hpp" 23 24 #include "AST/TypeSubstitution.hpp" … … 45 46 46 47 #ifdef PEDANTIC_PASS_ASSERT 47 #define __pedantic_pass_assert(...) assert 48 #define __pedantic_pass_assert(...) assert(__VA_ARGS__) 48 49 #define __pedantic_pass_assertf(...) assertf(__VA_ARGS__) 49 50 #else … … 124 125 return !new_val.empty(); 125 126 } 126 }127 128 template< typename node_t >129 template< typename object_t, typename super_t, typename field_t >130 void __pass::result1< node_t >::apply( object_t * object, field_t super_t::* field ) {131 object->*field = value;132 127 } 133 128 … … 233 228 234 229 return {true, compound}; 235 }236 237 template< template <class...> class container_t >238 template< typename object_t, typename super_t, typename field_t >239 void __pass::resultNstmt<container_t>::apply(object_t * object, field_t super_t::* field) {240 auto & container = object->*field;241 __pedantic_pass_assert( container.size() <= values.size() );242 243 auto cit = enumerate(container).begin();244 245 container_t<ptr<Stmt>> nvals;246 for (delta & d : values) {247 if ( d.is_old ) {248 __pedantic_pass_assert( cit.idx <= d.old_idx );249 std::advance( cit, d.old_idx - cit.idx );250 nvals.push_back( std::move( (*cit).val) );251 } else {252 nvals.push_back( std::move(d.new_val) );253 }254 }255 256 container = std::move(nvals);257 }258 259 template< template <class...> class container_t >260 template< template <class...> class incontainer_t >261 void __pass::resultNstmt< container_t >::take_all( incontainer_t<ptr<Stmt>> * stmts ) {262 if (!stmts || stmts->empty()) return;263 264 std::transform(stmts->begin(), stmts->end(), std::back_inserter( values ),265 [](ast::ptr<ast::Stmt>& stmt) -> delta {266 return delta( stmt.release(), -1, false );267 });268 stmts->clear();269 differs = true;270 }271 272 template< template<class...> class container_t >273 template< template<class...> class incontainer_t >274 void __pass::resultNstmt< container_t >::take_all( incontainer_t<ptr<Decl>> * decls ) {275 if (!decls || decls->empty()) return;276 277 std::transform(decls->begin(), decls->end(), std::back_inserter( values ),278 [](ast::ptr<ast::Decl>& decl) -> delta {279 auto loc = decl->location;280 auto stmt = new DeclStmt( loc, decl.release() );281 return delta( stmt, -1, false );282 });283 decls->clear();284 differs = true;285 230 } 286 231 … … 352 297 353 298 return new_kids; 354 }355 356 template< template <class...> class container_t, typename node_t >357 template< typename object_t, typename super_t, typename field_t >358 void __pass::resultN<container_t, node_t>::apply(object_t * object, field_t super_t::* field) {359 auto & container = object->*field;360 __pedantic_pass_assert( container.size() == values.size() );361 362 for(size_t i = 0; i < container.size(); i++) {363 // Take all the elements that are different in 'values'364 // and swap them into 'container'365 if( values[i] != nullptr ) swap(container[i], values[i]);366 }367 368 // Now the original containers should still have the unchanged values369 // but also contain the new values370 299 } 371 300 … … 836 765 if ( enterScope ) { 837 766 __pass::symtab::enter(core, 0); 838 __pass::scope::enter(core, 0);839 767 } 840 768 }, [this, leaveScope = !this->atFunctionTop]() { 841 769 if ( leaveScope ) { 842 770 __pass::symtab::leave(core, 0); 843 __pass::scope::leave(core, 0);844 771 } 845 772 }); … … 1067 994 1068 995 //-------------------------------------------------------------------------- 996 // WhenClause 997 template< typename core_t > 998 const ast::WhenClause * ast::Pass< core_t >::visit( const ast::WhenClause * node ) { 999 VISIT_START( node ); 1000 1001 if ( __visit_children() ) { 1002 maybe_accept( node, &WhenClause::target ); 1003 maybe_accept( node, &WhenClause::stmt ); 1004 maybe_accept( node, &WhenClause::when_cond ); 1005 } 1006 1007 VISIT_END( WhenClause, node ); 1008 } 1009 1010 //-------------------------------------------------------------------------- 1069 1011 // WaitForStmt 1070 1012 template< typename core_t > … … 1091 1033 1092 1034 if ( __visit_children() ) { 1093 maybe_accept( node, &WaitForClause::target _func);1035 maybe_accept( node, &WaitForClause::target ); 1094 1036 maybe_accept( node, &WaitForClause::target_args ); 1095 1037 maybe_accept( node, &WaitForClause::stmt ); 1096 maybe_accept( node, &WaitForClause:: cond );1038 maybe_accept( node, &WaitForClause::when_cond ); 1097 1039 } 1098 1040 1099 1041 VISIT_END( WaitForClause, node ); 1042 } 1043 1044 //-------------------------------------------------------------------------- 1045 // WaitUntilStmt 1046 template< typename core_t > 1047 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitUntilStmt * node ) { 1048 VISIT_START( node ); 1049 1050 if ( __visit_children() ) { 1051 maybe_accept( node, &WaitUntilStmt::clauses ); 1052 maybe_accept( node, &WaitUntilStmt::timeout_time ); 1053 maybe_accept( node, &WaitUntilStmt::timeout_stmt ); 1054 maybe_accept( node, &WaitUntilStmt::timeout_cond ); 1055 maybe_accept( node, &WaitUntilStmt::else_stmt ); 1056 maybe_accept( node, &WaitUntilStmt::else_cond ); 1057 } 1058 1059 VISIT_END( Stmt, node ); 1100 1060 } 1101 1061 … … 2043 2003 if ( __visit_children() ) { 2044 2004 maybe_accept( node, &TupleType::types ); 2045 maybe_accept( node, &TupleType::members );2046 2005 } 2047 2006 … … 2205 2164 } 2206 2165 2166 #undef __pedantic_pass_assertf 2167 #undef __pedantic_pass_assert 2207 2168 #undef VISIT_START 2208 2169 #undef VISIT_END -
src/AST/Pass.proto.hpp
r34b4268 r24d6572 17 17 // IWYU pragma: private, include "Pass.hpp" 18 18 19 #include "Common/Iterate.hpp" 19 20 #include "Common/Stats/Heap.h" 20 21 21 namespace ast { 22 template<typename core_t> 23 class Pass; 24 25 class TranslationUnit; 26 27 struct PureVisitor; 28 29 template<typename node_t> 30 node_t * deepCopy( const node_t * localRoot ); 31 32 namespace __pass { 33 typedef std::function<void( void * )> cleanup_func_t; 34 typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t; 35 36 37 // boolean reference that may be null 38 // either refers to a boolean value or is null and returns true 39 class bool_ref { 40 public: 41 bool_ref() = default; 42 ~bool_ref() = default; 43 44 operator bool() { return m_ref ? *m_ref : true; } 45 bool operator=( bool val ) { assert(m_ref); return *m_ref = val; } 46 47 private: 48 49 friend class visit_children_guard; 50 51 bool * set( bool * val ) { 52 bool * prev = m_ref; 53 m_ref = val; 54 return prev; 55 } 56 57 bool * m_ref = nullptr; 22 template<typename core_t> class Pass; 23 class TranslationUnit; 24 struct PureVisitor; 25 template<typename node_t> node_t * deepCopy( const node_t * ); 26 } 27 28 #ifdef PEDANTIC_PASS_ASSERT 29 #define __pedantic_pass_assert(...) assert(__VA_ARGS__) 30 #define __pedantic_pass_assertf(...) assertf(__VA_ARGS__) 31 #else 32 #define __pedantic_pass_assert(...) 33 #define __pedantic_pass_assertf(...) 34 #endif 35 36 namespace ast::__pass { 37 38 typedef std::function<void( void * )> cleanup_func_t; 39 typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t; 40 41 // boolean reference that may be null 42 // either refers to a boolean value or is null and returns true 43 class bool_ref { 44 public: 45 bool_ref() = default; 46 ~bool_ref() = default; 47 48 operator bool() { return m_ref ? *m_ref : true; } 49 bool operator=( bool val ) { assert(m_ref); return *m_ref = val; } 50 51 private: 52 53 friend class visit_children_guard; 54 55 bool * set( bool * val ) { 56 bool * prev = m_ref; 57 m_ref = val; 58 return prev; 59 } 60 61 bool * m_ref = nullptr; 62 }; 63 64 // Implementation of the guard value 65 // Created inside the visit scope 66 class guard_value { 67 public: 68 /// Push onto the cleanup 69 guard_value( at_cleanup_t * at_cleanup ) { 70 if( at_cleanup ) { 71 *at_cleanup = [this]( cleanup_func_t && func, void* val ) { 72 push( std::move( func ), val ); 73 }; 74 } 75 } 76 77 ~guard_value() { 78 while( !cleanups.empty() ) { 79 auto& cleanup = cleanups.top(); 80 cleanup.func( cleanup.val ); 81 cleanups.pop(); 82 } 83 } 84 85 void push( cleanup_func_t && func, void* val ) { 86 cleanups.emplace( std::move(func), val ); 87 } 88 89 private: 90 struct cleanup_t { 91 cleanup_func_t func; 92 void * val; 93 94 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {} 58 95 }; 59 96 60 // Implementation of the guard value 61 // Created inside the visit scope 62 class guard_value { 63 public: 64 /// Push onto the cleanup 65 guard_value( at_cleanup_t * at_cleanup ) { 66 if( at_cleanup ) { 67 *at_cleanup = [this]( cleanup_func_t && func, void* val ) { 68 push( std::move( func ), val ); 69 }; 97 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups; 98 }; 99 100 // Guard structure implementation for whether or not children should be visited 101 class visit_children_guard { 102 public: 103 104 visit_children_guard( bool_ref * ref ) 105 : m_val ( true ) 106 , m_prev( ref ? ref->set( &m_val ) : nullptr ) 107 , m_ref ( ref ) 108 {} 109 110 ~visit_children_guard() { 111 if( m_ref ) { 112 m_ref->set( m_prev ); 113 } 114 } 115 116 operator bool() { return m_val; } 117 118 private: 119 bool m_val; 120 bool * m_prev; 121 bool_ref * m_ref; 122 }; 123 124 /// "Short hand" to check if this is a valid previsit function 125 /// Mostly used to make the static_assert look (and print) prettier 126 template<typename core_t, typename node_t> 127 struct is_valid_previsit { 128 using ret_t = decltype( std::declval<core_t*>()->previsit( std::declval<const node_t *>() ) ); 129 130 static constexpr bool value = std::is_void< ret_t >::value || 131 std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value; 132 }; 133 134 /// The result is a single node. 135 template< typename node_t > 136 struct result1 { 137 bool differs = false; 138 const node_t * value = nullptr; 139 140 template< typename object_t, typename super_t, typename field_t > 141 void apply( object_t * object, field_t super_t::* field ) { 142 object->*field = value; 143 } 144 }; 145 146 /// The result is a container of statements. 147 template< template<class...> class container_t > 148 struct resultNstmt { 149 /// The delta/change on a single node. 150 struct delta { 151 ptr<Stmt> new_val; 152 ssize_t old_idx; 153 bool is_old; 154 155 delta(const Stmt * s, ssize_t i, bool old) : 156 new_val(s), old_idx(i), is_old(old) {} 157 }; 158 159 bool differs = false; 160 container_t< delta > values; 161 162 template< typename object_t, typename super_t, typename field_t > 163 void apply( object_t * object, field_t super_t::* field ) { 164 field_t & container = object->*field; 165 __pedantic_pass_assert( container.size() <= values.size() ); 166 167 auto cit = enumerate(container).begin(); 168 169 container_t<ptr<Stmt>> nvals; 170 for ( delta & d : values ) { 171 if ( d.is_old ) { 172 __pedantic_pass_assert( cit.idx <= d.old_idx ); 173 std::advance( cit, d.old_idx - cit.idx ); 174 nvals.push_back( std::move( (*cit).val ) ); 175 } else { 176 nvals.push_back( std::move( d.new_val ) ); 70 177 } 71 178 } 72 179 73 ~guard_value() { 74 while( !cleanups.empty() ) { 75 auto& cleanup = cleanups.top(); 76 cleanup.func( cleanup.val ); 77 cleanups.pop(); 78 } 79 } 80 81 void push( cleanup_func_t && func, void* val ) { 82 cleanups.emplace( std::move(func), val ); 83 } 84 85 private: 86 struct cleanup_t { 87 cleanup_func_t func; 88 void * val; 89 90 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {} 91 }; 92 93 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups; 94 }; 95 96 // Guard structure implementation for whether or not children should be visited 97 class visit_children_guard { 98 public: 99 100 visit_children_guard( bool_ref * ref ) 101 : m_val ( true ) 102 , m_prev( ref ? ref->set( &m_val ) : nullptr ) 103 , m_ref ( ref ) 104 {} 105 106 ~visit_children_guard() { 107 if( m_ref ) { 108 m_ref->set( m_prev ); 109 } 110 } 111 112 operator bool() { return m_val; } 113 114 private: 115 bool m_val; 116 bool * m_prev; 117 bool_ref * m_ref; 118 }; 119 120 /// "Short hand" to check if this is a valid previsit function 121 /// Mostly used to make the static_assert look (and print) prettier 180 container = std::move(nvals); 181 } 182 183 template< template<class...> class incontainer_t > 184 void take_all( incontainer_t<ptr<Stmt>> * stmts ) { 185 if ( !stmts || stmts->empty() ) return; 186 187 std::transform( stmts->begin(), stmts->end(), std::back_inserter( values ), 188 [](ast::ptr<ast::Stmt>& stmt) -> delta { 189 return delta( stmt.release(), -1, false ); 190 }); 191 stmts->clear(); 192 differs = true; 193 } 194 195 template< template<class...> class incontainer_t > 196 void take_all( incontainer_t<ptr<Decl>> * decls ) { 197 if ( !decls || decls->empty() ) return; 198 199 std::transform( decls->begin(), decls->end(), std::back_inserter( values ), 200 [](ast::ptr<ast::Decl>& decl) -> delta { 201 ast::Decl const * d = decl.release(); 202 return delta( new DeclStmt( d->location, d ), -1, false ); 203 }); 204 decls->clear(); 205 differs = true; 206 } 207 }; 208 209 /// The result is a container of nodes. 210 template< template<class...> class container_t, typename node_t > 211 struct resultN { 212 bool differs = false; 213 container_t<ptr<node_t>> values; 214 215 template< typename object_t, typename super_t, typename field_t > 216 void apply( object_t * object, field_t super_t::* field ) { 217 field_t & container = object->*field; 218 __pedantic_pass_assert( container.size() == values.size() ); 219 220 for ( size_t i = 0; i < container.size(); ++i ) { 221 // Take all the elements that are different in 'values' 222 // and swap them into 'container' 223 if ( values[i] != nullptr ) swap(container[i], values[i]); 224 } 225 // Now the original containers should still have the unchanged values 226 // but also contain the new values. 227 } 228 }; 229 230 /// Used by previsit implementation 231 /// We need to reassign the result to 'node', unless the function 232 /// returns void, then we just leave 'node' unchanged 233 template<bool is_void> 234 struct __assign; 235 236 template<> 237 struct __assign<true> { 122 238 template<typename core_t, typename node_t> 123 struct is_valid_previsit { 124 using ret_t = decltype( std::declval<core_t*>()->previsit( std::declval<const node_t *>() ) ); 125 126 static constexpr bool value = std::is_void< ret_t >::value || 127 std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value; 128 }; 129 130 /// The result is a single node. 131 template< typename node_t > 132 struct result1 { 133 bool differs = false; 134 const node_t * value = nullptr; 135 136 template< typename object_t, typename super_t, typename field_t > 137 void apply( object_t *, field_t super_t::* field ); 138 }; 139 140 /// The result is a container of statements. 141 template< template<class...> class container_t > 142 struct resultNstmt { 143 /// The delta/change on a single node. 144 struct delta { 145 ptr<Stmt> new_val; 146 ssize_t old_idx; 147 bool is_old; 148 149 delta(const Stmt * s, ssize_t i, bool old) : 150 new_val(s), old_idx(i), is_old(old) {} 151 }; 152 153 bool differs = false; 154 container_t< delta > values; 155 156 template< typename object_t, typename super_t, typename field_t > 157 void apply( object_t *, field_t super_t::* field ); 158 159 template< template<class...> class incontainer_t > 160 void take_all( incontainer_t<ptr<Stmt>> * stmts ); 161 162 template< template<class...> class incontainer_t > 163 void take_all( incontainer_t<ptr<Decl>> * decls ); 164 }; 165 166 /// The result is a container of nodes. 167 template< template<class...> class container_t, typename node_t > 168 struct resultN { 169 bool differs = false; 170 container_t<ptr<node_t>> values; 171 172 template< typename object_t, typename super_t, typename field_t > 173 void apply( object_t *, field_t super_t::* field ); 174 }; 175 176 /// Used by previsit implementation 177 /// We need to reassign the result to 'node', unless the function 178 /// returns void, then we just leave 'node' unchanged 179 template<bool is_void> 180 struct __assign; 181 182 template<> 183 struct __assign<true> { 184 template<typename core_t, typename node_t> 185 static inline void result( core_t & core, const node_t * & node ) { 186 core.previsit( node ); 187 } 188 }; 189 190 template<> 191 struct __assign<false> { 192 template<typename core_t, typename node_t> 193 static inline void result( core_t & core, const node_t * & node ) { 194 node = core.previsit( node ); 195 assertf(node, "Previsit must not return NULL"); 196 } 197 }; 198 199 /// Used by postvisit implementation 200 /// We need to return the result unless the function 201 /// returns void, then we just return the original node 202 template<bool is_void> 203 struct __return; 204 205 template<> 206 struct __return<true> { 207 template<typename core_t, typename node_t> 208 static inline const node_t * result( core_t & core, const node_t * & node ) { 209 core.postvisit( node ); 210 return node; 211 } 212 }; 213 214 template<> 215 struct __return<false> { 216 template<typename core_t, typename node_t> 217 static inline auto result( core_t & core, const node_t * & node ) { 218 return core.postvisit( node ); 219 } 220 }; 221 222 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 223 // Deep magic (a.k.a template meta programming) to make the templated visitor work 224 // Basically the goal is to make 2 previsit 225 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 226 // 'pass.previsit( node )' that compiles will be used for that node for that type 227 // This requires that this option only compile for passes that actually define an appropriate visit. 228 // SFINAE will make sure the compilation errors in this function don't halt the build. 229 // See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE 230 // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing. 231 // This is needed only to eliminate the need for passes to specify any kind of handlers. 232 // The second implementation only works because it has a lower priority. This is due to the bogus last parameter. 233 // The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0 234 // the first implementation takes priority in regards to overloading. 235 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 236 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call 239 static inline void result( core_t & core, const node_t * & node ) { 240 core.previsit( node ); 241 } 242 }; 243 244 template<> 245 struct __assign<false> { 237 246 template<typename core_t, typename node_t> 238 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) { 239 static_assert( 240 is_valid_previsit<core_t, node_t>::value, 241 "Previsit may not change the type of the node. It must return its paremeter or void." 242 ); 243 244 __assign< 245 std::is_void< 246 decltype( core.previsit( node ) ) 247 >::value 248 >::result( core, node ); 249 } 250 247 static inline void result( core_t & core, const node_t * & node ) { 248 node = core.previsit( node ); 249 assertf(node, "Previsit must not return NULL"); 250 } 251 }; 252 253 /// Used by postvisit implementation 254 /// We need to return the result unless the function 255 /// returns void, then we just return the original node 256 template<bool is_void> 257 struct __return; 258 259 template<> 260 struct __return<true> { 251 261 template<typename core_t, typename node_t> 252 static inline auto previsit( core_t &, const node_t *, long ) {} 253 254 // PostVisit : never mutates the passed pointer but may return a different node 262 static inline const node_t * result( core_t & core, const node_t * & node ) { 263 core.postvisit( node ); 264 return node; 265 } 266 }; 267 268 template<> 269 struct __return<false> { 255 270 template<typename core_t, typename node_t> 256 static inline auto postvisit( core_t & core, const node_t * node, int ) -> 257 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 258 { 259 return __return< 260 std::is_void< 261 decltype( core.postvisit( node ) ) 262 >::value 263 >::result( core, node ); 264 } 265 266 template<typename core_t, typename node_t> 267 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; } 268 269 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 270 // Deep magic (a.k.a template meta programming) continued 271 // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit 272 // from in order to get extra functionallity for example 273 // class ErrorChecker : WithShortCircuiting { ... }; 274 // Pass<ErrorChecker> checker; 275 // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting 276 // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched 277 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 278 // For several accessories, the feature is enabled by detecting that a specific field is present 279 // Use a macro the encapsulate the logic of detecting a particular field 280 // The type is not strictly enforced but does match the accessory 281 #define FIELD_PTR( name, default_type ) \ 282 template< typename core_t > \ 283 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \ 271 static inline auto result( core_t & core, const node_t * & node ) { 272 return core.postvisit( node ); 273 } 274 }; 275 276 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 277 // Deep magic (a.k.a template meta programming) to make the templated visitor work 278 // Basically the goal is to make 2 previsit 279 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 280 // 'pass.previsit( node )' that compiles will be used for that node for that type 281 // This requires that this option only compile for passes that actually define an appropriate visit. 282 // SFINAE will make sure the compilation errors in this function don't halt the build. 283 // See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE 284 // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing. 285 // This is needed only to eliminate the need for passes to specify any kind of handlers. 286 // The second implementation only works because it has a lower priority. This is due to the bogus last parameter. 287 // The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0 288 // the first implementation takes priority in regards to overloading. 289 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 290 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call 291 template<typename core_t, typename node_t> 292 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) { 293 static_assert( 294 is_valid_previsit<core_t, node_t>::value, 295 "Previsit may not change the type of the node. It must return its paremeter or void." 296 ); 297 298 __assign< 299 std::is_void< 300 decltype( core.previsit( node ) ) 301 >::value 302 >::result( core, node ); 303 } 304 305 template<typename core_t, typename node_t> 306 static inline auto previsit( core_t &, const node_t *, long ) {} 307 308 // PostVisit : never mutates the passed pointer but may return a different node 309 template<typename core_t, typename node_t> 310 static inline auto postvisit( core_t & core, const node_t * node, int ) -> 311 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 312 { 313 return __return< 314 std::is_void< 315 decltype( core.postvisit( node ) ) 316 >::value 317 >::result( core, node ); 318 } 319 320 template<typename core_t, typename node_t> 321 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; } 322 323 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 324 // Deep magic (a.k.a template meta programming) continued 325 // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit 326 // from in order to get extra functionallity for example 327 // class ErrorChecker : WithShortCircuiting { ... }; 328 // Pass<ErrorChecker> checker; 329 // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting 330 // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched 331 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 332 // For several accessories, the feature is enabled by detecting that a specific field is present 333 // Use a macro the encapsulate the logic of detecting a particular field 334 // The type is not strictly enforced but does match the accessory 335 #define FIELD_PTR( name, default_type ) \ 336 template< typename core_t > \ 337 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \ 338 \ 339 template< typename core_t > \ 340 static inline default_type * name( core_t &, long ) { return nullptr; } 341 342 // List of fields and their expected types 343 FIELD_PTR( typeSubs, const ast::TypeSubstitution * ) 344 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > ) 345 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > ) 346 FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > ) 347 FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > ) 348 FIELD_PTR( visit_children, __pass::bool_ref ) 349 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 350 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 351 352 // Remove the macro to make sure we don't clash 353 #undef FIELD_PTR 354 355 template< typename core_t > 356 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 357 // Stats::Heap::stacktrace_push(core_t::traceId); 358 } 359 360 template< typename core_t > 361 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 362 // Stats::Heap::stacktrace_pop(); 363 } 364 365 template< typename core_t > 366 static void beginTrace(core_t &, long) {} 367 368 template< typename core_t > 369 static void endTrace(core_t &, long) {} 370 371 // Allows visitor to handle an error on top-level declarations, and possibly suppress the error. 372 // If on_error() returns false, the error will be ignored. By default, it returns true. 373 374 template< typename core_t > 375 static bool on_error (core_t &, ptr<Decl> &, long) { return true; } 376 377 template< typename core_t > 378 static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) { 379 return core.on_error(decl); 380 } 381 382 template< typename core_t, typename node_t > 383 static auto make_location_guard( core_t & core, node_t * node, int ) 384 -> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) { 385 ValueGuardPtr<const CodeLocation *> guard( &core.location ); 386 core.location = &node->location; 387 return guard; 388 } 389 390 template< typename core_t, typename node_t > 391 static auto make_location_guard( core_t &, node_t *, long ) -> int { 392 return 0; 393 } 394 395 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement. 396 // All passes which have such functions are assumed desire this behaviour 397 // detect it using the same strategy 398 namespace scope { 399 template<typename core_t> 400 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) { 401 core.beginScope(); 402 } 403 404 template<typename core_t> 405 static inline void enter( core_t &, long ) {} 406 407 template<typename core_t> 408 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) { 409 core.endScope(); 410 } 411 412 template<typename core_t> 413 static inline void leave( core_t &, long ) {} 414 } // namespace scope 415 416 // Certain passes desire an up to date symbol table automatically 417 // detect the presence of a member name `symtab` and call all the members appropriately 418 namespace symtab { 419 // Some simple scoping rules 420 template<typename core_t> 421 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) { 422 core.symtab.enterScope(); 423 } 424 425 template<typename core_t> 426 static inline auto enter( core_t &, long ) {} 427 428 template<typename core_t> 429 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) { 430 core.symtab.leaveScope(); 431 } 432 433 template<typename core_t> 434 static inline auto leave( core_t &, long ) {} 435 436 // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments 437 // Create macro to condense these common patterns 438 #define SYMTAB_FUNC1( func, type ) \ 439 template<typename core_t> \ 440 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\ 441 core.symtab.func( arg ); \ 442 } \ 284 443 \ 285 template< typename core_t > \ 286 static inline default_type * name( core_t &, long ) { return nullptr; } 287 288 // List of fields and their expected types 289 FIELD_PTR( typeSubs, const ast::TypeSubstitution * ) 290 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > ) 291 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > ) 292 FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > ) 293 FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > ) 294 FIELD_PTR( visit_children, __pass::bool_ref ) 295 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 296 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 297 298 // Remove the macro to make sure we don't clash 299 #undef FIELD_PTR 300 301 template< typename core_t > 302 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 303 // Stats::Heap::stacktrace_push(core_t::traceId); 304 } 305 306 template< typename core_t > 307 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 308 // Stats::Heap::stacktrace_pop(); 309 } 310 311 template< typename core_t > 312 static void beginTrace(core_t &, long) {} 313 314 template< typename core_t > 315 static void endTrace(core_t &, long) {} 316 317 // Allows visitor to handle an error on top-level declarations, and possibly suppress the error. 318 // If onError() returns false, the error will be ignored. By default, it returns true. 319 320 template< typename core_t > 321 static bool on_error (core_t &, ptr<Decl> &, long) { return true; } 322 323 template< typename core_t > 324 static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) { 325 return core.on_error(decl); 326 } 327 328 template< typename core_t, typename node_t > 329 static auto make_location_guard( core_t & core, node_t * node, int ) 330 -> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) { 331 ValueGuardPtr<const CodeLocation *> guard( &core.location ); 332 core.location = &node->location; 333 return guard; 334 } 335 336 template< typename core_t, typename node_t > 337 static auto make_location_guard( core_t &, node_t *, long ) -> int { 338 return 0; 339 } 340 341 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement. 342 // All passes which have such functions are assumed desire this behaviour 343 // detect it using the same strategy 344 namespace scope { 345 template<typename core_t> 346 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) { 347 core.beginScope(); 348 } 349 350 template<typename core_t> 351 static inline void enter( core_t &, long ) {} 352 353 template<typename core_t> 354 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) { 355 core.endScope(); 356 } 357 358 template<typename core_t> 359 static inline void leave( core_t &, long ) {} 360 } // namespace scope 361 362 // Certain passes desire an up to date symbol table automatically 363 // detect the presence of a member name `symtab` and call all the members appropriately 364 namespace symtab { 365 // Some simple scoping rules 366 template<typename core_t> 367 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) { 368 core.symtab.enterScope(); 369 } 370 371 template<typename core_t> 372 static inline auto enter( core_t &, long ) {} 373 374 template<typename core_t> 375 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) { 376 core.symtab.leaveScope(); 377 } 378 379 template<typename core_t> 380 static inline auto leave( core_t &, long ) {} 381 382 // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments 383 // Create macro to condense these common patterns 384 #define SYMTAB_FUNC1( func, type ) \ 385 template<typename core_t> \ 386 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\ 387 core.symtab.func( arg ); \ 388 } \ 389 \ 390 template<typename core_t> \ 391 static inline void func( core_t &, long, type ) {} 392 393 #define SYMTAB_FUNC2( func, type1, type2 ) \ 394 template<typename core_t> \ 395 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\ 396 core.symtab.func( arg1, arg2 ); \ 397 } \ 398 \ 399 template<typename core_t> \ 400 static inline void func( core_t &, long, type1, type2 ) {} 401 402 SYMTAB_FUNC1( addId , const DeclWithType * ); 403 SYMTAB_FUNC1( addType , const NamedTypeDecl * ); 404 SYMTAB_FUNC1( addStruct , const StructDecl * ); 405 SYMTAB_FUNC1( addEnum , const EnumDecl * ); 406 SYMTAB_FUNC1( addUnion , const UnionDecl * ); 407 SYMTAB_FUNC1( addTrait , const TraitDecl * ); 408 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Decl * ); 409 410 // A few extra functions have more complicated behaviour, they are hand written 411 template<typename core_t> 412 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) { 413 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name ); 414 for ( const auto & param : decl->params ) { 415 fwd->params.push_back( deepCopy( param.get() ) ); 416 } 417 core.symtab.addStruct( fwd ); 418 } 419 420 template<typename core_t> 421 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {} 422 423 template<typename core_t> 424 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) { 425 ast::UnionDecl * fwd = new ast::UnionDecl( decl->location, decl->name ); 426 for ( const auto & param : decl->params ) { 427 fwd->params.push_back( deepCopy( param.get() ) ); 428 } 429 core.symtab.addUnion( fwd ); 430 } 431 432 template<typename core_t> 433 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {} 434 435 template<typename core_t> 436 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) { 437 if ( ! core.symtab.lookupStruct( str ) ) { 438 core.symtab.addStruct( str ); 439 } 440 } 441 442 template<typename core_t> 443 static inline void addStruct( core_t &, long, const std::string & ) {} 444 445 template<typename core_t> 446 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) { 447 if ( ! core.symtab.lookupUnion( str ) ) { 448 core.symtab.addUnion( str ); 449 } 450 } 451 452 template<typename core_t> 453 static inline void addUnion( core_t &, long, const std::string & ) {} 454 455 #undef SYMTAB_FUNC1 456 #undef SYMTAB_FUNC2 457 } // namespace symtab 458 459 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 460 // Detect the presence of a member name `subs` and call all members appropriately 461 namespace forall { 462 // Some simple scoping rules 463 template<typename core_t> 464 static inline auto enter( core_t & core, int, const ast::FunctionType * type ) 465 -> decltype( core.subs, void() ) { 466 if ( ! type->forall.empty() ) core.subs.beginScope(); 467 } 468 469 template<typename core_t> 470 static inline auto enter( core_t &, long, const ast::FunctionType * ) {} 471 472 template<typename core_t> 473 static inline auto leave( core_t & core, int, const ast::FunctionType * type ) 474 -> decltype( core.subs, void() ) { 475 if ( ! type->forall.empty() ) { core.subs.endScope(); } 476 } 477 478 template<typename core_t> 479 static inline auto leave( core_t &, long, const ast::FunctionType * ) {} 480 481 // Replaces a TypeInstType's base TypeDecl according to the table 482 template<typename core_t> 483 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst ) 484 -> decltype( core.subs, void() ) { 485 inst = ast::mutate_field( 486 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) ); 487 } 488 489 template<typename core_t> 490 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {} 491 492 } // namespace forall 493 494 // For passes that need access to the global context. Sreaches `translationUnit` 495 namespace translation_unit { 496 template<typename core_t> 497 static inline auto get_cptr( core_t & core, int ) 498 -> decltype( &core.translationUnit ) { 499 return &core.translationUnit; 500 } 501 502 template<typename core_t> 503 static inline const TranslationUnit ** get_cptr( core_t &, long ) { 504 return nullptr; 505 } 506 } 507 508 template<typename core_t> 509 static inline auto get_result( core_t & core, char ) -> decltype( core.result() ) { 444 template<typename core_t> \ 445 static inline void func( core_t &, long, type ) {} 446 447 #define SYMTAB_FUNC2( func, type1, type2 ) \ 448 template<typename core_t> \ 449 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\ 450 core.symtab.func( arg1, arg2 ); \ 451 } \ 452 \ 453 template<typename core_t> \ 454 static inline void func( core_t &, long, type1, type2 ) {} 455 456 SYMTAB_FUNC1( addId , const DeclWithType * ); 457 SYMTAB_FUNC1( addType , const NamedTypeDecl * ); 458 SYMTAB_FUNC1( addStruct , const StructDecl * ); 459 SYMTAB_FUNC1( addEnum , const EnumDecl * ); 460 SYMTAB_FUNC1( addUnion , const UnionDecl * ); 461 SYMTAB_FUNC1( addTrait , const TraitDecl * ); 462 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Decl * ); 463 464 // A few extra functions have more complicated behaviour, they are hand written 465 template<typename core_t> 466 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) { 467 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name ); 468 for ( const auto & param : decl->params ) { 469 fwd->params.push_back( deepCopy( param.get() ) ); 470 } 471 core.symtab.addStruct( fwd ); 472 } 473 474 template<typename core_t> 475 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {} 476 477 template<typename core_t> 478 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) { 479 ast::UnionDecl * fwd = new ast::UnionDecl( decl->location, decl->name ); 480 for ( const auto & param : decl->params ) { 481 fwd->params.push_back( deepCopy( param.get() ) ); 482 } 483 core.symtab.addUnion( fwd ); 484 } 485 486 template<typename core_t> 487 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {} 488 489 template<typename core_t> 490 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) { 491 if ( ! core.symtab.lookupStruct( str ) ) { 492 core.symtab.addStruct( str ); 493 } 494 } 495 496 template<typename core_t> 497 static inline void addStruct( core_t &, long, const std::string & ) {} 498 499 template<typename core_t> 500 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) { 501 if ( ! core.symtab.lookupUnion( str ) ) { 502 core.symtab.addUnion( str ); 503 } 504 } 505 506 template<typename core_t> 507 static inline void addUnion( core_t &, long, const std::string & ) {} 508 509 #undef SYMTAB_FUNC1 510 #undef SYMTAB_FUNC2 511 } // namespace symtab 512 513 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 514 // Detect the presence of a member name `subs` and call all members appropriately 515 namespace forall { 516 // Some simple scoping rules 517 template<typename core_t> 518 static inline auto enter( core_t & core, int, const ast::FunctionType * type ) 519 -> decltype( core.subs, void() ) { 520 if ( ! type->forall.empty() ) core.subs.beginScope(); 521 } 522 523 template<typename core_t> 524 static inline auto enter( core_t &, long, const ast::FunctionType * ) {} 525 526 template<typename core_t> 527 static inline auto leave( core_t & core, int, const ast::FunctionType * type ) 528 -> decltype( core.subs, void() ) { 529 if ( ! type->forall.empty() ) { core.subs.endScope(); } 530 } 531 532 template<typename core_t> 533 static inline auto leave( core_t &, long, const ast::FunctionType * ) {} 534 535 // Replaces a TypeInstType's base TypeDecl according to the table 536 template<typename core_t> 537 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst ) 538 -> decltype( core.subs, void() ) { 539 inst = ast::mutate_field( 540 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) ); 541 } 542 543 template<typename core_t> 544 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {} 545 } // namespace forall 546 547 // For passes that need access to the global context. Searches `translationUnit` 548 namespace translation_unit { 549 template<typename core_t> 550 static inline auto get_cptr( core_t & core, int ) 551 -> decltype( &core.translationUnit ) { 552 return &core.translationUnit; 553 } 554 555 template<typename core_t> 556 static inline const TranslationUnit ** get_cptr( core_t &, long ) { 557 return nullptr; 558 } 559 } 560 561 // For passes, usually utility passes, that have a result. 562 namespace result { 563 template<typename core_t> 564 static inline auto get( core_t & core, char ) -> decltype( core.result() ) { 510 565 return core.result(); 511 566 } 512 567 513 568 template<typename core_t> 514 static inline auto get _result( core_t & core, int ) -> decltype( core.result ) {569 static inline auto get( core_t & core, int ) -> decltype( core.result ) { 515 570 return core.result; 516 571 } 517 572 518 573 template<typename core_t> 519 static inline void get_result( core_t &, long ) {} 520 } // namespace __pass 521 } // namespace ast 574 static inline void get( core_t &, long ) {} 575 } 576 577 } // namespace ast::__pass 578 579 #undef __pedantic_pass_assertf 580 #undef __pedantic_pass_assert -
src/AST/Print.cpp
r34b4268 r24d6572 16 16 #include "Print.hpp" 17 17 18 #include "Attribute.hpp" 18 19 #include "Decl.hpp" 19 20 #include "Expr.hpp" 21 #include "Init.hpp" 20 22 #include "Stmt.hpp" 21 23 #include "Type.hpp" 22 24 #include "TypeSubstitution.hpp" 23 25 #include "CompilationState.h" 24 25 #include "Common/utility.h" // for group_iterate 26 #include "Common/Iterate.hpp" 26 27 27 28 using namespace std; … … 29 30 namespace ast { 30 31 31 template <typename C, typename... T> 32 constexpr array<C,sizeof...(T)> make_array(T&&... values) 33 { 34 return array<C,sizeof...(T)>{ 35 std::forward<T>(values)... 36 }; 32 namespace { 33 34 template<typename C, typename... T> 35 constexpr array<C, sizeof...(T)> make_array( T&&... values ) { 36 return array<C, sizeof...(T)>{ std::forward<T>( values )... }; 37 } 38 39 namespace Names { 40 static constexpr auto FuncSpecifiers = make_array<const char*>( 41 "inline", "_Noreturn", "fortran" 42 ); 43 44 static constexpr auto StorageClasses = make_array<const char*>( 45 "extern", "static", "auto", "register", "__thread", "_Thread_local" 46 ); 47 48 static constexpr auto Qualifiers = make_array<const char*>( 49 "const", "restrict", "volatile", "mutex", "_Atomic" 50 ); 51 } 52 53 template<typename bits_t, size_t N> 54 void print( ostream & os, const bits_t & bits, 55 const array<const char *, N> & names ) { 56 if ( !bits.any() ) return; 57 for ( size_t i = 0 ; i < N ; i += 1 ) { 58 if ( bits[i] ) { 59 os << names[i] << ' '; 60 } 61 } 37 62 } 38 63 … … 80 105 static const char* Names[]; 81 106 82 struct Names {83 static constexpr auto FuncSpecifiers = make_array<const char*>(84 "inline", "_Noreturn", "fortran"85 );86 87 static constexpr auto StorageClasses = make_array<const char*>(88 "extern", "static", "auto", "register", "__thread", "_Thread_local"89 );90 91 static constexpr auto Qualifiers = make_array<const char*>(92 "const", "restrict", "volatile", "mutex", "_Atomic"93 );94 };95 96 template<typename storage_t, size_t N>97 void print(const storage_t & storage, const array<const char *, N> & Names ) {98 if ( storage.any() ) {99 for ( size_t i = 0; i < Names.size(); i += 1 ) {100 if ( storage[i] ) {101 os << Names[i] << ' ';102 }103 }104 }105 }106 107 void print( const ast::Function::Specs & specs ) {108 print(specs, Names::FuncSpecifiers);109 }110 111 void print( const ast::Storage::Classes & storage ) {112 print(storage, Names::StorageClasses);113 }114 115 void print( const ast::CV::Qualifiers & qualifiers ) {116 print(qualifiers, Names::Qualifiers);117 }118 119 107 void print( const std::vector<ast::Label> & labels ) { 120 108 if ( labels.empty() ) return; … … 221 209 } 222 210 211 void print( const ast::WaitStmt * node ) { 212 if ( node->timeout_time ) { 213 os << indent-1 << "timeout of:" << endl; 214 node->timeout_time->accept( *this ); 215 216 if ( node->timeout_stmt ) { 217 os << indent-1 << "... with statment:" << endl; 218 node->timeout_stmt->accept( *this ); 219 } 220 221 if ( node->timeout_cond ) { 222 os << indent-1 << "... with condition:" << endl; 223 node->timeout_cond->accept( *this ); 224 } 225 } 226 227 if ( node->else_stmt ) { 228 os << indent-1 << "else:" << endl; 229 node->else_stmt->accept( *this ); 230 231 if ( node->else_cond ) { 232 os << indent-1 << "... with condition:" << endl; 233 node->else_cond->accept( *this ); 234 } 235 } 236 } 237 223 238 void preprint( const ast::NamedTypeDecl * node ) { 224 239 if ( ! node->name.empty() ) { … … 230 245 } 231 246 232 print(node->storage );247 ast::print( os, node->storage ); 233 248 os << node->typeString(); 234 249 … … 272 287 273 288 void preprint( const ast::Type * node ) { 274 print(node->qualifiers );289 ast::print( os, node->qualifiers ); 275 290 } 276 291 … … 278 293 print( node->forall ); 279 294 print( node->assertions ); 280 print(node->qualifiers );295 ast::print( os, node->qualifiers ); 281 296 } 282 297 283 298 void preprint( const ast::BaseInstType * node ) { 284 299 print( node->attributes ); 285 print(node->qualifiers );300 ast::print( os, node->qualifiers ); 286 301 } 287 302 … … 294 309 } 295 310 296 print(node->storage );311 ast::print( os, node->storage ); 297 312 298 313 if ( node->type ) { … … 338 353 if ( ! short_mode ) printAll( node->attributes ); 339 354 340 print( node->storage ); 341 print( node->funcSpec ); 342 343 355 ast::print( os, node->storage ); 356 ast::print( os, node->funcSpec ); 344 357 345 358 if ( node->type && node->isTypeFixed ) { … … 384 397 --indent; 385 398 } 399 } 400 401 if ( ! node->withExprs.empty() ) { 402 // Not with a clause, but the 'with clause'. 403 ++indent; 404 os << " with clause" << endl << indent; 405 printAll( node->withExprs ); 406 --indent; 386 407 } 387 408 … … 746 767 virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final { 747 768 os << "Suspend Statement"; 748 switch (node-> type) {749 750 751 769 switch (node->kind) { 770 case ast::SuspendStmt::None : os << " with implicit target"; break; 771 case ast::SuspendStmt::Generator: os << " for generator"; break; 772 case ast::SuspendStmt::Coroutine: os << " for coroutine"; break; 752 773 } 753 774 os << endl; … … 759 780 } 760 781 ++indent; 782 783 return node; 784 } 785 786 virtual const ast::WhenClause * visit( const ast::WhenClause * node ) override final { 787 os << indent-1 << "target: "; 788 safe_print( node->target ); 789 790 if ( node->stmt ) { 791 os << indent-1 << "... with statment:" << endl; 792 node->stmt->accept( *this ); 793 } 794 795 if ( node->when_cond ) { 796 os << indent-1 << "... with when condition:" << endl; 797 node->when_cond->accept( *this ); 798 } 761 799 762 800 return node; … … 800 838 virtual const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final { 801 839 os << indent-1 << "target function: "; 802 safe_print( node->target _func);840 safe_print( node->target ); 803 841 804 842 if ( !node->target_args.empty() ) { … … 814 852 } 815 853 816 if ( node-> cond ) {854 if ( node->when_cond ) { 817 855 os << indent-1 << "... with condition:" << endl; 818 node->cond->accept( *this ); 819 } 820 856 node->when_cond->accept( *this ); 857 } 858 859 return node; 860 } 861 862 virtual const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final { 863 os << "Waituntil Statement" << endl; 864 indent += 2; 865 for( const auto & clause : node->clauses ) { 866 clause->accept( *this ); 867 } 868 print(node); // calls print( const ast::WaitStmt * node ) 821 869 return node; 822 870 } … … 1627 1675 }; 1628 1676 1677 } // namespace 1678 1629 1679 void print( ostream & os, const ast::Node * node, Indenter indent ) { 1630 1680 Printer printer { os, indent, false }; … … 1637 1687 } 1638 1688 1639 // Annoyingly these needed to be defined out of line to avoid undefined references. 1640 // The size here needs to be explicit but at least the compiler will produce an error 1641 // if the wrong size is specified 1642 constexpr array<const char*, 3> Printer::Names::FuncSpecifiers; 1643 constexpr array<const char*, 6> Printer::Names::StorageClasses; 1644 constexpr array<const char*, 5> Printer::Names::Qualifiers; 1689 void print( ostream & os, Function::Specs specs ) { 1690 print( os, specs, Names::FuncSpecifiers ); 1645 1691 } 1692 1693 void print( ostream & os, Storage::Classes storage ) { 1694 print( os, storage, Names::StorageClasses ); 1695 } 1696 1697 void print( ostream & os, CV::Qualifiers qualifiers ) { 1698 print( os, qualifiers, Names::Qualifiers ); 1699 } 1700 1701 } // namespace ast -
src/AST/Print.hpp
r34b4268 r24d6572 16 16 #pragma once 17 17 18 #include <iostream> 19 #include <utility> // for forward 18 #include <iosfwd> 20 19 21 #include "AST/ Node.hpp"20 #include "AST/Fwd.hpp" 22 21 #include "Common/Indenter.h" 23 22 24 23 namespace ast { 25 26 class Decl;27 24 28 25 /// Print a node with the given indenter … … 44 41 } 45 42 43 /// Print each cv-qualifier used in the set, followed by a space. 44 void print( std::ostream & os, CV::Qualifiers ); 45 /// Print each function specifier used in the set, followed by a space. 46 void print( std::ostream & os, Function::Specs ); 47 /// Print each storage class used in the set, followed by a space. 48 void print( std::ostream & os, Storage::Classes ); 49 46 50 } -
src/AST/Stmt.hpp
r34b4268 r24d6572 10 10 // Created On : Wed May 8 13:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Apr 20 14:34:00 202213 // Update Count : 3 612 // Last Modified On : Wed Apr 5 10:34:00 2023 13 // Update Count : 37 14 14 // 15 15 … … 205 205 }; 206 206 207 // A while loop or a do-while loop: 208 enum WhileDoKind { While, DoWhile }; 209 207 210 // While loop: while (...) ... else ... or do ... while (...) else ...; 208 211 class WhileDoStmt final : public Stmt { … … 212 215 ptr<Stmt> else_; 213 216 std::vector<ptr<Stmt>> inits; 214 boolisDoWhile;217 WhileDoKind isDoWhile; 215 218 216 219 WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, 217 const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )220 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} ) 218 221 : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(nullptr), inits(std::move(inits)), isDoWhile(isDoWhile) {} 219 222 220 223 WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, const Stmt * else_, 221 const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )224 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} ) 222 225 : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(else_), inits(std::move(inits)), isDoWhile(isDoWhile) {} 223 226 … … 364 367 public: 365 368 ptr<CompoundStmt> then; 366 enum Type { None, Coroutine, Generator } type= None;367 368 SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, const std::vector<Label> && labels = {} )369 : Stmt(loc, std::move(labels)), then(then), type(type) {}369 enum Kind { None, Coroutine, Generator } kind = None; 370 371 SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Kind kind, const std::vector<Label> && labels = {} ) 372 : Stmt(loc, std::move(labels)), then(then), kind(kind) {} 370 373 371 374 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } … … 375 378 }; 376 379 377 // Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ...378 class WaitForStmt final : public Stmt { 379 public: 380 std::vector<ptr<WaitForClause>> clauses; 381 380 // Base class of WaitFor/WaitUntil statements 381 // form: KEYWORD(...) ... timeout(...) ... else ... 382 class WaitStmt : public Stmt { 383 public: 384 ptr<Expr> timeout_time; 382 385 ptr<Stmt> timeout_stmt; 383 386 ptr<Expr> timeout_cond; … … 385 388 ptr<Expr> else_cond; 386 389 390 WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} ) 391 : Stmt(loc, std::move(labels)) {} 392 393 private: 394 WaitStmt * clone() const override = 0; 395 MUTATE_FRIEND 396 }; 397 398 // Base class for WaitFor/WaitUntil clauses 399 // form: when( when_cond ) KEYWORD( target ) stmt 400 class WhenClause : public StmtClause { 401 public: 402 ptr<Expr> target; 403 ptr<Stmt> stmt; 404 ptr<Expr> when_cond; 405 406 WhenClause( const CodeLocation & loc ) 407 : StmtClause( loc ) {} 408 409 const WhenClause * accept( Visitor & v ) const override { return v.visit( this ); } 410 private: 411 WhenClause * clone() const override { return new WhenClause{ *this }; } 412 MUTATE_FRIEND 413 }; 414 415 // Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ... 416 class WaitForStmt final : public WaitStmt { 417 public: 418 std::vector<ptr<WaitForClause>> clauses; 419 387 420 WaitForStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} ) 388 : Stmt(loc, std::move(labels)) {}421 : WaitStmt(loc, std::move(labels)) {} 389 422 390 423 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } … … 394 427 }; 395 428 396 class WaitForClause final : public StmtClause { 397 public: 398 ptr<Expr> target_func; 429 // Clause in a waitfor statement: waitfor (..., ...) ... 430 class WaitForClause final : public WhenClause { 431 public: 399 432 std::vector<ptr<Expr>> target_args; 400 ptr<Stmt> stmt;401 ptr<Expr> cond;402 433 403 434 WaitForClause( const CodeLocation & loc ) 404 : StmtClause( loc ) {}435 : WhenClause( loc ) {} 405 436 406 437 const WaitForClause * accept( Visitor & v ) const override { return v.visit( this ); } 407 438 private: 408 439 WaitForClause * clone() const override { return new WaitForClause{ *this }; } 440 MUTATE_FRIEND 441 }; 442 443 // waituntil statement: when (...) waituntil (...) ... timeout(...) ... else ... 444 class WaitUntilStmt final : public WaitStmt { 445 public: 446 // Non-ast node used during compilation to store data needed to generate predicates 447 // and set initial status values for clauses 448 // Used to create a tree corresponding to the structure of the clauses in a WaitUntil 449 struct ClauseNode { 450 enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag 451 // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing 452 453 ClauseNode * left; 454 ClauseNode * right; 455 WhenClause * leaf; // only set if this node is a leaf (points into vector of clauses) 456 457 bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses 458 bool whenState; // used to track if when_cond is toggled on or off for generating init values 459 bool childOfAnd; // true on leaf nodes that are children of AND, false otherwise 460 461 ClauseNode( Op op, ClauseNode * left, ClauseNode * right ) 462 : op(op), left(left), right(right), leaf(nullptr), 463 ambiguousWhen(false), whenState(true), childOfAnd(false) {} 464 ClauseNode( Op op, WhenClause * leaf ) 465 : op(op), left(nullptr), right(nullptr), leaf(leaf), 466 ambiguousWhen(false), whenState(true), childOfAnd(false) {} 467 ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {} 468 469 ~ClauseNode() { 470 if ( left ) delete left; 471 if ( right ) delete right; 472 } 473 }; 474 475 std::vector<ptr<WhenClause>> clauses; 476 ClauseNode * predicateTree; 477 478 WaitUntilStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} ) 479 : WaitStmt(loc, std::move(labels)) {} 480 481 ~WaitUntilStmt() { delete predicateTree; } 482 483 const Stmt * accept( Visitor & v ) const override { return v.visit( this ); } 484 private: 485 WaitUntilStmt * clone() const override { return new WaitUntilStmt{ *this }; } 409 486 MUTATE_FRIEND 410 487 }; … … 454 531 MUTATE_FRIEND 455 532 }; 533 456 534 } // namespace ast 457 535 -
src/AST/SymbolTable.cpp
r34b4268 r24d6572 18 18 #include <cassert> 19 19 20 #include "Copy.hpp" 21 #include <iostream> 22 #include <algorithm> 23 20 24 #include "Decl.hpp" 21 25 #include "Expr.hpp" 22 26 #include "Inspect.hpp" 23 27 #include "Type.hpp" 24 #include "CodeGen/OperatorTable.h" // for isCtorDtorAssign28 #include "CodeGen/OperatorTable.h" // for isCtorDtorAssign 25 29 #include "Common/SemanticError.h" 26 30 #include "Common/Stats/Counter.h" … … 28 32 #include "InitTweak/InitTweak.h" 29 33 #include "ResolvExpr/Cost.h" 30 #include "ResolvExpr/typeops.h" 34 #include "ResolvExpr/CandidateFinder.hpp" // for referenceToRvalueConversion 35 #include "ResolvExpr/Unify.h" 31 36 #include "SymTab/Mangler.h" 32 37 … … 69 74 if ( baseExpr ) { 70 75 if (baseExpr->env) { 71 Expr * base = shallowCopy(baseExpr);76 Expr * base = deepCopy(baseExpr); 72 77 const TypeSubstitution * subs = baseExpr->env; 73 78 base->env = nullptr; … … 193 198 out.push_back(decl.second); 194 199 } 200 201 // std::cerr << otypeKey << ' ' << out.size() << std::endl; 195 202 } 196 203 … … 259 266 void SymbolTable::addId( const DeclWithType * decl, const Expr * baseExpr ) { 260 267 // default handling of conflicts is to raise an error 261 addId ( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );268 addIdCommon( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr ); 262 269 } 263 270 264 271 void SymbolTable::addDeletedId( const DeclWithType * decl, const Decl * deleter ) { 265 272 // default handling of conflicts is to raise an error 266 addId ( decl, OnConflict::error(), nullptr, deleter );273 addIdCommon( decl, OnConflict::error(), nullptr, deleter ); 267 274 } 268 275 … … 276 283 } else { 277 284 // typedef redeclarations are errors only if types are different 278 if ( ! ResolvExpr::typesCompatible( existing->base, added->base , SymbolTable{}) ) {285 if ( ! ResolvExpr::typesCompatible( existing->base, added->base ) ) { 279 286 SemanticError( added->location, "redeclaration of " + added->name ); 280 287 } … … 641 648 } else if ( existing.id->linkage.is_mangled 642 649 || ResolvExpr::typesCompatible( 643 added->get_type(), existing.id->get_type() , SymbolTable{}) ) {650 added->get_type(), existing.id->get_type() ) ) { 644 651 645 652 // it is a conflict if one declaration is deleted and the other is not … … 676 683 } 677 684 678 void SymbolTable::addId (679 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,680 const Decl * deleter ) {685 void SymbolTable::addIdCommon( 686 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, 687 const Expr * baseExpr, const Decl * deleter ) { 681 688 SpecialFunctionKind kind = getSpecialFunctionKind(decl->name); 682 689 if (kind == NUMBER_OF_KINDS) { // not a special decl 683 addId (decl, decl->name, idTable, handleConflicts, baseExpr, deleter);690 addIdToTable(decl, decl->name, idTable, handleConflicts, baseExpr, deleter); 684 691 } 685 692 else { … … 694 701 assertf(false, "special decl with non-function type"); 695 702 } 696 addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter); 697 } 698 } 699 700 void SymbolTable::addId( 701 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr, 702 const Decl * deleter ) { 703 addIdToTable(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter); 704 } 705 } 706 707 void SymbolTable::addIdToTable( 708 const DeclWithType * decl, const std::string & lookupKey, 709 IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, 710 const Expr * baseExpr, const Decl * deleter ) { 703 711 ++*stats().add_calls; 704 712 const std::string &name = decl->name; … … 777 785 void SymbolTable::addMembers( 778 786 const AggregateDecl * aggr, const Expr * expr, SymbolTable::OnConflict handleConflicts ) { 779 for ( const Decl *decl : aggr->members ) {780 if ( auto dwt = dynamic_cast< const DeclWithType * >( decl ) ) {781 addId( dwt, handleConflicts, expr );782 if ( dwt->name == "" ) {783 const Type * t = dwt->get_type()->stripReferences();784 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {785 if ( ! dynamic_cast<const StructInstType *>(rty)786 && ! dynamic_cast<const UnionInstType *>(rty) ) continue;787 ResolvExpr::Cost cost = ResolvExpr::Cost::zero;788 ast::ptr<ast::TypeSubstitution> tmp = expr->env;789 expr = mutate_field(expr, &Expr::env, nullptr);790 const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );791 base = mutate_field(base, &Expr::env, tmp);792 793 addMembers(794 rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts ); 795 }796 }787 for ( const ptr<Decl> & decl : aggr->members ) { 788 auto dwt = decl.as<DeclWithType>(); 789 if ( nullptr == dwt ) continue; 790 addIdCommon( dwt, handleConflicts, expr ); 791 // Inline through unnamed struct/union members. 792 if ( "" != dwt->name ) continue; 793 const Type * t = dwt->get_type()->stripReferences(); 794 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) { 795 if ( ! dynamic_cast<const StructInstType *>(rty) 796 && ! dynamic_cast<const UnionInstType *>(rty) ) continue; 797 ResolvExpr::Cost cost = ResolvExpr::Cost::zero; 798 ast::ptr<ast::TypeSubstitution> tmp = expr->env; 799 expr = mutate_field(expr, &Expr::env, nullptr); 800 const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost ); 801 base = mutate_field(base, &Expr::env, tmp); 802 803 addMembers( 804 rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts ); 797 805 } 798 806 } -
src/AST/SymbolTable.hpp
r34b4268 r24d6572 192 192 193 193 /// common code for addId, addDeletedId, etc. 194 void addId (195 const DeclWithType * decl, OnConflict handleConflicts, const Expr * baseExpr = nullptr,196 const Decl * deleter = nullptr );194 void addIdCommon( 195 const DeclWithType * decl, OnConflict handleConflicts, 196 const Expr * baseExpr = nullptr, const Decl * deleter = nullptr ); 197 197 198 198 /// common code for addId when special decls are placed into separate tables 199 void addId( 200 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & idTable, OnConflict handleConflicts, 199 void addIdToTable( 200 const DeclWithType * decl, const std::string & lookupKey, 201 IdTable::Ptr & idTable, OnConflict handleConflicts, 201 202 const Expr * baseExpr = nullptr, const Decl * deleter = nullptr); 202 203 203 204 /// adds all of the members of the Aggregate (addWith helper) 204 205 void addMembers( const AggregateDecl * aggr, const Expr * expr, OnConflict handleConflicts ); -
src/AST/TranslationUnit.hpp
r34b4268 r24d6572 10 10 // Created On : Tue Jun 11 15:30:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue Mar 11 11:19:00 202213 // Update Count : 112 // Last Modified On : Thr Mar 9 16:41:00 2023 13 // Update Count : 2 14 14 // 15 15 … … 17 17 18 18 #include <map> 19 #include < vector>19 #include <list> 20 20 21 21 #include "Fwd.hpp" … … 28 28 29 29 ptr<Type> sizeType; 30 const FunctionDecl * dereference ;31 const StructDecl * dtorStruct ;32 const FunctionDecl * dtorDestroy ;30 const FunctionDecl * dereference = nullptr; 31 const StructDecl * dtorStruct = nullptr; 32 const FunctionDecl * dtorDestroy = nullptr; 33 33 }; 34 34 -
src/AST/Type.cpp
r34b4268 r24d6572 10 10 // Created On : Mon May 13 15:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Nov 24 9:49:00 202213 // Update Count : 612 // Last Modified On : Thu Apr 6 15:59:00 2023 13 // Update Count : 7 14 14 // 15 15 … … 199 199 200 200 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q ) 201 : Type( q ), types( std::move(ts) ), members() { 202 // This constructor is awkward. `TupleType` needs to contain objects so that members can be 203 // named, but members without initializer nodes end up getting constructors, which breaks 204 // things. This happens because the object decls have to be visited so that their types are 205 // kept in sync with the types listed here. Ultimately, the types listed here should perhaps 206 // be eliminated and replaced with a list-view over members. The temporary solution is to 207 // make a `ListInit` with `maybeConstructed = false`, so when the object is visited it is not 208 // constructed. Potential better solutions include: 209 // a) Separate `TupleType` from its declarations, into `TupleDecl` and `Tuple{Inst?}Type`, 210 // similar to the aggregate types. 211 // b) Separate initializer nodes better, e.g. add a `MaybeConstructed` node that is replaced 212 // by `genInit`, rather than the current boolean flag. 213 members.reserve( types.size() ); 214 for ( const Type * ty : types ) { 215 members.emplace_back( new ObjectDecl{ 216 CodeLocation(), "", ty, new ListInit( CodeLocation(), {}, {}, NoConstruct ), 217 Storage::Classes{}, Linkage::Cforall } ); 218 } 219 } 201 : Type( q ), types( std::move(ts) ) {} 220 202 221 203 bool isUnboundType(const Type * type) { -
src/AST/Type.hpp
r34b4268 r24d6572 10 10 // Created On : Thu May 9 10:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Nov 24 9:47:00 202213 // Update Count : 812 // Last Modified On : Thu Apr 6 15:58:00 2023 13 // Update Count : 9 14 14 // 15 15 … … 265 265 }; 266 266 267 /// Function variable arguments flag268 enum ArgumentFlag { FixedArgs, VariableArgs };269 270 267 /// Type of a function `[R1, R2](*)(P1, P2, P3)` 271 268 class FunctionType final : public Type { … … 462 459 public: 463 460 std::vector<ptr<Type>> types; 464 std::vector<ptr<Decl>> members;465 461 466 462 TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q = {} ); -
src/AST/TypeEnvironment.cpp
r34b4268 r24d6572 178 178 179 179 bool TypeEnvironment::combine( 180 const TypeEnvironment & o, OpenVarSet & open , const SymbolTable & symtab) {180 const TypeEnvironment & o, OpenVarSet & open ) { 181 181 // short-circuit easy cases 182 182 if ( o.empty() ) return true; … … 201 201 EqvClass & r = *rt; 202 202 // merge bindings 203 if ( ! mergeBound( r, c, open , symtab) ) return false;203 if ( ! mergeBound( r, c, open ) ) return false; 204 204 // merge previous unbound variables into this class, checking occurs if needed 205 205 if ( r.bound ) for ( const auto & u : c.vars ) { … … 216 216 } else if ( st != rt ) { 217 217 // bound, but not to the same class 218 if ( ! mergeClasses( rt, st, open , symtab) ) return false;218 if ( ! mergeClasses( rt, st, open ) ) return false; 219 219 } // ignore bound into the same class 220 220 } … … 280 280 bool TypeEnvironment::bindVar( 281 281 const TypeInstType * typeInst, const Type * bindTo, const TypeData & data, 282 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen, 283 const SymbolTable & symtab 282 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen 284 283 ) { 285 284 // remove references from bound type, so that type variables can only bind to value types … … 300 299 if ( unifyInexact( 301 300 newType, target, *this, need, have, open, 302 widen & WidenMode{ it->allowWidening, true }, symtab,common ) ) {301 widen & WidenMode{ it->allowWidening, true }, common ) ) { 303 302 if ( common ) { 304 303 it->bound = std::move(common); … … 321 320 const TypeInstType * var1, const TypeInstType * var2, TypeData && data, 322 321 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, 323 WidenMode widen , const SymbolTable & symtab322 WidenMode widen 324 323 ) { 325 324 auto c1 = internal_lookup( *var1 ); … … 358 357 359 358 if ( unifyInexact( 360 newType1, newType2, *this, need, have, open, newWidenMode, symtab,common ) ) {359 newType1, newType2, *this, need, have, open, newWidenMode, common ) ) { 361 360 c1->vars.insert( c2->vars.begin(), c2->vars.end() ); 362 361 c1->allowWidening = widen1 && widen2; … … 409 408 410 409 bool TypeEnvironment::mergeBound( 411 EqvClass & to, const EqvClass & from, OpenVarSet & open , const SymbolTable & symtab) {410 EqvClass & to, const EqvClass & from, OpenVarSet & open ) { 412 411 if ( from.bound ) { 413 412 if ( to.bound ) { … … 419 418 420 419 if ( unifyInexact( 421 toType, fromType, *this, need, have, open, widen, symtab,common ) ) {420 toType, fromType, *this, need, have, open, widen, common ) ) { 422 421 // unifies, set common type if necessary 423 422 if ( common ) { … … 437 436 438 437 bool TypeEnvironment::mergeClasses( 439 ClassList::iterator to, ClassList::iterator from, OpenVarSet & open , const SymbolTable & symtab438 ClassList::iterator to, ClassList::iterator from, OpenVarSet & open 440 439 ) { 441 440 EqvClass & r = *to, & s = *from; 442 441 443 442 // ensure bounds match 444 if ( ! mergeBound( r, s, open , symtab) ) return false;443 if ( ! mergeBound( r, s, open ) ) return false; 445 444 446 445 // check safely bindable -
src/AST/TypeEnvironment.hpp
r34b4268 r24d6572 63 63 64 64 int cmp = d1->var->name.compare( d2->var->name ); 65 return cmp <0 || ( cmp == 0 && d1->result < d2->result );65 return cmp > 0 || ( cmp == 0 && d1->result < d2->result ); 66 66 } 67 67 }; … … 169 169 /// Merge environment with this one, checking compatibility. 170 170 /// Returns false if fails, but does NOT roll back partial changes. 171 bool combine( const TypeEnvironment & o, OpenVarSet & openVars , const SymbolTable & symtab);171 bool combine( const TypeEnvironment & o, OpenVarSet & openVars ); 172 172 173 173 /// Add all type variables in environment to open var list … … 183 183 const TypeInstType * typeInst, const Type * bindTo, const TypeData & data, 184 184 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 185 ResolvExpr::WidenMode widen , const SymbolTable & symtab);185 ResolvExpr::WidenMode widen ); 186 186 187 187 /// Binds the type classes represented by `var1` and `var2` together; will add one or both … … 190 190 const TypeInstType * var1, const TypeInstType * var2, TypeData && data, 191 191 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 192 ResolvExpr::WidenMode widen , const SymbolTable & symtab);192 ResolvExpr::WidenMode widen ); 193 193 194 194 /// Disallows widening for all bindings in the environment … … 205 205 /// Unifies the type bound of `to` with the type bound of `from`, returning false if fails 206 206 bool mergeBound( 207 EqvClass & to, const EqvClass & from, OpenVarSet & openVars , const SymbolTable & symtab);207 EqvClass & to, const EqvClass & from, OpenVarSet & openVars ); 208 208 209 209 /// Merges two type classes from local environment, returning false if fails 210 210 bool mergeClasses( 211 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 212 const SymbolTable & symtab ); 211 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars); 213 212 214 213 /// Private lookup API; returns array index of string, or env.size() for not found -
src/AST/TypeSubstitution.cpp
r34b4268 r24d6572 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Jun 3 13:26:00 2017 13 // Update Count : 5 14 // 12 // Last Modified On : Thr May 25 11:24:00 2023 13 // Update Count : 6 14 // 15 16 #include "TypeSubstitution.hpp" 15 17 16 18 #include "Type.hpp" // for TypeInstType, Type, StructInstType, UnionInstType 17 #include " TypeSubstitution.hpp"19 #include "Pass.hpp" // for Pass, PureVisitor, WithGuards, WithVisitorRef 18 20 19 21 namespace ast { 20 21 22 // size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");23 22 24 23 TypeSubstitution::TypeSubstitution() { … … 119 118 } 120 119 120 // definitition must happen after PassVisitor is included so that WithGuards can be used 121 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter>, public PureVisitor { 122 //static size_t traceId; 123 124 Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {} 125 126 const Type * postvisit( const TypeInstType * aggregateUseType ); 127 128 /// Records type variable bindings from forall-statements 129 void previsit( const FunctionType * type ); 130 /// Records type variable bindings from forall-statements and instantiations of generic types 131 // void handleAggregateType( const BaseInstType * type ); 132 133 // void previsit( const StructInstType * aggregateUseType ); 134 // void previsit( const UnionInstType * aggregateUseType ); 135 136 const TypeSubstitution & sub; 137 int subCount = 0; 138 bool freeOnly; 139 typedef std::unordered_set< TypeEnvKey > BoundVarsType; 140 BoundVarsType boundVars; 141 }; 142 143 // size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution"); 144 121 145 void TypeSubstitution::normalize() { 122 146 Pass<Substituter> sub( *this, true ); … … 128 152 } 129 153 } while ( sub.core.subCount ); 154 } 155 156 TypeSubstitution::ApplyResult<Node> TypeSubstitution::applyBase( 157 const Node * input, bool isFree ) const { 158 assert( input ); 159 Pass<Substituter> sub( *this, isFree ); 160 const Node * output = input->accept( sub ); 161 return { output, sub.core.subCount }; 130 162 } 131 163 -
src/AST/TypeSubstitution.hpp
r34b4268 r24d6572 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : T ue Apr 30 22:52:47 201913 // Update Count : 911 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr May 25 12:31:00 2023 13 // Update Count : 10 14 14 // 15 15 … … 46 46 TypeSubstitution &operator=( const TypeSubstitution &other ); 47 47 48 template< typename SynTreeClass>48 template< typename node_t > 49 49 struct ApplyResult { 50 ast::ptr< SynTreeClass> node;50 ast::ptr<node_t> node; 51 51 int count; 52 52 }; 53 53 54 template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const; 55 template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const; 54 template< typename node_t > 55 ApplyResult<node_t> apply( const node_t * input ) const { 56 ApplyResult<Node> ret = applyBase( input, false ); 57 return { ret.node.strict_as<node_t>(), ret.count }; 58 } 56 59 57 60 template< typename node_t, enum Node::ref_type ref_t > 58 61 int apply( ptr_base< node_t, ref_t > & input ) const { 59 const node_t * p = input.get(); 60 auto ret = apply(p); 61 input = ret.node; 62 ApplyResult<Node> ret = applyBase( input.get(), false ); 63 input = ret.node.strict_as<node_t>(); 62 64 return ret.count; 65 } 66 67 template< typename node_t > 68 ApplyResult<node_t> applyFree( const node_t * input ) const { 69 ApplyResult<Node> ret = applyBase( input, true ); 70 return { ret.node.strict_as<node_t>(), ret.count }; 63 71 } 64 72 65 73 template< typename node_t, enum Node::ref_type ref_t > 66 74 int applyFree( ptr_base< node_t, ref_t > & input ) const { 67 const node_t * p = input.get(); 68 auto ret = applyFree(p); 69 input = ret.node; 75 ApplyResult<Node> ret = applyBase( input.get(), true ); 76 input = ret.node.strict_as<node_t>(); 70 77 return ret.count; 71 78 } … … 97 104 // Mutator that performs the substitution 98 105 struct Substituter; 106 ApplyResult<Node> applyBase( const Node * input, bool isFree ) const; 99 107 100 108 // TODO: worry about traversing into a forall-qualified function type or type decl with assertions … … 158 166 } // namespace ast 159 167 160 // include needs to happen after TypeSubstitution is defined so that both TypeSubstitution and161 // PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals.162 #include "Pass.hpp"163 #include "Copy.hpp"164 165 namespace ast {166 167 // definitition must happen after PassVisitor is included so that WithGuards can be used168 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter>, public PureVisitor {169 static size_t traceId;170 171 Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}172 173 const Type * postvisit( const TypeInstType * aggregateUseType );174 175 /// Records type variable bindings from forall-statements176 void previsit( const FunctionType * type );177 /// Records type variable bindings from forall-statements and instantiations of generic types178 // void handleAggregateType( const BaseInstType * type );179 180 // void previsit( const StructInstType * aggregateUseType );181 // void previsit( const UnionInstType * aggregateUseType );182 183 const TypeSubstitution & sub;184 int subCount = 0;185 bool freeOnly;186 typedef std::unordered_set< TypeEnvKey > BoundVarsType;187 BoundVarsType boundVars;188 189 };190 191 template< typename SynTreeClass >192 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const {193 assert( input );194 Pass<Substituter> sub( *this, false );195 input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );196 return { input, sub.core.subCount };197 }198 199 template< typename SynTreeClass >200 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const {201 assert( input );202 Pass<Substituter> sub( *this, true );203 input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );204 return { input, sub.core.subCount };205 }206 207 } // namespace ast208 209 168 // Local Variables: // 210 169 // tab-width: 4 // -
src/AST/Visitor.hpp
r34b4268 r24d6572 50 50 virtual const ast::FinallyClause * visit( const ast::FinallyClause * ) = 0; 51 51 virtual const ast::Stmt * visit( const ast::SuspendStmt * ) = 0; 52 virtual const ast::WhenClause * visit( const ast::WhenClause * ) = 0; 52 53 virtual const ast::Stmt * visit( const ast::WaitForStmt * ) = 0; 53 54 virtual const ast::WaitForClause * visit( const ast::WaitForClause * ) = 0; 55 virtual const ast::Stmt * visit( const ast::WaitUntilStmt * ) = 0; 54 56 virtual const ast::Decl * visit( const ast::WithStmt * ) = 0; 55 57 virtual const ast::NullStmt * visit( const ast::NullStmt * ) = 0; -
src/AST/porting.md
r34b4268 r24d6572 213 213 * `get_statement()` exclusively used for code location, replaced with `CodeLocation` field 214 214 215 `CaseStmt` 215 `CaseStmt` => `CaseClause` 216 216 * `_isDefault` has been removed 217 217 * `isDefault` calculates value from `cond` … … 227 227 * `block` -> `body` and `finallyBlock` -> `finally` 228 228 229 `ThrowStmt` `CatchStmt`229 `ThrowStmt` and `CatchStmt` => `CatchClause` 230 230 * moved `Kind` enums to shared `ast::ExceptionKind` enum 231 231 232 `FinallyStmt` 232 `FinallyStmt` => `FinallyClause` 233 233 * `block` -> `body` 234 234 … … 280 280 * Template class, with specializations and using to implement some other types: 281 281 * `StructInstType`, `UnionInstType` & `EnumInstType` 282 * `baseStruct`, `baseUnion` & `baseEnum` => `base` 282 283 283 284 `TypeInstType`
Note:
See TracChangeset
for help on using the changeset viewer.