- Timestamp:
- Apr 21, 2023, 5:36:12 PM (3 years ago)
- Branches:
- ADT, master, stuck-waitfor-destruct
- Children:
- 28f8f15, 6e4c44d
- Parents:
- 2ed94a9 (diff), 699a97d (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:
-
- 22 edited
-
Attribute.hpp (modified) (1 diff)
-
Convert.cpp (modified) (4 diffs)
-
Create.cpp (modified) (1 diff)
-
Decl.cpp (modified) (3 diffs)
-
Decl.hpp (modified) (6 diffs)
-
Expr.hpp (modified) (4 diffs)
-
Fwd.hpp (modified) (2 diffs)
-
Init.hpp (modified) (1 diff)
-
Inspect.cpp (modified) (2 diffs)
-
Inspect.hpp (modified) (2 diffs)
-
ParseNode.hpp (modified) (1 diff)
-
Pass.impl.hpp (modified) (2 diffs)
-
Pass.proto.hpp (modified) (1 diff)
-
Print.cpp (modified) (11 diffs)
-
Print.hpp (modified) (2 diffs)
-
Stmt.hpp (modified) (6 diffs)
-
SymbolTable.cpp (modified) (5 diffs)
-
SymbolTable.hpp (modified) (1 diff)
-
TranslationUnit.hpp (modified) (3 diffs)
-
Type.cpp (modified) (2 diffs)
-
Type.hpp (modified) (3 diffs)
-
porting.md (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Attribute.hpp
r2ed94a9 rb110bcc 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
r2ed94a9 rb110bcc 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; … … 1683 1683 GET_ACCEPT_V(attributes, Attribute), 1684 1684 { old->get_funcSpec().val }, 1685 old->type->isVarArgs1685 (old->type->isVarArgs) ? ast::VariableArgs : ast::FixedArgs 1686 1686 }; 1687 1687 … … 1989 1989 GET_ACCEPT_1(else_, Stmt), 1990 1990 GET_ACCEPT_V(initialization, Stmt), 1991 old->isDoWhile,1991 (old->isDoWhile) ? ast::DoWhile : ast::While, 1992 1992 GET_LABELS_V(old->labels) 1993 1993 ); … … 2131 2131 virtual void visit( const SuspendStmt * old ) override final { 2132 2132 if ( inCache( old ) ) return; 2133 ast::SuspendStmt:: Typetype;2133 ast::SuspendStmt::Kind type; 2134 2134 switch (old->type) { 2135 2135 case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break; -
src/AST/Create.cpp
r2ed94a9 rb110bcc 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
r2ed94a9 rb110bcc 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
r2ed94a9 rb110bcc 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.hpp
r2ed94a9 rb110bcc 254 254 }; 255 255 256 /// A name qualified by a namespace or type. 256 257 class QualifiedNameExpr final : public Expr { 257 258 public: … … 259 260 std::string name; 260 261 261 QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 262 QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 262 263 : Expr( loc ), type_decl( d ), name( n ) {} 263 264 … … 621 622 }; 622 623 624 /// A name that refers to a generic dimension parameter. 623 625 class DimensionExpr final : public Expr { 624 626 public: … … 910 912 }; 911 913 912 913 914 } 914 915 -
src/AST/Fwd.hpp
r2ed94a9 rb110bcc 15 15 16 16 #pragma once 17 18 template<typename> struct bitfield; 17 19 18 20 #include "AST/Node.hpp" … … 147 149 class TranslationGlobal; 148 150 151 // For the following types, only use the using type. 152 namespace CV { 153 struct qualifier_flags; 154 using Qualifiers = bitfield<qualifier_flags>; 149 155 } 156 namespace Function { 157 struct spec_flags; 158 using Specs = bitfield<spec_flags>; 159 } 160 namespace Storage { 161 struct class_flags; 162 using Classes = bitfield<class_flags>; 163 } 164 namespace Linkage { 165 struct spec_flags; 166 using Spec = bitfield<spec_flags>; 167 } 168 169 } -
src/AST/Init.hpp
r2ed94a9 rb110bcc 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
r2ed94a9 rb110bcc 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
r2ed94a9 rb110bcc 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/ParseNode.hpp
r2ed94a9 rb110bcc 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.impl.hpp
r2ed94a9 rb110bcc 22 22 #include "AST/TranslationUnit.hpp" 23 23 #include "AST/TypeSubstitution.hpp" 24 #include "Common/Iterate.hpp" 24 25 25 26 #define VISIT_START( node ) \ … … 2041 2042 if ( __visit_children() ) { 2042 2043 maybe_accept( node, &TupleType::types ); 2043 maybe_accept( node, &TupleType::members );2044 2044 } 2045 2045 -
src/AST/Pass.proto.hpp
r2ed94a9 rb110bcc 18 18 19 19 #include "Common/Stats/Heap.h" 20 21 20 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; 21 template<typename core_t> class Pass; 22 class TranslationUnit; 23 struct PureVisitor; 24 template<typename node_t> node_t * deepCopy( const node_t * ); 25 } 26 27 namespace ast::__pass { 28 29 typedef std::function<void( void * )> cleanup_func_t; 30 typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t; 31 32 // boolean reference that may be null 33 // either refers to a boolean value or is null and returns true 34 class bool_ref { 35 public: 36 bool_ref() = default; 37 ~bool_ref() = default; 38 39 operator bool() { return m_ref ? *m_ref : true; } 40 bool operator=( bool val ) { assert(m_ref); return *m_ref = val; } 41 42 private: 43 44 friend class visit_children_guard; 45 46 bool * set( bool * val ) { 47 bool * prev = m_ref; 48 m_ref = val; 49 return prev; 50 } 51 52 bool * m_ref = nullptr; 53 }; 54 55 // Implementation of the guard value 56 // Created inside the visit scope 57 class guard_value { 58 public: 59 /// Push onto the cleanup 60 guard_value( at_cleanup_t * at_cleanup ) { 61 if( at_cleanup ) { 62 *at_cleanup = [this]( cleanup_func_t && func, void* val ) { 63 push( std::move( func ), val ); 64 }; 65 } 66 } 67 68 ~guard_value() { 69 while( !cleanups.empty() ) { 70 auto& cleanup = cleanups.top(); 71 cleanup.func( cleanup.val ); 72 cleanups.pop(); 73 } 74 } 75 76 void push( cleanup_func_t && func, void* val ) { 77 cleanups.emplace( std::move(func), val ); 78 } 79 80 private: 81 struct cleanup_t { 82 cleanup_func_t func; 83 void * val; 84 85 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {} 58 86 }; 59 87 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 }; 70 } 71 } 72 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; 88 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups; 89 }; 90 91 // Guard structure implementation for whether or not children should be visited 92 class visit_children_guard { 93 public: 94 95 visit_children_guard( bool_ref * ref ) 96 : m_val ( true ) 97 , m_prev( ref ? ref->set( &m_val ) : nullptr ) 98 , m_ref ( ref ) 99 {} 100 101 ~visit_children_guard() { 102 if( m_ref ) { 103 m_ref->set( m_prev ); 104 } 105 } 106 107 operator bool() { return m_val; } 108 109 private: 110 bool m_val; 111 bool * m_prev; 112 bool_ref * m_ref; 113 }; 114 115 /// "Short hand" to check if this is a valid previsit function 116 /// Mostly used to make the static_assert look (and print) prettier 117 template<typename core_t, typename node_t> 118 struct is_valid_previsit { 119 using ret_t = decltype( std::declval<core_t*>()->previsit( std::declval<const node_t *>() ) ); 120 121 static constexpr bool value = std::is_void< ret_t >::value || 122 std::is_base_of<const node_t, typename std::remove_pointer<ret_t>::type >::value; 123 }; 124 125 /// The result is a single node. 126 template< typename node_t > 127 struct result1 { 128 bool differs = false; 129 const node_t * value = nullptr; 130 131 template< typename object_t, typename super_t, typename field_t > 132 void apply( object_t *, field_t super_t::* field ); 133 }; 134 135 /// The result is a container of statements. 136 template< template<class...> class container_t > 137 struct resultNstmt { 138 /// The delta/change on a single node. 139 struct delta { 140 ptr<Stmt> new_val; 141 ssize_t old_idx; 142 bool is_old; 143 144 delta(const Stmt * s, ssize_t i, bool old) : 145 new_val(s), old_idx(i), is_old(old) {} 94 146 }; 95 147 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 148 bool differs = false; 149 container_t< delta > values; 150 151 template< typename object_t, typename super_t, typename field_t > 152 void apply( object_t *, field_t super_t::* field ); 153 154 template< template<class...> class incontainer_t > 155 void take_all( incontainer_t<ptr<Stmt>> * stmts ); 156 157 template< template<class...> class incontainer_t > 158 void take_all( incontainer_t<ptr<Decl>> * decls ); 159 }; 160 161 /// The result is a container of nodes. 162 template< template<class...> class container_t, typename node_t > 163 struct resultN { 164 bool differs = false; 165 container_t<ptr<node_t>> values; 166 167 template< typename object_t, typename super_t, typename field_t > 168 void apply( object_t *, field_t super_t::* field ); 169 }; 170 171 /// Used by previsit implementation 172 /// We need to reassign the result to 'node', unless the function 173 /// returns void, then we just leave 'node' unchanged 174 template<bool is_void> 175 struct __assign; 176 177 template<> 178 struct __assign<true> { 122 179 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 180 static inline void result( core_t & core, const node_t * & node ) { 181 core.previsit( node ); 182 } 183 }; 184 185 template<> 186 struct __assign<false> { 237 187 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 188 static inline void result( core_t & core, const node_t * & node ) { 189 node = core.previsit( node ); 190 assertf(node, "Previsit must not return NULL"); 191 } 192 }; 193 194 /// Used by postvisit implementation 195 /// We need to return the result unless the function 196 /// returns void, then we just return the original node 197 template<bool is_void> 198 struct __return; 199 200 template<> 201 struct __return<true> { 251 202 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 203 static inline const node_t * result( core_t & core, const node_t * & node ) { 204 core.postvisit( node ); 205 return node; 206 } 207 }; 208 209 template<> 210 struct __return<false> { 255 211 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; } \ 212 static inline auto result( core_t & core, const node_t * & node ) { 213 return core.postvisit( node ); 214 } 215 }; 216 217 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 218 // Deep magic (a.k.a template meta programming) to make the templated visitor work 219 // Basically the goal is to make 2 previsit 220 // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of 221 // 'pass.previsit( node )' that compiles will be used for that node for that type 222 // This requires that this option only compile for passes that actually define an appropriate visit. 223 // SFINAE will make sure the compilation errors in this function don't halt the build. 224 // See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE 225 // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing. 226 // This is needed only to eliminate the need for passes to specify any kind of handlers. 227 // The second implementation only works because it has a lower priority. This is due to the bogus last parameter. 228 // The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0 229 // the first implementation takes priority in regards to overloading. 230 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 231 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call 232 template<typename core_t, typename node_t> 233 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) { 234 static_assert( 235 is_valid_previsit<core_t, node_t>::value, 236 "Previsit may not change the type of the node. It must return its paremeter or void." 237 ); 238 239 __assign< 240 std::is_void< 241 decltype( core.previsit( node ) ) 242 >::value 243 >::result( core, node ); 244 } 245 246 template<typename core_t, typename node_t> 247 static inline auto previsit( core_t &, const node_t *, long ) {} 248 249 // PostVisit : never mutates the passed pointer but may return a different node 250 template<typename core_t, typename node_t> 251 static inline auto postvisit( core_t & core, const node_t * node, int ) -> 252 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 253 { 254 return __return< 255 std::is_void< 256 decltype( core.postvisit( node ) ) 257 >::value 258 >::result( core, node ); 259 } 260 261 template<typename core_t, typename node_t> 262 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; } 263 264 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 265 // Deep magic (a.k.a template meta programming) continued 266 // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit 267 // from in order to get extra functionallity for example 268 // class ErrorChecker : WithShortCircuiting { ... }; 269 // Pass<ErrorChecker> checker; 270 // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting 271 // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched 272 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 273 // For several accessories, the feature is enabled by detecting that a specific field is present 274 // Use a macro the encapsulate the logic of detecting a particular field 275 // The type is not strictly enforced but does match the accessory 276 #define FIELD_PTR( name, default_type ) \ 277 template< typename core_t > \ 278 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \ 279 \ 280 template< typename core_t > \ 281 static inline default_type * name( core_t &, long ) { return nullptr; } 282 283 // List of fields and their expected types 284 FIELD_PTR( typeSubs, const ast::TypeSubstitution * ) 285 FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > ) 286 FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > ) 287 FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > ) 288 FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > ) 289 FIELD_PTR( visit_children, __pass::bool_ref ) 290 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 291 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 292 293 // Remove the macro to make sure we don't clash 294 #undef FIELD_PTR 295 296 template< typename core_t > 297 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 298 // Stats::Heap::stacktrace_push(core_t::traceId); 299 } 300 301 template< typename core_t > 302 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 303 // Stats::Heap::stacktrace_pop(); 304 } 305 306 template< typename core_t > 307 static void beginTrace(core_t &, long) {} 308 309 template< typename core_t > 310 static void endTrace(core_t &, long) {} 311 312 // Allows visitor to handle an error on top-level declarations, and possibly suppress the error. 313 // If on_error() returns false, the error will be ignored. By default, it returns true. 314 315 template< typename core_t > 316 static bool on_error (core_t &, ptr<Decl> &, long) { return true; } 317 318 template< typename core_t > 319 static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) { 320 return core.on_error(decl); 321 } 322 323 template< typename core_t, typename node_t > 324 static auto make_location_guard( core_t & core, node_t * node, int ) 325 -> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) { 326 ValueGuardPtr<const CodeLocation *> guard( &core.location ); 327 core.location = &node->location; 328 return guard; 329 } 330 331 template< typename core_t, typename node_t > 332 static auto make_location_guard( core_t &, node_t *, long ) -> int { 333 return 0; 334 } 335 336 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement. 337 // All passes which have such functions are assumed desire this behaviour 338 // detect it using the same strategy 339 namespace scope { 340 template<typename core_t> 341 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) { 342 core.beginScope(); 343 } 344 345 template<typename core_t> 346 static inline void enter( core_t &, long ) {} 347 348 template<typename core_t> 349 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) { 350 core.endScope(); 351 } 352 353 template<typename core_t> 354 static inline void leave( core_t &, long ) {} 355 } // namespace scope 356 357 // Certain passes desire an up to date symbol table automatically 358 // detect the presence of a member name `symtab` and call all the members appropriately 359 namespace symtab { 360 // Some simple scoping rules 361 template<typename core_t> 362 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) { 363 core.symtab.enterScope(); 364 } 365 366 template<typename core_t> 367 static inline auto enter( core_t &, long ) {} 368 369 template<typename core_t> 370 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) { 371 core.symtab.leaveScope(); 372 } 373 374 template<typename core_t> 375 static inline auto leave( core_t &, long ) {} 376 377 // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments 378 // Create macro to condense these common patterns 379 #define SYMTAB_FUNC1( func, type ) \ 380 template<typename core_t> \ 381 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\ 382 core.symtab.func( arg ); \ 383 } \ 284 384 \ 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 } // namespace forall 492 493 // For passes that need access to the global context. Sreaches `translationUnit` 494 namespace translation_unit { 495 template<typename core_t> 496 static inline auto get_cptr( core_t & core, int ) 497 -> decltype( &core.translationUnit ) { 498 return &core.translationUnit; 499 } 500 501 template<typename core_t> 502 static inline const TranslationUnit ** get_cptr( core_t &, long ) { 503 return nullptr; 504 } 505 } 506 507 // For passes, usually utility passes, that have a result. 508 namespace result { 509 template<typename core_t> 510 static inline auto get( core_t & core, char ) -> decltype( core.result() ) { 511 return core.result(); 512 } 513 514 template<typename core_t> 515 static inline auto get( core_t & core, int ) -> decltype( core.result ) { 516 return core.result; 517 } 518 519 template<typename core_t> 520 static inline void get( core_t &, long ) {} 521 } 522 } // namespace __pass 523 } // namespace ast 385 template<typename core_t> \ 386 static inline void func( core_t &, long, type ) {} 387 388 #define SYMTAB_FUNC2( func, type1, type2 ) \ 389 template<typename core_t> \ 390 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\ 391 core.symtab.func( arg1, arg2 ); \ 392 } \ 393 \ 394 template<typename core_t> \ 395 static inline void func( core_t &, long, type1, type2 ) {} 396 397 SYMTAB_FUNC1( addId , const DeclWithType * ); 398 SYMTAB_FUNC1( addType , const NamedTypeDecl * ); 399 SYMTAB_FUNC1( addStruct , const StructDecl * ); 400 SYMTAB_FUNC1( addEnum , const EnumDecl * ); 401 SYMTAB_FUNC1( addUnion , const UnionDecl * ); 402 SYMTAB_FUNC1( addTrait , const TraitDecl * ); 403 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Decl * ); 404 405 // A few extra functions have more complicated behaviour, they are hand written 406 template<typename core_t> 407 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) { 408 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name ); 409 for ( const auto & param : decl->params ) { 410 fwd->params.push_back( deepCopy( param.get() ) ); 411 } 412 core.symtab.addStruct( fwd ); 413 } 414 415 template<typename core_t> 416 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {} 417 418 template<typename core_t> 419 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) { 420 ast::UnionDecl * fwd = new ast::UnionDecl( decl->location, decl->name ); 421 for ( const auto & param : decl->params ) { 422 fwd->params.push_back( deepCopy( param.get() ) ); 423 } 424 core.symtab.addUnion( fwd ); 425 } 426 427 template<typename core_t> 428 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {} 429 430 template<typename core_t> 431 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) { 432 if ( ! core.symtab.lookupStruct( str ) ) { 433 core.symtab.addStruct( str ); 434 } 435 } 436 437 template<typename core_t> 438 static inline void addStruct( core_t &, long, const std::string & ) {} 439 440 template<typename core_t> 441 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) { 442 if ( ! core.symtab.lookupUnion( str ) ) { 443 core.symtab.addUnion( str ); 444 } 445 } 446 447 template<typename core_t> 448 static inline void addUnion( core_t &, long, const std::string & ) {} 449 450 #undef SYMTAB_FUNC1 451 #undef SYMTAB_FUNC2 452 } // namespace symtab 453 454 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 455 // Detect the presence of a member name `subs` and call all members appropriately 456 namespace forall { 457 // Some simple scoping rules 458 template<typename core_t> 459 static inline auto enter( core_t & core, int, const ast::FunctionType * type ) 460 -> decltype( core.subs, void() ) { 461 if ( ! type->forall.empty() ) core.subs.beginScope(); 462 } 463 464 template<typename core_t> 465 static inline auto enter( core_t &, long, const ast::FunctionType * ) {} 466 467 template<typename core_t> 468 static inline auto leave( core_t & core, int, const ast::FunctionType * type ) 469 -> decltype( core.subs, void() ) { 470 if ( ! type->forall.empty() ) { core.subs.endScope(); } 471 } 472 473 template<typename core_t> 474 static inline auto leave( core_t &, long, const ast::FunctionType * ) {} 475 476 // Replaces a TypeInstType's base TypeDecl according to the table 477 template<typename core_t> 478 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst ) 479 -> decltype( core.subs, void() ) { 480 inst = ast::mutate_field( 481 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) ); 482 } 483 484 template<typename core_t> 485 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {} 486 } // namespace forall 487 488 // For passes that need access to the global context. Searches `translationUnit` 489 namespace translation_unit { 490 template<typename core_t> 491 static inline auto get_cptr( core_t & core, int ) 492 -> decltype( &core.translationUnit ) { 493 return &core.translationUnit; 494 } 495 496 template<typename core_t> 497 static inline const TranslationUnit ** get_cptr( core_t &, long ) { 498 return nullptr; 499 } 500 } 501 502 // For passes, usually utility passes, that have a result. 503 namespace result { 504 template<typename core_t> 505 static inline auto get( core_t & core, char ) -> decltype( core.result() ) { 506 return core.result(); 507 } 508 509 template<typename core_t> 510 static inline auto get( core_t & core, int ) -> decltype( core.result ) { 511 return core.result; 512 } 513 514 template<typename core_t> 515 static inline void get( core_t &, long ) {} 516 } 517 518 } // namespace ast::__pass -
src/AST/Print.cpp
r2ed94a9 rb110bcc 29 29 namespace ast { 30 30 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 }; 31 namespace { 32 33 template<typename C, typename... T> 34 constexpr array<C, sizeof...(T)> make_array( T&&... values ) { 35 return array<C, sizeof...(T)>{ std::forward<T>( values )... }; 36 } 37 38 namespace Names { 39 static constexpr auto FuncSpecifiers = make_array<const char*>( 40 "inline", "_Noreturn", "fortran" 41 ); 42 43 static constexpr auto StorageClasses = make_array<const char*>( 44 "extern", "static", "auto", "register", "__thread", "_Thread_local" 45 ); 46 47 static constexpr auto Qualifiers = make_array<const char*>( 48 "const", "restrict", "volatile", "mutex", "_Atomic" 49 ); 50 } 51 52 template<typename bits_t, size_t N> 53 void print( ostream & os, const bits_t & bits, 54 const array<const char *, N> & names ) { 55 if ( !bits.any() ) return; 56 for ( size_t i = 0 ; i < N ; i += 1 ) { 57 if ( bits[i] ) { 58 os << names[i] << ' '; 59 } 60 } 37 61 } 38 62 … … 80 104 static const char* Names[]; 81 105 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 106 void print( const std::vector<ast::Label> & labels ) { 120 107 if ( labels.empty() ) return; … … 230 217 } 231 218 232 print(node->storage );219 ast::print( os, node->storage ); 233 220 os << node->typeString(); 234 221 … … 272 259 273 260 void preprint( const ast::Type * node ) { 274 print(node->qualifiers );261 ast::print( os, node->qualifiers ); 275 262 } 276 263 … … 278 265 print( node->forall ); 279 266 print( node->assertions ); 280 print(node->qualifiers );267 ast::print( os, node->qualifiers ); 281 268 } 282 269 283 270 void preprint( const ast::BaseInstType * node ) { 284 271 print( node->attributes ); 285 print(node->qualifiers );272 ast::print( os, node->qualifiers ); 286 273 } 287 274 … … 294 281 } 295 282 296 print(node->storage );283 ast::print( os, node->storage ); 297 284 298 285 if ( node->type ) { … … 338 325 if ( ! short_mode ) printAll( node->attributes ); 339 326 340 print( node->storage ); 341 print( node->funcSpec ); 342 343 327 ast::print( os, node->storage ); 328 ast::print( os, node->funcSpec ); 344 329 345 330 if ( node->type && node->isTypeFixed ) { … … 384 369 --indent; 385 370 } 371 } 372 373 if ( ! node->withExprs.empty() ) { 374 // Not with a clause, but the 'with clause'. 375 ++indent; 376 os << " with clause" << endl << indent; 377 printAll( node->withExprs ); 378 --indent; 386 379 } 387 380 … … 746 739 virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final { 747 740 os << "Suspend Statement"; 748 switch (node-> type) {749 case ast::SuspendStmt::None : os << " with implicit target"; break;750 case ast::SuspendStmt::Generator: os << " for generator"; break;751 case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;741 switch (node->kind) { 742 case ast::SuspendStmt::None : os << " with implicit target"; break; 743 case ast::SuspendStmt::Generator: os << " for generator"; break; 744 case ast::SuspendStmt::Coroutine: os << " for coroutine"; break; 752 745 } 753 746 os << endl; … … 1627 1620 }; 1628 1621 1622 } // namespace 1623 1629 1624 void print( ostream & os, const ast::Node * node, Indenter indent ) { 1630 1625 Printer printer { os, indent, false }; … … 1637 1632 } 1638 1633 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; 1634 void print( ostream & os, Function::Specs specs ) { 1635 print( os, specs, Names::FuncSpecifiers ); 1645 1636 } 1637 1638 void print( ostream & os, Storage::Classes storage ) { 1639 print( os, storage, Names::StorageClasses ); 1640 } 1641 1642 void print( ostream & os, CV::Qualifiers qualifiers ) { 1643 print( os, qualifiers, Names::Qualifiers ); 1644 } 1645 1646 } // namespace ast -
src/AST/Print.hpp
r2ed94a9 rb110bcc 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
r2ed94a9 rb110bcc 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 ); } … … 394 397 }; 395 398 399 // Clause in a waitfor statement: waitfor (..., ...) ... 396 400 class WaitForClause final : public StmtClause { 397 401 public: … … 454 458 MUTATE_FRIEND 455 459 }; 460 456 461 } // namespace ast 457 462 -
src/AST/SymbolTable.cpp
r2ed94a9 rb110bcc 70 70 if ( baseExpr ) { 71 71 if (baseExpr->env) { 72 Expr * base = shallowCopy(baseExpr);72 Expr * base = deepCopy(baseExpr); 73 73 const TypeSubstitution * subs = baseExpr->env; 74 74 base->env = nullptr; … … 260 260 void SymbolTable::addId( const DeclWithType * decl, const Expr * baseExpr ) { 261 261 // default handling of conflicts is to raise an error 262 addId ( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );262 addIdCommon( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr ); 263 263 } 264 264 265 265 void SymbolTable::addDeletedId( const DeclWithType * decl, const Decl * deleter ) { 266 266 // default handling of conflicts is to raise an error 267 addId ( decl, OnConflict::error(), nullptr, deleter );267 addIdCommon( decl, OnConflict::error(), nullptr, deleter ); 268 268 } 269 269 … … 677 677 } 678 678 679 void SymbolTable::addId (680 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,681 const Decl * deleter ) {679 void SymbolTable::addIdCommon( 680 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, 681 const Expr * baseExpr, const Decl * deleter ) { 682 682 SpecialFunctionKind kind = getSpecialFunctionKind(decl->name); 683 683 if (kind == NUMBER_OF_KINDS) { // not a special decl 684 addId (decl, decl->name, idTable, handleConflicts, baseExpr, deleter);684 addIdToTable(decl, decl->name, idTable, handleConflicts, baseExpr, deleter); 685 685 } 686 686 else { … … 695 695 assertf(false, "special decl with non-function type"); 696 696 } 697 addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter); 698 } 699 } 700 701 void SymbolTable::addId( 702 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr, 703 const Decl * deleter ) { 697 addIdToTable(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter); 698 } 699 } 700 701 void SymbolTable::addIdToTable( 702 const DeclWithType * decl, const std::string & lookupKey, 703 IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, 704 const Expr * baseExpr, const Decl * deleter ) { 704 705 ++*stats().add_calls; 705 706 const std::string &name = decl->name; … … 778 779 void SymbolTable::addMembers( 779 780 const AggregateDecl * aggr, const Expr * expr, SymbolTable::OnConflict handleConflicts ) { 780 for ( const Decl *decl : aggr->members ) {781 if ( auto dwt = dynamic_cast< const DeclWithType * >( decl ) ) {782 addId( dwt, handleConflicts, expr );783 if ( dwt->name == "" ) {784 const Type * t = dwt->get_type()->stripReferences();785 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {786 if ( ! dynamic_cast<const StructInstType *>(rty)787 && ! dynamic_cast<const UnionInstType *>(rty) ) continue;788 ResolvExpr::Cost cost = ResolvExpr::Cost::zero;789 ast::ptr<ast::TypeSubstitution> tmp = expr->env;790 expr = mutate_field(expr, &Expr::env, nullptr);791 const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );792 base = mutate_field(base, &Expr::env, tmp);793 794 addMembers(795 rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts ); 796 }797 }781 for ( const ptr<Decl> & decl : aggr->members ) { 782 auto dwt = decl.as<DeclWithType>(); 783 if ( nullptr == dwt ) continue; 784 addIdCommon( dwt, handleConflicts, expr ); 785 // Inline through unnamed struct/union members. 786 if ( "" != dwt->name ) continue; 787 const Type * t = dwt->get_type()->stripReferences(); 788 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) { 789 if ( ! dynamic_cast<const StructInstType *>(rty) 790 && ! dynamic_cast<const UnionInstType *>(rty) ) continue; 791 ResolvExpr::Cost cost = ResolvExpr::Cost::zero; 792 ast::ptr<ast::TypeSubstitution> tmp = expr->env; 793 expr = mutate_field(expr, &Expr::env, nullptr); 794 const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost ); 795 base = mutate_field(base, &Expr::env, tmp); 796 797 addMembers( 798 rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts ); 798 799 } 799 800 } -
src/AST/SymbolTable.hpp
r2ed94a9 rb110bcc 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
r2ed94a9 rb110bcc 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
r2ed94a9 rb110bcc 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
r2ed94a9 rb110bcc 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 { … … 460 457 public: 461 458 std::vector<ptr<Type>> types; 462 std::vector<ptr<Decl>> members;463 459 464 460 TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q = {} ); -
src/AST/porting.md
r2ed94a9 rb110bcc 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.