Changeset 24d6572 for src/AST


Ignore:
Timestamp:
Jun 12, 2023, 2:45:32 PM (2 years ago)
Author:
Fangren Yu <f37yu@…>
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.
Message:

Merge branch 'master' into ast-experimental

Location:
src/AST
Files:
31 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Attribute.hpp

    r34b4268 r24d6572  
    2727class Expr;
    2828
     29/// An entry in an attribute list: `__attribute__(( ... ))`
    2930class Attribute final : public Node {
    3031public:
  • src/AST/Convert.cpp

    r34b4268 r24d6572  
    559559                auto stmt = new SuspendStmt();
    560560                stmt->then   = get<CompoundStmt>().accept1( node->then   );
    561                 switch(node->type) {
     561                switch (node->kind) {
    562562                        case ast::SuspendStmt::None     : stmt->type = SuspendStmt::None     ; break;
    563563                        case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break;
     
    565565                }
    566566                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;
    567573        }
    568574
     
    573579                for ( auto clause : node->clauses ) {
    574580                        stmt->clauses.push_back({{
    575                                         get<Expression>().accept1( clause->target_func ),
     581                                        get<Expression>().accept1( clause->target ),
    576582                                        get<Expression>().acceptL( clause->target_args ),
    577583                                },
    578584                                get<Statement>().accept1( clause->stmt ),
    579                                 get<Expression>().accept1( clause->cond ),
     585                                get<Expression>().accept1( clause->when_cond ),
    580586                        });
    581587                }
     
    594600        const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final {
    595601                // 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.
    596608                assert( !node );
    597609                return nullptr;
     
    16831695                        GET_ACCEPT_V(attributes, Attribute),
    16841696                        { old->get_funcSpec().val },
    1685                         old->type->isVarArgs
     1697                        (old->type->isVarArgs) ? ast::VariableArgs : ast::FixedArgs
    16861698                };
    16871699
     
    19892001                        GET_ACCEPT_1(else_, Stmt),
    19902002                        GET_ACCEPT_V(initialization, Stmt),
    1991                         old->isDoWhile,
     2003                        (old->isDoWhile) ? ast::DoWhile : ast::While,
    19922004                        GET_LABELS_V(old->labels)
    19932005                );
     
    21312143        virtual void visit( const SuspendStmt * old ) override final {
    21322144                if ( inCache( old ) ) return;
    2133                 ast::SuspendStmt::Type type;
     2145                ast::SuspendStmt::Kind type;
    21342146                switch (old->type) {
    21352147                        case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break;
     
    21582170                        auto clause = new ast::WaitForClause( old->location );
    21592171
    2160                         clause->target_func = GET_ACCEPT_1(clauses[i].target.function, Expr);
     2172                        clause->target = GET_ACCEPT_1(clauses[i].target.function, Expr);
    21612173                        clause->target_args = GET_ACCEPT_V(clauses[i].target.arguments, Expr);
    21622174                        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);
    21642176
    21652177                        stmt->clauses.push_back( clause );
  • src/AST/Create.cpp

    r34b4268 r24d6572  
    2020#include "AST/Decl.hpp"
    2121#include "AST/Type.hpp"
     22#include "Common/Iterate.hpp"
    2223
    2324namespace ast {
  • src/AST/Decl.cpp

    r34b4268 r24d6572  
    2020#include <unordered_map>
    2121
    22 #include "Common/utility.h"
     22#include "Common/Eval.h"       // for eval
    2323
    2424#include "Fwd.hpp"             // for UniqueId
     
    5757        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    5858        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 )
    6060: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ),
    6161        type_params(std::move(forall)), assertions(),
    6262        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 );
    6464        for (auto & param : this->params) {
    6565                ftype->params.emplace_back(param->get_type());
     
    8181        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    8282        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 )
    8484: DeclWithType( location, name, storage, linkage, std::move(attrs), fs ),
    8585                type_params( std::move( forall) ), assertions( std::move( assertions ) ),
    8686                params( std::move(params) ), returns( std::move(returns) ),
    8787                type( nullptr ), stmts( stmts ) {
    88         FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );
     88        FunctionType * type = new FunctionType( isVarArgs );
    8989        for ( auto & param : this->params ) {
    9090                type->params.emplace_back( param->get_type() );
  • src/AST/Decl.hpp

    r34b4268 r24d6572  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Nov 24  9:44:00 2022
    13 // Update Count     : 34
     12// Last Modified On : Wed Apr  5 10:42:00 2023
     13// Update Count     : 35
    1414//
    1515
     
    122122};
    123123
     124/// Function variable arguments flag
     125enum ArgumentFlag { FixedArgs, VariableArgs };
     126
    124127/// Object declaration `int foo()`
    125128class FunctionDecl : public DeclWithType {
     
    144147                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    145148                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 );
    147150
    148151        FunctionDecl( const CodeLocation & location, const std::string & name,
     
    150153                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    151154                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 );
    153156
    154157        const Type * get_type() const override;
     
    313316public:
    314317        bool isTyped; // isTyped indicated if the enum has a declaration like:
    315         // enum (type_optional) Name {...} 
     318        // enum (type_optional) Name {...}
    316319        ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum
    317320        enum class EnumHiding { Visible, Hide } hide;
     
    371374};
    372375
     376/// Assembly declaration: `asm ... ( "..." : ... )`
    373377class AsmDecl : public Decl {
    374378public:
  • src/AST/Expr.cpp

    r34b4268 r24d6572  
    3030#include "Common/SemanticError.h"
    3131#include "GenPoly/Lvalue.h"        // for referencesPermissable
    32 #include "ResolvExpr/typeops.h"    // for extractResultType
     32#include "ResolvExpr/Unify.h"      // for extractResultType
    3333#include "Tuples/Tuples.h"         // for makeTupleType
    3434
  • src/AST/Expr.hpp

    r34b4268 r24d6572  
    256256};
    257257
     258/// A name qualified by a namespace or type.
    258259class QualifiedNameExpr final : public Expr {
    259260public:
     
    261262        std::string name;
    262263
    263         QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 
     264        QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n )
    264265        : Expr( loc ), type_decl( d ), name( n ) {}
    265266
     
    631632};
    632633
     634/// A name that refers to a generic dimension parameter.
    633635class DimensionExpr final : public Expr {
    634636public:
     
    920922};
    921923
    922 
    923924}
    924925
  • src/AST/Fwd.hpp

    r34b4268 r24d6572  
    1515
    1616#pragma once
     17
     18template<typename> struct bitfield;
    1719
    1820#include "AST/Node.hpp"
     
    5658class FinallyClause;
    5759class SuspendStmt;
     60class WhenClause;
    5861class WaitForStmt;
    5962class WaitForClause;
     63class WaitUntilStmt;
    6064class WithStmt;
    6165class DeclStmt;
     
    147151class TranslationGlobal;
    148152
     153// For the following types, only use the using type.
     154namespace CV {
     155        struct qualifier_flags;
     156        using Qualifiers = bitfield<qualifier_flags>;
    149157}
     158namespace Function {
     159        struct spec_flags;
     160        using Specs = bitfield<spec_flags>;
     161}
     162namespace Storage {
     163        struct class_flags;
     164        using Classes = bitfield<class_flags>;
     165}
     166namespace Linkage {
     167        struct spec_flags;
     168        using Spec = bitfield<spec_flags>;
     169}
     170
     171}
  • src/AST/Init.hpp

    r34b4268 r24d6572  
    117117        ptr<Init> init;
    118118
    119         ConstructorInit( 
     119        ConstructorInit(
    120120                const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init )
    121121        : Init( loc, MaybeConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
  • src/AST/Inspect.cpp

    r34b4268 r24d6572  
    1010// Created On       : Fri Jun 24 13:16:31 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Oct  3 11:04:00 2022
    13 // Update Count     : 3
     12// Last Modified On : Fri Apr 14 15:09:00 2023
     13// Update Count     : 4
    1414//
    1515
     
    168168}
    169169
     170bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
     171        return obj && obj->name.empty() && obj->bitfieldWidth;
     172}
     173
    170174} // namespace ast
  • src/AST/Inspect.hpp

    r34b4268 r24d6572  
    1010// Created On       : Fri Jun 24 13:16:31 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Sep 22 13:44:00 2022
    13 // Update Count     : 2
     12// Last Modified On : Fri Apr 14 15:09:00 2023
     13// Update Count     : 3
    1414//
    1515
     
    3838const ApplicationExpr * isIntrinsicCallExpr( const Expr * expr );
    3939
     40/// Returns true if obj's name is the empty string and it has a bitfield width.
     41bool isUnnamedBitfield( const ObjectDecl * obj );
     42
    4043}
  • src/AST/Node.cpp

    r34b4268 r24d6572  
    174174template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::weak >;
    175175template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::strong >;
     176template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::weak >;
     177template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::strong >;
    176178template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::weak >;
    177179template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::strong >;
    178180template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::weak >;
    179181template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::strong >;
     182template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::weak >;
     183template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::strong >;
    180184template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::weak >;
    181185template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::strong >;
  • src/AST/Node.hpp

    r34b4268 r24d6572  
    1919#include <cstddef>     // for nullptr_t
    2020#include <iosfwd>
    21 #include <type_traits> // for remove_reference
    2221
    2322#include "Common/ErrorObjects.h"  // for SemanticErrorException
     
    3635        Node(const Node&) : strong_count(0), weak_count(0) {}
    3736        Node(Node&&) : strong_count(0), weak_count(0) {}
    38         Node& operator= (const Node&) = delete;
    39         Node& operator= (Node&&) = delete;
     37        Node& operator=(const Node&) = delete;
     38        Node& operator=(Node&&) = delete;
    4039        virtual ~Node() {}
    4140
  • src/AST/ParseNode.hpp

    r34b4268 r24d6572  
    4040        template<typename node_t>
    4141        friend node_t * mutate(const node_t * node);
     42        template<typename node_t>
     43        friend node_t * shallowCopy(const node_t * node);
    4244};
    4345
  • src/AST/Pass.hpp

    r34b4268 r24d6572  
    6666//
    6767// 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.
    6872// | result                - Either a method that takes no parameters or a field. If a method (or
    6973//                           callable field) get_result calls it, otherwise the value is returned.
     
    8286        {
    8387                // 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 ) {
    8690                        *const_cast<type **>( visitor ) = this;
    8791                }
     
    9498
    9599        /// 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' );
    98102        }
    99103
     
    158162        const ast::FinallyClause *    visit( const ast::FinallyClause        * ) override final;
    159163        const ast::Stmt *             visit( const ast::SuspendStmt          * ) override final;
     164    const ast::WhenClause *       visit( const ast::WhenClause           * ) override final;
    160165        const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
    161166        const ast::WaitForClause *    visit( const ast::WaitForClause        * ) override final;
     167    const ast::Stmt *             visit( const ast::WaitUntilStmt        * ) override final;
    162168        const ast::Decl *             visit( const ast::WithStmt             * ) override final;
    163169        const ast::NullStmt *         visit( const ast::NullStmt             * ) override final;
  • src/AST/Pass.impl.hpp

    r34b4268 r24d6572  
    2020#include <unordered_map>
    2121
     22#include "AST/Copy.hpp"
    2223#include "AST/TranslationUnit.hpp"
    2324#include "AST/TypeSubstitution.hpp"
     
    4546
    4647#ifdef PEDANTIC_PASS_ASSERT
    47 #define __pedantic_pass_assert(...) assert (__VA_ARGS__)
     48#define __pedantic_pass_assert(...) assert(__VA_ARGS__)
    4849#define __pedantic_pass_assertf(...) assertf(__VA_ARGS__)
    4950#else
     
    124125                        return !new_val.empty();
    125126                }
    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;
    132127        }
    133128
     
    233228
    234229                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;
    285230        }
    286231
     
    352297
    353298                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 values
    369                 // but also contain the new values
    370299        }
    371300
     
    836765                        if ( enterScope ) {
    837766                                __pass::symtab::enter(core, 0);
    838                                 __pass::scope::enter(core, 0);
    839767                        }
    840768                }, [this, leaveScope = !this->atFunctionTop]() {
    841769                        if ( leaveScope ) {
    842770                                __pass::symtab::leave(core, 0);
    843                                 __pass::scope::leave(core, 0);
    844771                        }
    845772                });
     
    1067994
    1068995//--------------------------------------------------------------------------
     996// WhenClause
     997template< typename core_t >
     998const 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//--------------------------------------------------------------------------
    10691011// WaitForStmt
    10701012template< typename core_t >
     
    10911033
    10921034        if ( __visit_children() ) {
    1093                 maybe_accept( node, &WaitForClause::target_func );
     1035                maybe_accept( node, &WaitForClause::target );
    10941036                maybe_accept( node, &WaitForClause::target_args );
    10951037                maybe_accept( node, &WaitForClause::stmt );
    1096                 maybe_accept( node, &WaitForClause::cond );
     1038                maybe_accept( node, &WaitForClause::when_cond );
    10971039        }
    10981040
    10991041        VISIT_END( WaitForClause, node );
     1042}
     1043
     1044//--------------------------------------------------------------------------
     1045// WaitUntilStmt
     1046template< typename core_t >
     1047const 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 );
    11001060}
    11011061
     
    20432003        if ( __visit_children() ) {
    20442004                maybe_accept( node, &TupleType::types );
    2045                 maybe_accept( node, &TupleType::members );
    20462005        }
    20472006
     
    22052164}
    22062165
     2166#undef __pedantic_pass_assertf
     2167#undef __pedantic_pass_assert
    22072168#undef VISIT_START
    22082169#undef VISIT_END
  • src/AST/Pass.proto.hpp

    r34b4268 r24d6572  
    1717// IWYU pragma: private, include "Pass.hpp"
    1818
     19#include "Common/Iterate.hpp"
    1920#include "Common/Stats/Heap.h"
    20 
    2121namespace 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
     36namespace ast::__pass {
     37
     38typedef std::function<void( void * )> cleanup_func_t;
     39typedef 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
     43class bool_ref {
     44public:
     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
     51private:
     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
     66class guard_value {
     67public:
     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
     89private:
     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) {}
    5895        };
    5996
    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
     101class visit_children_guard {
     102public:
     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
     118private:
     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
     126template<typename core_t, typename node_t>
     127struct 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.
     135template< typename node_t >
     136struct 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.
     147template< template<class...> class container_t >
     148struct 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 ) );
    70177                        }
    71178                }
    72179
    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.
     210template< template<class...> class container_t, typename node_t >
     211struct 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
     233template<bool is_void>
     234struct __assign;
     235
     236template<>
     237struct __assign<true> {
    122238        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
     244template<>
     245struct __assign<false> {
    237246        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
     256template<bool is_void>
     257struct __return;
     258
     259template<>
     260struct __return<true> {
    251261        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
     268template<>
     269struct __return<false> {
    255270        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
     291template<typename core_t, typename node_t>
     292static 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
     305template<typename core_t, typename node_t>
     306static inline auto previsit( core_t &, const node_t *, long ) {}
     307
     308// PostVisit : never mutates the passed pointer but may return a different node
     309template<typename core_t, typename node_t>
     310static 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
     320template<typename core_t, typename node_t>
     321static 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 ) \
     336template< typename core_t > \
     337static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
     338\
     339template< typename core_t > \
     340static inline default_type * name( core_t &, long ) { return nullptr; }
     341
     342// List of fields and their expected types
     343FIELD_PTR( typeSubs, const ast::TypeSubstitution * )
     344FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
     345FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
     346FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > )
     347FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > )
     348FIELD_PTR( visit_children, __pass::bool_ref )
     349FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
     350FIELD_PTR( visitor, ast::Pass<core_t> * const )
     351
     352// Remove the macro to make sure we don't clash
     353#undef FIELD_PTR
     354
     355template< typename core_t >
     356static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     357        // Stats::Heap::stacktrace_push(core_t::traceId);
     358}
     359
     360template< typename core_t >
     361static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     362        // Stats::Heap::stacktrace_pop();
     363}
     364
     365template< typename core_t >
     366static void beginTrace(core_t &, long) {}
     367
     368template< typename core_t >
     369static 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
     374template< typename core_t >
     375static bool on_error (core_t &, ptr<Decl> &, long) { return true; }
     376
     377template< typename core_t >
     378static auto on_error (core_t & core, ptr<Decl> & decl, int) -> decltype(core.on_error(decl)) {
     379        return core.on_error(decl);
     380}
     381
     382template< typename core_t, typename node_t >
     383static 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
     390template< typename core_t, typename node_t >
     391static 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
     398namespace 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
     418namespace 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        } \
    284443        \
    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
     515namespace 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`
     548namespace 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.
     562namespace result {
     563        template<typename core_t>
     564        static inline auto get( core_t & core, char ) -> decltype( core.result() ) {
    510565                return core.result();
    511566        }
    512567
    513568        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 ) {
    515570                return core.result;
    516571        }
    517572
    518573        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  
    1616#include "Print.hpp"
    1717
     18#include "Attribute.hpp"
    1819#include "Decl.hpp"
    1920#include "Expr.hpp"
     21#include "Init.hpp"
    2022#include "Stmt.hpp"
    2123#include "Type.hpp"
    2224#include "TypeSubstitution.hpp"
    2325#include "CompilationState.h"
    24 
    25 #include "Common/utility.h" // for group_iterate
     26#include "Common/Iterate.hpp"
    2627
    2728using namespace std;
     
    2930namespace ast {
    3031
    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         };
     32namespace {
     33
     34template<typename C, typename... T>
     35constexpr array<C, sizeof...(T)> make_array( T&&... values ) {
     36        return array<C, sizeof...(T)>{ std::forward<T>( values )... };
     37}
     38
     39namespace 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
     53template<typename bits_t, size_t N>
     54void 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        }
    3762}
    3863
     
    80105        static const char* Names[];
    81106
    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 
    119107        void print( const std::vector<ast::Label> & labels ) {
    120108                if ( labels.empty() ) return;
     
    221209        }
    222210
     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
    223238        void preprint( const ast::NamedTypeDecl * node ) {
    224239                if ( ! node->name.empty() ) {
     
    230245                }
    231246
    232                 print( node->storage );
     247                ast::print( os, node->storage );
    233248                os << node->typeString();
    234249
     
    272287
    273288        void preprint( const ast::Type * node ) {
    274                 print( node->qualifiers );
     289                ast::print( os, node->qualifiers );
    275290        }
    276291
     
    278293                print( node->forall );
    279294                print( node->assertions );
    280                 print( node->qualifiers );
     295                ast::print( os, node->qualifiers );
    281296        }
    282297
    283298        void preprint( const ast::BaseInstType * node ) {
    284299                print( node->attributes );
    285                 print( node->qualifiers );
     300                ast::print( os, node->qualifiers );
    286301        }
    287302
     
    294309                }
    295310
    296                 print( node->storage );
     311                ast::print( os, node->storage );
    297312
    298313                if ( node->type ) {
     
    338353                if ( ! short_mode ) printAll( node->attributes );
    339354
    340                 print( node->storage );
    341                 print( node->funcSpec );
    342 
    343 
     355                ast::print( os, node->storage );
     356                ast::print( os, node->funcSpec );
    344357
    345358                if ( node->type && node->isTypeFixed ) {
     
    384397                                --indent;
    385398                        }
     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;
    386407                }
    387408
     
    746767        virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final {
    747768                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;
     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;
    752773                }
    753774                os << endl;
     
    759780                }
    760781                ++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                }
    761799
    762800                return node;
     
    800838        virtual const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final {
    801839                os << indent-1 << "target function: ";
    802                 safe_print( node->target_func );
     840                safe_print( node->target );
    803841
    804842                if ( !node->target_args.empty() ) {
     
    814852                }
    815853
    816                 if ( node->cond ) {
     854                if ( node->when_cond ) {
    817855                        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 )
    821869                return node;
    822870        }
     
    16271675};
    16281676
     1677} // namespace
     1678
    16291679void print( ostream & os, const ast::Node * node, Indenter indent ) {
    16301680        Printer printer { os, indent, false };
     
    16371687}
    16381688
    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;
     1689void print( ostream & os, Function::Specs specs ) {
     1690        print( os, specs, Names::FuncSpecifiers );
    16451691}
     1692
     1693void print( ostream & os, Storage::Classes storage ) {
     1694        print( os, storage, Names::StorageClasses );
     1695}
     1696
     1697void print( ostream & os, CV::Qualifiers qualifiers ) {
     1698        print( os, qualifiers, Names::Qualifiers );
     1699}
     1700
     1701} // namespace ast
  • src/AST/Print.hpp

    r34b4268 r24d6572  
    1616#pragma once
    1717
    18 #include <iostream>
    19 #include <utility>   // for forward
     18#include <iosfwd>
    2019
    21 #include "AST/Node.hpp"
     20#include "AST/Fwd.hpp"
    2221#include "Common/Indenter.h"
    2322
    2423namespace ast {
    25 
    26 class Decl;
    2724
    2825/// Print a node with the given indenter
     
    4441}
    4542
     43/// Print each cv-qualifier used in the set, followed by a space.
     44void print( std::ostream & os, CV::Qualifiers );
     45/// Print each function specifier used in the set, followed by a space.
     46void print( std::ostream & os, Function::Specs );
     47/// Print each storage class used in the set, followed by a space.
     48void print( std::ostream & os, Storage::Classes );
     49
    4650}
  • src/AST/Stmt.hpp

    r34b4268 r24d6572  
    1010// Created On       : Wed May  8 13:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr 20 14:34:00 2022
    13 // Update Count     : 36
     12// Last Modified On : Wed Apr  5 10:34:00 2023
     13// Update Count     : 37
    1414//
    1515
     
    205205};
    206206
     207// A while loop or a do-while loop:
     208enum WhileDoKind { While, DoWhile };
     209
    207210// While loop: while (...) ... else ... or do ... while (...) else ...;
    208211class WhileDoStmt final : public Stmt {
     
    212215        ptr<Stmt> else_;
    213216        std::vector<ptr<Stmt>> inits;
    214         bool isDoWhile;
     217        WhileDoKind isDoWhile;
    215218
    216219        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 = {} )
    218221                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(nullptr), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    219222
    220223        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 = {} )
    222225                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(else_), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    223226
     
    364367  public:
    365368        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) {}
    370373
    371374        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    375378};
    376379
    377 // Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ...
    378 class WaitForStmt final : public Stmt {
    379   public:
    380         std::vector<ptr<WaitForClause>> clauses;
    381         ptr<Expr> timeout_time;
     380// Base class of WaitFor/WaitUntil statements
     381// form: KEYWORD(...) ... timeout(...) ... else ...
     382class WaitStmt : public Stmt {
     383  public:
     384    ptr<Expr> timeout_time;
    382385        ptr<Stmt> timeout_stmt;
    383386        ptr<Expr> timeout_cond;
     
    385388        ptr<Expr> else_cond;
    386389
     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
     400class 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 ...
     416class WaitForStmt final : public WaitStmt {
     417  public:
     418        std::vector<ptr<WaitForClause>> clauses;
     419
    387420        WaitForStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    388                 : Stmt(loc, std::move(labels)) {}
     421                : WaitStmt(loc, std::move(labels)) {}
    389422
    390423        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    394427};
    395428
    396 class WaitForClause final : public StmtClause {
    397   public:
    398         ptr<Expr> target_func;
     429// Clause in a waitfor statement: waitfor (..., ...) ...
     430class WaitForClause final : public WhenClause {
     431  public:
    399432        std::vector<ptr<Expr>> target_args;
    400         ptr<Stmt> stmt;
    401         ptr<Expr> cond;
    402433
    403434        WaitForClause( const CodeLocation & loc )
    404                 : StmtClause( loc ) {}
     435                : WhenClause( loc ) {}
    405436
    406437        const WaitForClause * accept( Visitor & v ) const override { return v.visit( this ); }
    407438  private:
    408439        WaitForClause * clone() const override { return new WaitForClause{ *this }; }
     440        MUTATE_FRIEND
     441};
     442
     443// waituntil statement: when (...) waituntil (...) ... timeout(...) ... else ...
     444class 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 }; }
    409486        MUTATE_FRIEND
    410487};
     
    454531        MUTATE_FRIEND
    455532};
     533
    456534} // namespace ast
    457535
  • src/AST/SymbolTable.cpp

    r34b4268 r24d6572  
    1818#include <cassert>
    1919
     20#include "Copy.hpp"
     21#include <iostream>
     22#include <algorithm>
     23
    2024#include "Decl.hpp"
    2125#include "Expr.hpp"
    2226#include "Inspect.hpp"
    2327#include "Type.hpp"
    24 #include "CodeGen/OperatorTable.h"  // for isCtorDtorAssign
     28#include "CodeGen/OperatorTable.h"         // for isCtorDtorAssign
    2529#include "Common/SemanticError.h"
    2630#include "Common/Stats/Counter.h"
     
    2832#include "InitTweak/InitTweak.h"
    2933#include "ResolvExpr/Cost.h"
    30 #include "ResolvExpr/typeops.h"
     34#include "ResolvExpr/CandidateFinder.hpp"  // for referenceToRvalueConversion
     35#include "ResolvExpr/Unify.h"
    3136#include "SymTab/Mangler.h"
    3237
     
    6974        if ( baseExpr ) {
    7075                if (baseExpr->env) {
    71                         Expr * base = shallowCopy(baseExpr);
     76                        Expr * base = deepCopy(baseExpr);
    7277                        const TypeSubstitution * subs = baseExpr->env;
    7378                        base->env = nullptr;
     
    193198                        out.push_back(decl.second);
    194199                }
     200
     201                // std::cerr << otypeKey << ' ' << out.size() << std::endl;
    195202        }
    196203
     
    259266void SymbolTable::addId( const DeclWithType * decl, const Expr * baseExpr ) {
    260267        // 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 );
    262269}
    263270
    264271void SymbolTable::addDeletedId( const DeclWithType * decl, const Decl * deleter ) {
    265272        // default handling of conflicts is to raise an error
    266         addId( decl, OnConflict::error(), nullptr, deleter );
     273        addIdCommon( decl, OnConflict::error(), nullptr, deleter );
    267274}
    268275
     
    276283                } else {
    277284                        // 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 ) ) {
    279286                                SemanticError( added->location, "redeclaration of " + added->name );
    280287                        }
     
    641648        } else if ( existing.id->linkage.is_mangled
    642649                        || ResolvExpr::typesCompatible(
    643                                 added->get_type(), existing.id->get_type(), SymbolTable{} ) ) {
     650                                added->get_type(), existing.id->get_type() ) ) {
    644651
    645652                // it is a conflict if one declaration is deleted and the other is not
     
    676683}
    677684
    678 void SymbolTable::addId(
    679                 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    680                 const Decl * deleter ) {
     685void SymbolTable::addIdCommon(
     686                const DeclWithType * decl, SymbolTable::OnConflict handleConflicts,
     687                const Expr * baseExpr, const Decl * deleter ) {
    681688        SpecialFunctionKind kind = getSpecialFunctionKind(decl->name);
    682689        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);
    684691        }
    685692        else {
     
    694701                        assertf(false, "special decl with non-function type");
    695702                }
    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
     707void SymbolTable::addIdToTable(
     708                const DeclWithType * decl, const std::string & lookupKey,
     709                IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts,
     710                const Expr * baseExpr, const Decl * deleter ) {
    703711        ++*stats().add_calls;
    704712        const std::string &name = decl->name;
     
    777785void SymbolTable::addMembers(
    778786                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 );
    797805                }
    798806        }
  • src/AST/SymbolTable.hpp

    r34b4268 r24d6572  
    192192
    193193        /// 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 );
    197197
    198198        /// 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,
    201202                const Expr * baseExpr = nullptr, const Decl * deleter = nullptr);
    202        
     203
    203204        /// adds all of the members of the Aggregate (addWith helper)
    204205        void addMembers( const AggregateDecl * aggr, const Expr * expr, OnConflict handleConflicts );
  • src/AST/TranslationUnit.hpp

    r34b4268 r24d6572  
    1010// Created On       : Tue Jun 11 15:30:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Mar 11 11:19:00 2022
    13 // Update Count     : 1
     12// Last Modified On : Thr Mar  9 16:41:00 2023
     13// Update Count     : 2
    1414//
    1515
     
    1717
    1818#include <map>
    19 #include <vector>
     19#include <list>
    2020
    2121#include "Fwd.hpp"
     
    2828
    2929        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;
    3333};
    3434
  • src/AST/Type.cpp

    r34b4268 r24d6572  
    1010// Created On       : Mon May 13 15:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Nov 24  9:49:00 2022
    13 // Update Count     : 6
     12// Last Modified On : Thu Apr  6 15:59:00 2023
     13// Update Count     : 7
    1414//
    1515
     
    199199
    200200TupleType::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) ) {}
    220202
    221203bool isUnboundType(const Type * type) {
  • src/AST/Type.hpp

    r34b4268 r24d6572  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Nov 24  9:47:00 2022
    13 // Update Count     : 8
     12// Last Modified On : Thu Apr  6 15:58:00 2023
     13// Update Count     : 9
    1414//
    1515
     
    265265};
    266266
    267 /// Function variable arguments flag
    268 enum ArgumentFlag { FixedArgs, VariableArgs };
    269 
    270267/// Type of a function `[R1, R2](*)(P1, P2, P3)`
    271268class FunctionType final : public Type {
     
    462459public:
    463460        std::vector<ptr<Type>> types;
    464         std::vector<ptr<Decl>> members;
    465461
    466462        TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q = {} );
  • src/AST/TypeEnvironment.cpp

    r34b4268 r24d6572  
    178178
    179179bool TypeEnvironment::combine(
    180                 const TypeEnvironment & o, OpenVarSet & open, const SymbolTable & symtab ) {
     180                const TypeEnvironment & o, OpenVarSet & open ) {
    181181        // short-circuit easy cases
    182182        if ( o.empty() ) return true;
     
    201201                        EqvClass & r = *rt;
    202202                        // merge bindings
    203                         if ( ! mergeBound( r, c, open, symtab ) ) return false;
     203                        if ( ! mergeBound( r, c, open ) ) return false;
    204204                        // merge previous unbound variables into this class, checking occurs if needed
    205205                        if ( r.bound ) for ( const auto & u : c.vars ) {
     
    216216                                } else if ( st != rt ) {
    217217                                        // bound, but not to the same class
    218                                         if ( ! mergeClasses( rt, st, open, symtab ) ) return false;
     218                                        if ( ! mergeClasses( rt, st, open ) ) return false;
    219219                                }       // ignore bound into the same class
    220220                        }
     
    280280bool TypeEnvironment::bindVar(
    281281                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
    284283) {
    285284        // remove references from bound type, so that type variables can only bind to value types
     
    300299                        if ( unifyInexact(
    301300                                        newType, target, *this, need, have, open,
    302                                         widen & WidenMode{ it->allowWidening, true }, symtab, common ) ) {
     301                                        widen & WidenMode{ it->allowWidening, true }, common ) ) {
    303302                                if ( common ) {
    304303                                        it->bound = std::move(common);
     
    321320                const TypeInstType * var1, const TypeInstType * var2, TypeData && data,
    322321                AssertionSet & need, AssertionSet & have, const OpenVarSet & open,
    323                 WidenMode widen, const SymbolTable & symtab
     322                WidenMode widen
    324323) {
    325324        auto c1 = internal_lookup( *var1 );
     
    358357
    359358                if ( unifyInexact(
    360                                 newType1, newType2, *this, need, have, open, newWidenMode, symtab, common ) ) {
     359                                newType1, newType2, *this, need, have, open, newWidenMode, common ) ) {
    361360                        c1->vars.insert( c2->vars.begin(), c2->vars.end() );
    362361                        c1->allowWidening = widen1 && widen2;
     
    409408
    410409bool TypeEnvironment::mergeBound(
    411                 EqvClass & to, const EqvClass & from, OpenVarSet & open, const SymbolTable & symtab ) {
     410                EqvClass & to, const EqvClass & from, OpenVarSet & open ) {
    412411        if ( from.bound ) {
    413412                if ( to.bound ) {
     
    419418
    420419                        if ( unifyInexact(
    421                                         toType, fromType, *this, need, have, open, widen, symtab, common ) ) {
     420                                        toType, fromType, *this, need, have, open, widen, common ) ) {
    422421                                // unifies, set common type if necessary
    423422                                if ( common ) {
     
    437436
    438437bool TypeEnvironment::mergeClasses(
    439         ClassList::iterator to, ClassList::iterator from, OpenVarSet & open, const SymbolTable & symtab
     438        ClassList::iterator to, ClassList::iterator from, OpenVarSet & open
    440439) {
    441440        EqvClass & r = *to, & s = *from;
    442441
    443442        // ensure bounds match
    444         if ( ! mergeBound( r, s, open, symtab ) ) return false;
     443        if ( ! mergeBound( r, s, open ) ) return false;
    445444
    446445        // check safely bindable
  • src/AST/TypeEnvironment.hpp

    r34b4268 r24d6572  
    6363
    6464                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 );
    6666        }
    6767};
     
    169169        /// Merge environment with this one, checking compatibility.
    170170        /// 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 );
    172172
    173173        /// Add all type variables in environment to open var list
     
    183183                const TypeInstType * typeInst, const Type * bindTo, const TypeData & data,
    184184                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
    185                 ResolvExpr::WidenMode widen, const SymbolTable & symtab );
     185                ResolvExpr::WidenMode widen );
    186186
    187187        /// Binds the type classes represented by `var1` and `var2` together; will add one or both
     
    190190                const TypeInstType * var1, const TypeInstType * var2, TypeData && data,
    191191                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
    192                 ResolvExpr::WidenMode widen, const SymbolTable & symtab );
     192                ResolvExpr::WidenMode widen );
    193193
    194194        /// Disallows widening for all bindings in the environment
     
    205205        /// Unifies the type bound of `to` with the type bound of `from`, returning false if fails
    206206        bool mergeBound(
    207                 EqvClass & to, const EqvClass & from, OpenVarSet & openVars, const SymbolTable & symtab );
     207                EqvClass & to, const EqvClass & from, OpenVarSet & openVars );
    208208
    209209        /// Merges two type classes from local environment, returning false if fails
    210210        bool mergeClasses(
    211                 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars,
    212                 const SymbolTable & symtab );
     211                ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars);
    213212
    214213        /// Private lookup API; returns array index of string, or env.size() for not found
  • src/AST/TypeSubstitution.cpp

    r34b4268 r24d6572  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// 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"
    1517
    1618#include "Type.hpp"   // for TypeInstType, Type, StructInstType, UnionInstType
    17 #include "TypeSubstitution.hpp"
     19#include "Pass.hpp"   // for Pass, PureVisitor, WithGuards, WithVisitorRef
    1820
    1921namespace ast {
    20 
    21 
    22 // size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");
    2322
    2423TypeSubstitution::TypeSubstitution() {
     
    119118}
    120119
     120// definitition must happen after PassVisitor is included so that WithGuards can be used
     121struct 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
    121145void TypeSubstitution::normalize() {
    122146        Pass<Substituter> sub( *this, true );
     
    128152                }
    129153        } while ( sub.core.subCount );
     154}
     155
     156TypeSubstitution::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 };
    130162}
    131163
  • src/AST/TypeSubstitution.hpp

    r34b4268 r24d6572  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 30 22:52:47 2019
    13 // Update Count     : 9
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr May 25 12:31:00 2023
     13// Update Count     : 10
    1414//
    1515
     
    4646        TypeSubstitution &operator=( const TypeSubstitution &other );
    4747
    48         template< typename SynTreeClass >
     48        template< typename node_t >
    4949        struct ApplyResult {
    50                 ast::ptr<SynTreeClass> node;
     50                ast::ptr<node_t> node;
    5151                int count;
    5252        };
    5353
    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        }
    5659
    5760        template< typename node_t, enum Node::ref_type ref_t >
    5861        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>();
    6264                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 };
    6371        }
    6472
    6573        template< typename node_t, enum Node::ref_type ref_t >
    6674        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>();
    7077                return ret.count;
    7178        }
     
    97104        // Mutator that performs the substitution
    98105        struct Substituter;
     106        ApplyResult<Node> applyBase( const Node * input, bool isFree ) const;
    99107
    100108        // TODO: worry about traversing into a forall-qualified function type or type decl with assertions
     
    158166} // namespace ast
    159167
    160 // include needs to happen after TypeSubstitution is defined so that both TypeSubstitution and
    161 // 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 used
    168 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-statements
    176                 void previsit( const FunctionType * type );
    177                 /// Records type variable bindings from forall-statements and instantiations of generic types
    178                 // 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 ast
    208 
    209168// Local Variables: //
    210169// tab-width: 4 //
  • src/AST/Visitor.hpp

    r34b4268 r24d6572  
    5050    virtual const ast::FinallyClause *    visit( const ast::FinallyClause        * ) = 0;
    5151    virtual const ast::Stmt *             visit( const ast::SuspendStmt          * ) = 0;
     52    virtual const ast::WhenClause *       visit( const ast::WhenClause           * ) = 0;
    5253    virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) = 0;
    5354    virtual const ast::WaitForClause *    visit( const ast::WaitForClause        * ) = 0;
     55    virtual const ast::Stmt *             visit( const ast::WaitUntilStmt        * ) = 0;
    5456    virtual const ast::Decl *             visit( const ast::WithStmt             * ) = 0;
    5557    virtual const ast::NullStmt *         visit( const ast::NullStmt             * ) = 0;
  • src/AST/porting.md

    r34b4268 r24d6572  
    213213* `get_statement()` exclusively used for code location, replaced with `CodeLocation` field
    214214
    215 `CaseStmt`
     215`CaseStmt` => `CaseClause`
    216216* `_isDefault` has been removed
    217217  * `isDefault` calculates value from `cond`
     
    227227* `block` -> `body` and `finallyBlock` -> `finally`
    228228
    229 `ThrowStmt` `CatchStmt`
     229`ThrowStmt` and `CatchStmt` => `CatchClause`
    230230* moved `Kind` enums to shared `ast::ExceptionKind` enum
    231231
    232 `FinallyStmt`
     232`FinallyStmt` => `FinallyClause`
    233233* `block` -> `body`
    234234
     
    280280* Template class, with specializations and using to implement some other types:
    281281  * `StructInstType`, `UnionInstType` & `EnumInstType`
     282  * `baseStruct`, `baseUnion` & `baseEnum` => `base`
    282283
    283284`TypeInstType`
Note: See TracChangeset for help on using the changeset viewer.