Changes in / [768b3b4f:b78129a]


Ignore:
Files:
1 deleted
20 edited

Legend:

Unmodified
Added
Removed
  • doc/proposals/vtable.md

    r768b3b4f rb78129a  
    88
    99The basic concept of a virtual table (vtable) is the same here as in most
    10 other languages that use them. They will mostly contain function pointers
    11 although they should be able to store anything that goes into a trait.
    12 
    13 I also include notes on a sample implementation, which primarily exists to show
    14 there is a reasonable implementation. The code samples for that are in a slight
    15 pseudo-code to help avoid name mangling and keeps some CFA features while they
    16 would actually be written in C.
     10other languages. They will mostly contain function pointers although they
     11should be able to store anything that goes into a trait.
     12
     13I also include notes on a sample implementation, which primarly exists to show
     14there is a resonable implementation. The code samples for that are in a slight
     15psudo-code to help avoid name mangling and keeps some CFA features while they
     16would actually be writen in C.
    1717
    1818Trait Instances
     
    2020
    2121Currently traits are completely abstract. Data types might implement a trait
    22 but traits are not themselves data types. Which is to say you cannot have an
    23 instance of a trait. This proposal will change that and allow instances of
    24 traits to be created from instances of data types that implement the trait.
    25 
    26 For example:
     22but traits are not themselves data types. This will change that and allow
     23instances of traits to be created from instances of data types that implement
     24the trait.
    2725
    2826    trait combiner(otype T) {
    29         void combine(T&, int);
    30     };
     27                void combine(T&, int);
     28        };
    3129
    3230    struct summation {
    33         int sum;
    34     };
    35 
    36     void ?{}( struct summation & this ) {
    37         this.sum = 0;
    38     }
     31                int sum;
     32        };
     33
     34        void ?{}( struct summation & this ) {
     35                this.sum = 0;
     36        }
    3937
    4038    void combine( struct summation & this, int num ) {
    41         this.sum = this.sum + num;
    42     }
    43 
    44     trait combiner obj = struct summation{};
    45     combine(obj, 5);
     39                this.sum = this.sum + num;
     40        }
     41
     42        trait combiner obj = struct summation{};
     43        combine(obj, 5);
    4644
    4745As with `struct` (and `union` and `enum`), `trait` might be optional when
     
    5149For traits to be used this way they should meet two requirements. First they
    5250should only have a single polymorphic type and each assertion should use that
    53 type once as a parameter. Extensions may later loosen these requirements.
    54 
    55 Also note this applies to the final expanded list of assertions. Consider:
    56 
    57     trait foo(otype T, otype U) {
    58         ... functions that use T once ...
    59     }
    60 
    61     trait bar(otype S | foo(S, char)) {
    62         ... functions that use S once ...
    63     }
    64 
    65 In this example `bar` may be used as a type but `foo` may not.
    66 
    67 When a trait is used as a type it creates a generic object which combines
    68 the base structure (an instance of `summation` in this case) and the vtable,
    69 which is currently created and provided by a hidden mechanism.
    70 
    71 The generic object type for each trait also implements that trait. This is
    72 actually the only means by which it can be used. The type of these functions
    73 look something like this:
    74 
    75     void combine(trait combiner & this, int num);
     51type once as a parameter. Extentions may later loosen these requirements.
     52
     53If a trait object is used it should generate a series of implicate functions
     54each of which implements one of the functions required by the trait. So for
     55combiner there is an implicate:
     56
     57    void combine(trait combiner & this, int);
     58
     59This function is the one actually called at the end
    7660
    7761The main use case for trait objects is that they can be stored. They can be
    78 passed into functions, but using the trait directly is preferred in this case.
     62passed into functions, but using the trait directly is prefred in this case.
    7963
    8064    trait drawable(otype T) {
     
    9478    }
    9579
    96 The trait types can also be used in the types of assertions on traits as well.
    97 In this usage they passed as the underlying object and vtable pair as they
    98 are stored. The trait types can also be used in that trait's definition, which
    99 means you can pass two instances of a trait to a single function. However the
    100 look-up of the one that is not used to look up any functions, until another
    101 function that uses that object in the generic/look-up location is called.
     80Currently these traits are limited to 1 trait parameter and functions should
     81have exactly 1 parameter. We cannot abstract away pairs of types and still
     82pass them into normal functions, which take them seperately.
     83
     84The second is required the because we need to get the vtable from somewhere.
     85If there are 0 trait objects than no vtable is avalible, if we have more than
     861 than the vtables give conflicting answers on what underlying function to
     87call. And even then the underlying type assumes a concrete type.
     88
     89This loop can sort of be broken by using the trait object directly in the
     90signature. This has well defined meaning, but might not be useful.
    10291
    10392    trait example(otype T) {
    10493        bool test(T & this, trait example & that);
    10594    }
    106 
    107 ### Explanation Of Restrictions
    108 
    109 The two restrictions on traits that can be used as trait objects are:
    110 
    111 1.  Only one generic parameter may be defined in the trait's header.
    112 2.  Each function assertion must have one parameter with the type of the
    113     generic parameter. They may or may not return a value of that type.
    114 
    115 Elsewhere in this proposal I suggest ways to broaden these requirements.
    116 A simple example would be if a trait meets requirement 1 but not 2, then
    117 the assertions that do not satisfy the exactly one parameter requirement can
    118 be ignored.
    119 
    120 However I would like to talk about why these two rules are in place in the
    121 first place and the problems that any exceptions to these rules must avoid.
    122 
    123 The problems appear when the dispatcher function which operates on the
    124 generic object.
    125 
    126     trait combiner(otype T, otype U) {
    127         void combine(T&, U);
    128     }
    129 
    130 This one is so strange I don't have proper syntax for it but let us say that
    131 the concrete dispatcher would be typed as
    132 `void combine(combiner(T) &, combiner(U));`. Does the function that combine
    133 the two underlying types exist to dispatch too?
    134 
    135 Maybe not. If `combiner(T)` works with ints and `combiner(U)` is a char then
    136 they could not be. It would have to enforce that all pairs of any types
    137 that are wrapped in this way. Which would pretty much destroy any chance of
    138 separate compilation.
    139 
    140 Even then it would be more expensive as the wrappers would have to carry ids
    141 that you use to look up on an <number of types>+1 dimensional table.
    142 
    143 The second restriction has a similar issue but makes a bit more sense to
    144 write out.
    145 
    146     trait Series(otype T) {
    147         ... size, iterators, getters ...
    148         T join(T const &, T const &);
    149     }
    150 
    151 With the dispatcher typed as:
    152 
    153     Series join(Series const &, Series const &);
    154 
    155 Because these instances are generic and hide the underlying implementation we
    156 do not know what that implementation is. Unfortunately this also means the
    157 implementation for the two parameters might not be the same. Once we have
    158 two different types involved this devolves into the first case.
    159 
    160 We could check at run-time that the have the same underlying type, but this
    161 would likely time and space overhead and there is no clear recovery path.
    16295
    16396#### Sample Implementation
     
    183116
    184117There may have to be special cases for things like copy construction, that
    185 might require a more significant wrapper. On the other hand moving could be
     118might require a more sigificant wrapper. On the other hand moving could be
    186119implemented by moving the pointers without any need to refer to the base
    187120object.
    188121
    189 ### Extension: Multiple Trait Parameters
    190 The base proposal in effect creates another use for the trait syntax that is
    191 related to the ones currently in the language but is also separate from them.
    192 The current uses generic functions and generic types, this new use could be
    193 described as generic objects.
    194 
    195 A generic object is of a concrete type and has concrete functions that work on
    196 it. It is generic in that it is a wrapper for an unknown type. Traits serve
    197 a similar role here as in generic functions as they limit what the function
    198 can be generic over.
    199 
    200 This combines the use allowing to have a generic type that is a generic
    201 object. All but one of the trait's parameters is given a concrete type,
    202 conceptually currying the trait to create a trait with on generic parameter
    203 that fits the original restrictions. The resulting concrete generic object
    204 type is different with each set of provided parameters and their values.
    205 
    206 Then it just becomes a question of where this is done. Again both examples use
    207 a basic syntax to show the idea.
    208 
    209     trait iterator(virtual otype T, otype Item) {
    210         bool has_next(T const &);
    211         Item get_next(T const *);
    212     }
    213 
    214     iterator(int) int_it = begin(container_of_ints);
    215 
    216 The first option is to do it at the definition of the trait. One parameter
    217 is selected (here with the `virtual` keyword, but other rules like "the first"
    218 could also be used) and when an instance of the trait is created all the
    219 other parameters must be provided.
    220 
    221     trait iterator(otype T, otype Item) {
    222         bool has_next(T const &);
    223         Item get_next(T const *);
    224     }
    225 
    226     iterator(virtual, int) int_it = begin(container_of_ints);
    227 
    228 The second option is to skip a parameter as part of the type instance
    229 definition. One parameter is explicitly skipped (again with the `virtual`
    230 keyword) and the others have concrete types. The skipped one is the one we
    231 are generic on.
    232 
    233 Incidentally in both examples `container_of_ints` may itself be a generic
    234 object and `begin` returns a generic iterator with unknown implementation.
    235 
    236 These options are not exclusive. Defining a default on the trait allows for
    237 an object to be created as in the first example. However, whether the
    238 default is provided or not, the second syntax can be used to pick a
    239 parameter on instantiation.
     122### Extention: Multiple Trait Parameters
     123Currently, this gives traits two independent uses. They use the same syntax,
     124except for limits boxable traits have, and yet don't really mix. The most
     125natural way to do this is to allow trait instances to pick one parameter
     126that they are generic over, the others they choose types to implement.
     127
     128The two ways to do the selection, the first is do it at the trait definition.
     129Each trait picks out a single parameter which it can box (here the `virtual`
     130qualifier). When you create an instance of a trait object you provide
     131arguments like for a generic structure, but skip over the marked parameter.
     132
     133    trait combiner(virtual otype T, otype Combined) {
     134        void combine(T &, Combined &);
     135    }
     136
     137    trait combiner(int) int_combiner;
     138
     139The second is to do it at the instaniation point. A placeholder (here the
     140keyword `virtual`) is used to explicately skip over the parameter that will be
     141abstracted away, with the same rules as above if it was the marked parameter.
     142
     143    trait combiner(otype T, otype Combined) {
     144        void combine(T &, Combined &);
     145    };
     146
     147    trait combiner(virtual, int) int_combiner;
     148
     149Using both (first to set the default, second as a local override) would also
     150work, although might be exessively complicated.
     151
     152This is useful in cases where you want to use a generic type, but leave part
     153of it open and store partially generic result. As a simple example
     154
     155    trait folder(otype T, otype In, otype Out) {
     156        void fold(T & this, In);
     157        Out fold_result(T & this);
     158    }
     159
     160Which allows you to fold values without putting them in a container. If they
     161are already in a container this is exessive, but if they are generated over
     162time this gives you a simple interface. This could for instance be used in
     163a profile, where T changes for each profiling statistic and you can plug in
     164multiple profilers for any run by adding them to an array.
    240165
    241166Hierarchy
    242167---------
    243168
    244 We would also like to implement hierarchical relations between types.
    245 
    246     AstNode
    247     |-ParseNode
    248     | |-Declaration
    249     | | |-DeclarationWithType
    250     | | |-StructureDeclaration
    251     | |-Statement
    252     | | |-CompoundStatement
    253     | |-Expression
    254     |-Type
    255 
    256 Virtual tables by themselves are not quite enough to implement this system.
    257 A vtable is just a list of functions and there is no way to check at run-time
    258 what these functions, we carry that knowledge with the table.
    259 
    260 This proposal adds type ids to check for position in the hierarchy and an
    261 explicate syntax for establishing a hierarchical relation between traits and
    262 their implementing types. The ids should uniquely identify each type and
    263 allow retrieval of the type's parent if one exists. By recursion this allows
    264 the ancestor relation between any two hierarchical types can be checked.
    265 
    266 The hierarchy is created with traits as the internal nodes and structures
    267 as the leaf nodes. The structures may be used normally and the traits can
    268 be used to create generic objects as in the first section (the same
    269 restrictions apply). However these type objects store their type id which can
    270 be recovered to figure out which type they are or at least check to see if
    271 they fall into a given sub-tree at run-time.
    272 
    273 Here is an example of part of a hierarchy. The `virtual(PARENT)` syntax is
    274 just an example. But when used it give the name of the parent type or if
    275 empty it shows that this type is the root of its hierarchy.
     169Virtual tables by them selves are not quite enough to implement the planned
     170hierarchy system. An addition of type ids, implemented as pointers which
     171point to your parent's type id, is required to actually create the shape of
     172the hierarchy. However vtables would allow behaviour to be carried with the
     173tree.
     174
     175The hierarchy would be a tree of types, of traits and structs. Currently we do
     176not support structural extension, so traits form the internal nodes and
     177structures the leaf nodes.
     178
     179The syntax is undecided but it will include a clause like `virtual (PARENT)`
     180on trait and struct definitions. It marks out all types in a hierarchy.
     181PARENT may be omitted, if it is this type is the root of a hierarchy. Otherwise
     182it is the name of the type that is this type's parent in the hierarchy.
     183
     184Traits define a trait instance type that implements all assertions in this
     185trait and its parents up until the root of the hierarchy. Each trait then
     186defines a vtable type. Structures will also have a vtable type but it should
     187be the same as their parent's.
     188
     189Trait objects within the tree can be statically cast to a parent type. Casts
     190from a parent type to a child type are conditional, they check to make sure
     191the underlying instance is an instance of the child type, or an instance of
     192one of its children. The type then is recoverable at run-time.
     193
     194As with regular trait objects, calling a function on a trait object will cause
     195a look-up on the the virtual table. The casting rules make sure anything that
     196can be cast to a trait type will have all the function implementations for
     197that trait.
     198
     199Converting from a concrete type (structures at the edge of the hierarchy) to
     200an abstract type works the same as with normal trait objects, the underlying
     201object is packaged with a virtual table pointer. Converting back to an abstract
     202type requires confirming the underlying type matches, but then simply extracts
     203the pointer to it.
     204
     205Exception Example:
    276206(Also I'm not sure where I got these casing rules.)
     207
     208    trait exception(otype T) virtual() {
     209        char const * what(T & this);
     210    }
     211
     212    trait io_error(otype T) virtual(exception) {
     213        FILE * which_file(T & this);
     214    }
     215
     216    struct eof_error(otype T) virtual(io_error) {
     217        FILE * file;
     218    }
     219
     220    char const * what(eof_error &) {
     221        return "Tried to read from an empty file.";
     222    }
     223
     224    FILE * which_file(eof_error & this) {
     225        return eof_error.file;
     226    }
     227
     228Ast Example:
    277229
    278230    trait ast_node(otype T) virtual() {
     
    315267    }
    316268
    317 ### Extension: Structural Inheritance
    318 An extension would be allow structures to be used as internal nodes on the
    319 inheritance tree. Its child types would have to implement the same fields.
    320 
    321 The weaker restriction would be to convert the fields into field assertions
    322 (Not implemented yet: `U T.x` means there is a field of type you on the type
    323 T. Offset unknown and passed in/stored with function pointers.)
    324 A concrete child would have to declare the same set of fields with the same
    325 types. This is of a more functional style.
    326 
    327 The stronger restriction is that the fields of the parent are a prefix of the
    328 child's fields. Possibly automatically inserted. This the imperative view and
    329 may also have less overhead.
    330 
    331 ### Extension: Unions and Enumerations
    332 Currently there is no reason unions and enumerations, in the cases they
    333 do implement the trait, could not be in the hierarchy as leaf nodes.
    334 
    335 It does not work with structural induction, but that could just be a compile
    336 time check that all ancestors are traits or do not add field assertions.
    337 
    338269#### Sample Implementation
    339270The type id may be as little as:
     
    344275
    345276Some linker magic would have to be used to ensure exactly one copy of each
    346 structure for each type exists in memory. There seem to be special once
     277structure for each type exists in memory. There seem to be spectial once
    347278sections that support this and it should be easier than generating unique
    348279ids across compilation units.
     
    369300
    370301### Virtual Casts
    371 The generic objects may be cast up and down the hierarchy.
    372 
    373 Casting to an ancestor type always succeeds. From one generic type to another
    374 is just a reinterpretation and could be implicate. Wrapping and unwrapping
    375 a concrete type will probably use the same syntax as in the first section.
    376 
    377 Casting from an ancestor to a descendent requires a check. The underlying
    378 type may or may not belong to the sub-tree headed by that descendent. For this
    379 we introduce a new cast operator, which returns the pointer unchanged if the
    380 check succeeds and null otherwise.
     302To convert from a pointer to a type higher on the hierarchy to one lower on
     303the hierarchy a check is used to make sure that the underlying type is also
     304of that lower type.
     305
     306The proposed syntax for this is:
    381307
    382308    trait SubType * new_value = (virtual trait SubType *)super_type;
    383309
    384 For the following example I am using the as of yet finished exception system.
    385 
    386     trait exception(otype T) virtual() {
    387         char const * what(T & this);
    388     }
    389 
    390     trait io_error(otype T) virtual(exception) {
    391         FILE * which_file(T & this);
    392     }
    393 
    394     struct eof_error(otype T) virtual(io_error) {
    395         FILE * file;
    396     }
    397 
    398     char const * what(eof_error &) {
    399         return "Tried to read from an empty file.";
    400     }
    401 
    402     FILE * which_file(eof_error & this) {
    403         return eof_error.file;
    404     }
    405 
    406     bool handleIoError(exception * exc) {
    407         io_error * error = (virtual io_error *)exc;
    408         if (NULL == error) {
    409             return false;
    410         }
    411         ...
    412         return true;
    413     }
    414 
    415 ### Extension: Implicate Virtual Cast Target
    416 This is a small extension, even in the example above `io_error *` is repeated
    417 in the cast and the variable being assigned to. Using return type inference
    418 would allow the second type to be skipped in cases it is clear what type is
    419 being checked against.
    420 
    421 The line then becomes:
    422 
    423     io_error * error = (virtual)exc;
    424 
    425 ### Extension: Inline vtables
     310It will return the same pointer if it does point to the subtype and null if
     311it does not, doing the check and conversion in one operation.
     312
     313### Inline vtables
    426314Since the structures here are usually made to be turned into trait objects
    427 it might be worth it to have fields in them to store the virtual table
     315it might be worth it to have fields on them to store the virtual table
    428316pointer. This would have to be declared on the trait as an assertion (example:
    429317`vtable;` or `T.vtable;`), but if it is the trait object could be a single
     
    432320There are also three options for where the pointer to the vtable. It could be
    433321anywhere, a fixed location for each trait or always at the front. For the per-
    434 trait solution an extension to specify what it is (example `vtable[0];`) which
     322trait solution an extention to specify what it is (example `vtable[0];`) which
    435323could also be used to combine it with others. So these options can be combined
    436324to allow access to all three options.
     
    456344the type declaration, including the functions that satisfy the trait, are
    457345all defined. Currently there are many points where this can happen, not all
    458 of them have the same definitions and no way to select one over the other.
     346of them will have the same definitions and no way to select one over the
     347other.
    459348
    460349Some syntax would have to be added to specify the resolution point. To ensure
     
    506395
    507396These could also be placed inside functions. In which case both the name and
    508 the default keyword might be optional. If the name is omitted in an assignment
    509 the closest vtable is chosen (returning to the global default rule if no
    510 appropriate local vtable is in scope).
     397the default keyword might be optional. If the name is ommited in an assignment
     398the closest vtable is choosen (returning to the global default rule if no
     399approprate local vtable is in scope).
    511400
    512401### Site Based Resolution:
  • src/AST/Attribute.hpp

    r768b3b4f rb78129a  
    4747};
    4848
    49 
    50 
    51 //=================================================================================================
    52 /// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
    53 /// remove only if there is a better solution
    54 /// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
    55 /// forward declarations
    56 inline void increment( const class Attribute * node, Node::ref_type ref ) { node->increment( ref ); }
    57 inline void decrement( const class Attribute * node, Node::ref_type ref ) { node->decrement( ref ); }
    5849}
    5950
  • src/AST/Bitfield.hpp

    r768b3b4f rb78129a  
    2222/// does not allow it. Requires type to have `unsigned val` field
    2323/// @param BFType  Name of containing type
    24 template<typename T>
    25 struct bitfield : public T {
    26         static_assert(sizeof(T) == sizeof(unsigned int), "Type has incorrect size");
    27         using T::val;
    28         using val_t = decltype(val);
    29 
    30         constexpr bitfield() : T( 0 ) {}
    31         constexpr bitfield( val_t v ) : T( v ) {}
    32 
    33         bool operator[]( val_t i ) const { return val & (1 << i); }
    34         bool any() const { return val != 0; }
    35         void reset() { val = 0; }
    36         int ffs() { return ::ffs( val ) - 1; }
    37 
    38         bitfield operator&=( bitfield other ) {
    39                 val &= other.val; return *this;
     24#define MakeBitfield( BFType )                                         \
     25        constexpr BFType() : val( 0 ) {}                                   \
     26        constexpr BFType( unsigned int v ) : val( v ) {}                   \
     27        bool operator[]( unsigned int i ) const { return val & (1 << i); } \
     28        bool any() const { return val != 0; }                              \
     29        void reset() { val = 0; }                                          \
     30        int ffs() { return ::ffs( val ) - 1; }                             \
     31        BFType operator&=( BFType other ) {                                \
     32                val &= other.val; return *this;                                \
     33        }                                                                  \
     34        BFType operator&( BFType other ) const {                           \
     35                BFType q = other;                                              \
     36                q &= *this;                                                    \
     37                return q;                                                      \
     38        }                                                                  \
     39        BFType operator|=( BFType other ) {                                \
     40                val |= other.val; return *this;                                \
     41        }                                                                  \
     42        BFType operator|( BFType other ) const {                           \
     43                BFType q = other;                                              \
     44                q |= *this;                                                    \
     45                return q;                                                      \
     46        }                                                                  \
     47        BFType operator-=( BFType other ) {                                \
     48                val &= ~other.val; return *this;                               \
    4049        }
    41         bitfield operator&( bitfield other ) const {
    42                 bitfield q = other;
    43                 q &= *this;
    44                 return q;
    45         }
    46         bitfield operator|=( bitfield other ) {
    47                 val |= other.val; return *this;
    48         }
    49         bitfield operator|( bitfield other ) const {
    50                 bitfield q = other;
    51                 q |= *this;
    52                 return q;
    53         }
    54         bitfield operator-=( bitfield other ) {
    55                 val &= ~other.val; return *this;
    56         }
    57 };
    5850
    5951/// Adds default printing operator to a bitfield type.
    6052/// Include in definition to add print function, requires other bitfield operators.
    6153/// @param N  Number of bits in bitfield
    62 #define MakeBitfieldPrint( N ) \
    63         static const char* Names[]; \
    64  \
    65         void print( std::ostream & os ) const { \
    66                 if ( (*this).any() ) { \
    67                         for ( unsigned int i = 0; i < N; i += 1 ) { \
    68                                 if ( (*this)[i] ) { \
    69                                         os << Names[i] << ' '; \
    70                                 } \
    71                         } \
    72                 } \
     54#define MakeBitfieldPrint( N )                                         \
     55        static const char* Names[];                                        \
     56        void print( std::ostream & os ) const {                            \
     57                if ( (*this).any() ) {                                         \
     58                        for ( unsigned int i = 0; i < N; i += 1 ) {                \
     59                                if ( (*this)[i] ) {                                    \
     60                                        os << Names[i] << ' ';                             \
     61                                }                                                      \
     62                        }                                                          \
     63                }                                                              \
    7364        }
    7465
  • src/AST/Decl.hpp

    r768b3b4f rb78129a  
    122122        std::vector<ptr<DeclWithType>> assertions;
    123123
    124         NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
     124        NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, 
    125125                Type* b, Linkage::Spec spec = Linkage::Cforall )
    126126        : Decl( loc, name, storage, spec ), base( b ), parameters(), assertions() {}
     
    149149                Data( TypeDecl* d ) : kind( d->kind ), isComplete( d->sized ) {}
    150150                Data( Kind k, bool c ) : kind( k ), isComplete( c ) {}
    151                 Data( const Data& d1, const Data& d2 )
     151                Data( const Data& d1, const Data& d2 ) 
    152152                : kind( d1.kind ), isComplete( d1.isComplete || d2.isComplete ) {}
    153153
     
    158158        };
    159159
    160         TypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, Type* b,
     160        TypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, Type* b, 
    161161                Kind k, bool s, Type* i = nullptr )
    162162        : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == Ttype || s ), init( i ) {}
     
    174174class TypedefDecl final : public NamedTypeDecl {
    175175public:
    176         TypedefDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
     176        TypedefDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, 
    177177                Type* b, Linkage::Spec spec = Linkage::Cforall )
    178178        : NamedTypeDecl( loc, name, storage, b, spec ) {}
     
    275275};
    276276
    277 
    278 //=================================================================================================
    279 /// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
    280 /// remove only if there is a better solution
    281 /// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
    282 /// forward declarations
    283 inline void increment( const class Decl * node, Node::ref_type ref ) { node->increment(ref); }
    284 inline void decrement( const class Decl * node, Node::ref_type ref ) { node->decrement(ref); }
    285 inline void increment( const class DeclWithType * node, Node::ref_type ref ) { node->increment(ref); }
    286 inline void decrement( const class DeclWithType * node, Node::ref_type ref ) { node->decrement(ref); }
    287 inline void increment( const class ObjectDecl * node, Node::ref_type ref ) { node->increment(ref); }
    288 inline void decrement( const class ObjectDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    289 inline void increment( const class FunctionDecl * node, Node::ref_type ref ) { node->increment(ref); }
    290 inline void decrement( const class FunctionDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    291 inline void increment( const class AggregateDecl * node, Node::ref_type ref ) { node->increment(ref); }
    292 inline void decrement( const class AggregateDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    293 inline void increment( const class StructDecl * node, Node::ref_type ref ) { node->increment(ref); }
    294 inline void decrement( const class StructDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    295 inline void increment( const class UnionDecl * node, Node::ref_type ref ) { node->increment(ref); }
    296 inline void decrement( const class UnionDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    297 inline void increment( const class EnumDecl * node, Node::ref_type ref ) { node->increment(ref); }
    298 inline void decrement( const class EnumDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    299 inline void increment( const class TraitDecl * node, Node::ref_type ref ) { node->increment(ref); }
    300 inline void decrement( const class TraitDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    301 inline void increment( const class NamedTypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
    302 inline void decrement( const class NamedTypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    303 inline void increment( const class TypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
    304 inline void decrement( const class TypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    305 inline void increment( const class FtypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
    306 inline void decrement( const class FtypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    307 inline void increment( const class DtypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
    308 inline void decrement( const class DtypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    309 inline void increment( const class TypedefDecl * node, Node::ref_type ref ) { node->increment(ref); }
    310 inline void decrement( const class TypedefDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    311 inline void increment( const class AsmDecl * node, Node::ref_type ref ) { node->increment(ref); }
    312 inline void decrement( const class AsmDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    313 inline void increment( const class StaticAssertDecl * node, Node::ref_type ref ) { node->increment(ref); }
    314 inline void decrement( const class StaticAssertDecl * node, Node::ref_type ref ) { node->decrement(ref); }
    315 
    316277}
    317278
  • src/AST/FunctionSpec.hpp

    r768b3b4f rb78129a  
    3131
    3232        /// Bitflag type for storage classes
    33         struct spec_flags {
    34                 union {
    35                         unsigned int val;
    36                         struct {
    37                                 bool is_inline   : 1;
    38                                 bool is_noreturn : 1;
    39                                 bool is_fortran  : 1;
    40                         };
    41 
    42                         // MakeBitfieldPrint( NumSpecs )
     33        union Specs {
     34                unsigned int val;
     35                struct {
     36                        bool is_inline   : 1;
     37                        bool is_noreturn : 1;
     38                        bool is_fortran  : 1;
    4339                };
    4440
    45                 constexpr spec_flags( unsigned int val ) : val(val) {}
     41                MakeBitfield( Specs )
     42                MakeBitfieldPrint( NumSpecs )
    4643        };
    4744
    48         using Specs = bitfield<spec_flags>;
    4945}
    5046}
  • src/AST/Fwd.hpp

    r768b3b4f rb78129a  
    1616#pragma once
    1717
    18 #include "AST/Node.hpp"
    19 
    2018namespace ast {
    2119
     20class Node;
    2221class ParseNode;
    2322
     
    138137class TypeSubstitution;
    139138
    140 //=================================================================================================
    141 /// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
    142 /// remove only if there is a better solution
    143 /// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
    144 /// forward declarations
    145 inline void decrement( const class Node * node, Node::ref_type ref ) { node->decrement(ref); }
    146 inline void increment( const class Node * node, Node::ref_type ref ) { node->increment(ref); }
    147 inline void increment( const class ParseNode *, Node::ref_type );
    148 inline void decrement( const class ParseNode *, Node::ref_type );
    149 inline void increment( const class Decl *, Node::ref_type );
    150 inline void decrement( const class Decl *, Node::ref_type );
    151 inline void increment( const class DeclWithType *, Node::ref_type );
    152 inline void decrement( const class DeclWithType *, Node::ref_type );
    153 inline void increment( const class ObjectDecl *, Node::ref_type );
    154 inline void decrement( const class ObjectDecl *, Node::ref_type );
    155 inline void increment( const class FunctionDecl *, Node::ref_type );
    156 inline void decrement( const class FunctionDecl *, Node::ref_type );
    157 inline void increment( const class AggregateDecl *, Node::ref_type );
    158 inline void decrement( const class AggregateDecl *, Node::ref_type );
    159 inline void increment( const class StructDecl *, Node::ref_type );
    160 inline void decrement( const class StructDecl *, Node::ref_type );
    161 inline void increment( const class UnionDecl *, Node::ref_type );
    162 inline void decrement( const class UnionDecl *, Node::ref_type );
    163 inline void increment( const class EnumDecl *, Node::ref_type );
    164 inline void decrement( const class EnumDecl *, Node::ref_type );
    165 inline void increment( const class TraitDecl *, Node::ref_type );
    166 inline void decrement( const class TraitDecl *, Node::ref_type );
    167 inline void increment( const class NamedTypeDecl *, Node::ref_type );
    168 inline void decrement( const class NamedTypeDecl *, Node::ref_type );
    169 inline void increment( const class TypeDecl *, Node::ref_type );
    170 inline void decrement( const class TypeDecl *, Node::ref_type );
    171 inline void increment( const class FtypeDecl *, Node::ref_type );
    172 inline void decrement( const class FtypeDecl *, Node::ref_type );
    173 inline void increment( const class DtypeDecl *, Node::ref_type );
    174 inline void decrement( const class DtypeDecl *, Node::ref_type );
    175 inline void increment( const class TypedefDecl *, Node::ref_type );
    176 inline void decrement( const class TypedefDecl *, Node::ref_type );
    177 inline void increment( const class AsmDecl *, Node::ref_type );
    178 inline void decrement( const class AsmDecl *, Node::ref_type );
    179 inline void increment( const class StaticAssertDecl *, Node::ref_type );
    180 inline void decrement( const class StaticAssertDecl *, Node::ref_type );
    181 inline void increment( const class Stmt *, Node::ref_type );
    182 inline void decrement( const class Stmt *, Node::ref_type );
    183 inline void increment( const class CompoundStmt *, Node::ref_type );
    184 inline void decrement( const class CompoundStmt *, Node::ref_type );
    185 inline void increment( const class ExprStmt *, Node::ref_type );
    186 inline void decrement( const class ExprStmt *, Node::ref_type );
    187 inline void increment( const class AsmStmt *, Node::ref_type );
    188 inline void decrement( const class AsmStmt *, Node::ref_type );
    189 inline void increment( const class DirectiveStmt *, Node::ref_type );
    190 inline void decrement( const class DirectiveStmt *, Node::ref_type );
    191 inline void increment( const class IfStmt *, Node::ref_type );
    192 inline void decrement( const class IfStmt *, Node::ref_type );
    193 inline void increment( const class WhileStmt *, Node::ref_type );
    194 inline void decrement( const class WhileStmt *, Node::ref_type );
    195 inline void increment( const class ForStmt *, Node::ref_type );
    196 inline void decrement( const class ForStmt *, Node::ref_type );
    197 inline void increment( const class SwitchStmt *, Node::ref_type );
    198 inline void decrement( const class SwitchStmt *, Node::ref_type );
    199 inline void increment( const class CaseStmt *, Node::ref_type );
    200 inline void decrement( const class CaseStmt *, Node::ref_type );
    201 inline void increment( const class BranchStmt *, Node::ref_type );
    202 inline void decrement( const class BranchStmt *, Node::ref_type );
    203 inline void increment( const class ReturnStmt *, Node::ref_type );
    204 inline void decrement( const class ReturnStmt *, Node::ref_type );
    205 inline void increment( const class ThrowStmt *, Node::ref_type );
    206 inline void decrement( const class ThrowStmt *, Node::ref_type );
    207 inline void increment( const class TryStmt *, Node::ref_type );
    208 inline void decrement( const class TryStmt *, Node::ref_type );
    209 inline void increment( const class CatchStmt *, Node::ref_type );
    210 inline void decrement( const class CatchStmt *, Node::ref_type );
    211 inline void increment( const class FinallyStmt *, Node::ref_type );
    212 inline void decrement( const class FinallyStmt *, Node::ref_type );
    213 inline void increment( const class WaitForStmt *, Node::ref_type );
    214 inline void decrement( const class WaitForStmt *, Node::ref_type );
    215 inline void increment( const class WithStmt *, Node::ref_type );
    216 inline void decrement( const class WithStmt *, Node::ref_type );
    217 inline void increment( const class DeclStmt *, Node::ref_type );
    218 inline void decrement( const class DeclStmt *, Node::ref_type );
    219 inline void increment( const class NullStmt *, Node::ref_type );
    220 inline void decrement( const class NullStmt *, Node::ref_type );
    221 inline void increment( const class ImplicitCtorDtorStmt *, Node::ref_type );
    222 inline void decrement( const class ImplicitCtorDtorStmt *, Node::ref_type );
    223 inline void increment( const class Expr *, Node::ref_type );
    224 inline void decrement( const class Expr *, Node::ref_type );
    225 inline void increment( const class ApplicationExpr *, Node::ref_type );
    226 inline void decrement( const class ApplicationExpr *, Node::ref_type );
    227 inline void increment( const class UntypedExpr *, Node::ref_type );
    228 inline void decrement( const class UntypedExpr *, Node::ref_type );
    229 inline void increment( const class NameExpr *, Node::ref_type );
    230 inline void decrement( const class NameExpr *, Node::ref_type );
    231 inline void increment( const class AddressExpr *, Node::ref_type );
    232 inline void decrement( const class AddressExpr *, Node::ref_type );
    233 inline void increment( const class LabelAddressExpr *, Node::ref_type );
    234 inline void decrement( const class LabelAddressExpr *, Node::ref_type );
    235 inline void increment( const class CastExpr *, Node::ref_type );
    236 inline void decrement( const class CastExpr *, Node::ref_type );
    237 inline void increment( const class KeywordCastExpr *, Node::ref_type );
    238 inline void decrement( const class KeywordCastExpr *, Node::ref_type );
    239 inline void increment( const class VirtualCastExpr *, Node::ref_type );
    240 inline void decrement( const class VirtualCastExpr *, Node::ref_type );
    241 inline void increment( const class MemberExpr *, Node::ref_type );
    242 inline void decrement( const class MemberExpr *, Node::ref_type );
    243 inline void increment( const class UntypedMemberExpr *, Node::ref_type );
    244 inline void decrement( const class UntypedMemberExpr *, Node::ref_type );
    245 inline void increment( const class VariableExpr *, Node::ref_type );
    246 inline void decrement( const class VariableExpr *, Node::ref_type );
    247 inline void increment( const class ConstantExpr *, Node::ref_type );
    248 inline void decrement( const class ConstantExpr *, Node::ref_type );
    249 inline void increment( const class SizeofExpr *, Node::ref_type );
    250 inline void decrement( const class SizeofExpr *, Node::ref_type );
    251 inline void increment( const class AlignofExpr *, Node::ref_type );
    252 inline void decrement( const class AlignofExpr *, Node::ref_type );
    253 inline void increment( const class UntypedOffsetofExpr *, Node::ref_type );
    254 inline void decrement( const class UntypedOffsetofExpr *, Node::ref_type );
    255 inline void increment( const class OffsetofExpr *, Node::ref_type );
    256 inline void decrement( const class OffsetofExpr *, Node::ref_type );
    257 inline void increment( const class OffsetPackExpr *, Node::ref_type );
    258 inline void decrement( const class OffsetPackExpr *, Node::ref_type );
    259 inline void increment( const class AttrExpr *, Node::ref_type );
    260 inline void decrement( const class AttrExpr *, Node::ref_type );
    261 inline void increment( const class LogicalExpr *, Node::ref_type );
    262 inline void decrement( const class LogicalExpr *, Node::ref_type );
    263 inline void increment( const class ConditionalExpr *, Node::ref_type );
    264 inline void decrement( const class ConditionalExpr *, Node::ref_type );
    265 inline void increment( const class CommaExpr *, Node::ref_type );
    266 inline void decrement( const class CommaExpr *, Node::ref_type );
    267 inline void increment( const class TypeExpr *, Node::ref_type );
    268 inline void decrement( const class TypeExpr *, Node::ref_type );
    269 inline void increment( const class AsmExpr *, Node::ref_type );
    270 inline void decrement( const class AsmExpr *, Node::ref_type );
    271 inline void increment( const class ImplicitCopyCtorExpr *, Node::ref_type );
    272 inline void decrement( const class ImplicitCopyCtorExpr *, Node::ref_type );
    273 inline void increment( const class ConstructorExpr *, Node::ref_type );
    274 inline void decrement( const class ConstructorExpr *, Node::ref_type );
    275 inline void increment( const class CompoundLiteralExpr *, Node::ref_type );
    276 inline void decrement( const class CompoundLiteralExpr *, Node::ref_type );
    277 inline void increment( const class UntypedValofExpr *, Node::ref_type );
    278 inline void decrement( const class UntypedValofExpr *, Node::ref_type );
    279 inline void increment( const class RangeExpr *, Node::ref_type );
    280 inline void decrement( const class RangeExpr *, Node::ref_type );
    281 inline void increment( const class UntypedTupleExpr *, Node::ref_type );
    282 inline void decrement( const class UntypedTupleExpr *, Node::ref_type );
    283 inline void increment( const class TupleExpr *, Node::ref_type );
    284 inline void decrement( const class TupleExpr *, Node::ref_type );
    285 inline void increment( const class TupleIndexExpr *, Node::ref_type );
    286 inline void decrement( const class TupleIndexExpr *, Node::ref_type );
    287 inline void increment( const class TupleAssignExpr *, Node::ref_type );
    288 inline void decrement( const class TupleAssignExpr *, Node::ref_type );
    289 inline void increment( const class StmtExpr *, Node::ref_type );
    290 inline void decrement( const class StmtExpr *, Node::ref_type );
    291 inline void increment( const class UniqueExpr *, Node::ref_type );
    292 inline void decrement( const class UniqueExpr *, Node::ref_type );
    293 inline void increment( const class UntypedInitExpr *, Node::ref_type );
    294 inline void decrement( const class UntypedInitExpr *, Node::ref_type );
    295 inline void increment( const class InitExpr *, Node::ref_type );
    296 inline void decrement( const class InitExpr *, Node::ref_type );
    297 inline void increment( const class DeletedExpr *, Node::ref_type );
    298 inline void decrement( const class DeletedExpr *, Node::ref_type );
    299 inline void increment( const class DefaultArgExpr *, Node::ref_type );
    300 inline void decrement( const class DefaultArgExpr *, Node::ref_type );
    301 inline void increment( const class GenericExpr *, Node::ref_type );
    302 inline void decrement( const class GenericExpr *, Node::ref_type );
    303 inline void increment( const class Type *, Node::ref_type );
    304 inline void decrement( const class Type *, Node::ref_type );
    305 inline void increment( const class VoidType *, Node::ref_type );
    306 inline void decrement( const class VoidType *, Node::ref_type );
    307 inline void increment( const class BasicType *, Node::ref_type );
    308 inline void decrement( const class BasicType *, Node::ref_type );
    309 inline void increment( const class PointerType *, Node::ref_type );
    310 inline void decrement( const class PointerType *, Node::ref_type );
    311 inline void increment( const class ArrayType *, Node::ref_type );
    312 inline void decrement( const class ArrayType *, Node::ref_type );
    313 inline void increment( const class ReferenceType *, Node::ref_type );
    314 inline void decrement( const class ReferenceType *, Node::ref_type );
    315 inline void increment( const class QualifiedType *, Node::ref_type );
    316 inline void decrement( const class QualifiedType *, Node::ref_type );
    317 inline void increment( const class FunctionType *, Node::ref_type );
    318 inline void decrement( const class FunctionType *, Node::ref_type );
    319 inline void increment( const class ReferenceToType *, Node::ref_type );
    320 inline void decrement( const class ReferenceToType *, Node::ref_type );
    321 inline void increment( const class StructInstType *, Node::ref_type );
    322 inline void decrement( const class StructInstType *, Node::ref_type );
    323 inline void increment( const class UnionInstType *, Node::ref_type );
    324 inline void decrement( const class UnionInstType *, Node::ref_type );
    325 inline void increment( const class EnumInstType *, Node::ref_type );
    326 inline void decrement( const class EnumInstType *, Node::ref_type );
    327 inline void increment( const class TraitInstType *, Node::ref_type );
    328 inline void decrement( const class TraitInstType *, Node::ref_type );
    329 inline void increment( const class TypeInstType *, Node::ref_type );
    330 inline void decrement( const class TypeInstType *, Node::ref_type );
    331 inline void increment( const class TupleType *, Node::ref_type );
    332 inline void decrement( const class TupleType *, Node::ref_type );
    333 inline void increment( const class TypeofType *, Node::ref_type );
    334 inline void decrement( const class TypeofType *, Node::ref_type );
    335 inline void increment( const class AttrType *, Node::ref_type );
    336 inline void decrement( const class AttrType *, Node::ref_type );
    337 inline void increment( const class VarArgsType *, Node::ref_type );
    338 inline void decrement( const class VarArgsType *, Node::ref_type );
    339 inline void increment( const class ZeroType *, Node::ref_type );
    340 inline void decrement( const class ZeroType *, Node::ref_type );
    341 inline void increment( const class OneType *, Node::ref_type );
    342 inline void decrement( const class OneType *, Node::ref_type );
    343 inline void increment( const class GlobalScopeType *, Node::ref_type );
    344 inline void decrement( const class GlobalScopeType *, Node::ref_type );
    345 inline void increment( const class Designation *, Node::ref_type );
    346 inline void decrement( const class Designation *, Node::ref_type );
    347 inline void increment( const class Init *, Node::ref_type );
    348 inline void decrement( const class Init *, Node::ref_type );
    349 inline void increment( const class SingleInit *, Node::ref_type );
    350 inline void decrement( const class SingleInit *, Node::ref_type );
    351 inline void increment( const class ListInit *, Node::ref_type );
    352 inline void decrement( const class ListInit *, Node::ref_type );
    353 inline void increment( const class ConstructorInit *, Node::ref_type );
    354 inline void decrement( const class ConstructorInit *, Node::ref_type );
    355 inline void increment( const class Constant *, Node::ref_type );
    356 inline void decrement( const class Constant *, Node::ref_type );
    357 inline void increment( const class Label *, Node::ref_type );
    358 inline void decrement( const class Label *, Node::ref_type );
    359 inline void increment( const class Attribute *, Node::ref_type );
    360 inline void decrement( const class Attribute *, Node::ref_type );
    361 inline void increment( const class TypeSubstitution *, Node::ref_type );
    362 inline void decrement( const class TypeSubstitution *, Node::ref_type );
    363 
    364139typedef unsigned int UniqueId;
    365140
  • src/AST/Init.hpp

    r768b3b4f rb78129a  
    2828class Stmt;
    2929
    30 /// List of designator (NameExpr, VariableExpr, and ConstantExpr) expressions that specify an
     30/// List of designator (NameExpr, VariableExpr, and ConstantExpr) expressions that specify an 
    3131/// object being initialized
    3232class Designation final : public ParseNode {
     
    3434        std::vector<ptr<Expr>> designators;
    3535
    36         Designation( const CodeLocation& loc, std::vector<ptr<Expr>>&& ds = {} )
     36        Designation( const CodeLocation& loc, std::vector<ptr<Expr>>&& ds = {} ) 
    3737        : ParseNode( loc ), designators( std::move(ds) ) {}
    3838
     
    6060        ptr<Expr> value;
    6161
    62         SingleInit( const CodeLocation& loc, Expr* val, bool mc = false )
     62        SingleInit( const CodeLocation& loc, Expr* val, bool mc = false ) 
    6363        : Init( loc, mc ), value( val ) {}
    6464
     
    7777        std::vector<ptr<Designation>> designations;
    7878
    79         ListInit( const CodeLocation& loc, std::vector<ptr<Init>>&& is,
     79        ListInit( const CodeLocation& loc, std::vector<ptr<Init>>&& is, 
    8080                std::vector<ptr<Designation>>&& ds = {}, bool mc = false );
    81 
     81       
    8282        using iterator = std::vector<ptr<Init>>::iterator;
    8383        using const_iterator = std::vector<ptr<Init>>::const_iterator;
     
    9393
    9494/// Either a constructor expression or a C-style initializer.
    95 /// Should not be necessary to create manually; instead set `maybeConstructed` true on `SingleInit`
     95/// Should not be necessary to create manually; instead set `maybeConstructed` true on `SingleInit` 
    9696/// or `ListInit` if the object should be constructed.
    9797class ConstructorInit final : public Init {
     
    9999        ptr<Stmt> ctor;
    100100        ptr<Stmt> dtor;
    101         /// C-style initializer made up of SingleInit/ListInit nodes to use as a fallback if an
     101        /// C-style initializer made up of SingleInit/ListInit nodes to use as a fallback if an 
    102102        /// appropriate constructor definition is not found by the resolver.
    103103        ptr<Init> init;
     
    111111};
    112112
    113 
    114 //=================================================================================================
    115 /// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
    116 /// remove only if there is a better solution
    117 /// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
    118 /// forward declarations
    119 inline void increment( const class Init * node, Node::ref_type ref ) { node->increment( ref ); }
    120 inline void decrement( const class Init * node, Node::ref_type ref ) { node->decrement( ref ); }
    121 inline void increment( const class SingleInit * node, Node::ref_type ref ) { node->increment( ref ); }
    122 inline void decrement( const class SingleInit * node, Node::ref_type ref ) { node->decrement( ref ); }
    123 inline void increment( const class ListInit * node, Node::ref_type ref ) { node->increment( ref ); }
    124 inline void decrement( const class ListInit * node, Node::ref_type ref ) { node->decrement( ref ); }
    125 inline void increment( const class ConstructorInit * node, Node::ref_type ref ) { node->increment( ref ); }
    126 inline void decrement( const class ConstructorInit * node, Node::ref_type ref ) { node->decrement( ref ); }
    127113}
    128114
  • src/AST/Label.hpp

    r768b3b4f rb78129a  
    2525namespace ast {
    2626
    27 class Attribute;
     27        class Attribute;
    2828
    29 /// Named labels for statements
    30 class Label {
    31 public:
    32         CodeLocation location;
    33         std::string name;
    34         std::vector< ptr<Attribute> > attributes;
     29        /// Named labels for statements
     30        class Label {
     31        public:
     32                CodeLocation location;
     33                std::string name;
     34                std::vector< ptr<Attribute> > attributes;
    3535
    36         Label( CodeLocation loc, const std::string& name = "",
    37                 const std::vector<ptr<Attribute>>& attrs = std::vector<ptr<Attribute>>{} )
    38         : location( loc ), name( name ), attributes( attrs ) {}
     36                Label( CodeLocation loc, const std::string& name = "",
     37                        const std::vector<ptr<Attribute>>& attrs = std::vector<ptr<Attribute>>{} )
     38                : location( loc ), name( name ), attributes( attrs ) {}
    3939
    40         operator std::string () const { return name; }
    41         bool empty() { return name.empty(); }
    42 };
     40                operator std::string () const { return name; }
     41                bool empty() { return name.empty(); }
     42        };
    4343
    44 inline bool operator== ( const Label& l1, const Label& l2 ) { return l1.name == l2.name; }
    45 inline bool operator!= ( const Label& l1, const Label& l2 ) { return !(l1 == l2); }
    46 inline bool operator<  ( const Label& l1, const Label& l2 ) { return l1.name < l2.name; }
     44        inline bool operator== ( const Label& l1, const Label& l2 ) { return l1.name == l2.name; }
     45        inline bool operator!= ( const Label& l1, const Label& l2 ) { return !(l1 == l2); }
     46        inline bool operator<  ( const Label& l1, const Label& l2 ) { return l1.name < l2.name; }
    4747
    48 inline std::ostream& operator<< ( std::ostream& out, const Label& l ) { return out << l.name; }
    49 
    50 
    51 //=================================================================================================
    52 /// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
    53 /// remove only if there is a better solution
    54 /// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
    55 /// forward declarations
    56 inline void increment( const class Label * node, Node::ref_type ref ) { node->increment( ref ); }
    57 inline void decrement( const class Label * node, Node::ref_type ref ) { node->decrement( ref ); }
     48        inline std::ostream& operator<< ( std::ostream& out, const Label& l ) { return out << l.name; }
    5849
    5950}
  • src/AST/LinkageSpec.hpp

    r768b3b4f rb78129a  
    3535
    3636        /// Bitflag type for storage classes
    37         struct spec_flags {
    38                 union {
    39                         unsigned int val;
    40                         struct {
    41                                 bool is_mangled      : 1;
    42                                 bool is_generatable  : 1;
    43                                 bool is_overrideable : 1;
    44                                 bool is_builtin      : 1;
    45                                 bool is_gcc_builtin  : 1;
    46                         };
     37        union Spec {
     38                unsigned int val;
     39                struct {
     40                        bool is_mangled      : 1;
     41                        bool is_generatable  : 1;
     42                        bool is_overrideable : 1;
     43                        bool is_builtin      : 1;
     44                        bool is_gcc_builtin  : 1;
    4745                };
    4846
    49                 constexpr spec_flags( unsigned int val ) : val(val) {}
     47                MakeBitfield( Spec )
    5048        };
    51 
    52         using Spec = bitfield<spec_flags>;
    5349
    5450        /// If `cmd` = "C" returns `spec` with `is_mangled = false`.
  • src/AST/ParseNode.hpp

    r768b3b4f rb78129a  
    2222namespace ast {
    2323
    24 /// AST node with an included source location
    25 class ParseNode : public Node {
    26 public:
    27         CodeLocation location;
     24        /// AST node with an included source location
     25        class ParseNode : public Node {
     26        public:
     27                CodeLocation location;
    2828
    29         // Default constructor is deliberately omitted, all ParseNodes must have a location.
    30         // Escape hatch if needed is to explicitly pass a default-constructed location, but
    31         // this should be used sparingly.
     29                // Default constructor is deliberately omitted, all ParseNodes must have a location.
     30                // Escape hatch if needed is to explicitly pass a default-constructed location, but
     31                // this should be used sparingly.
    3232
    33         ParseNode( const CodeLocation& loc ) : Node(), location(loc) {}
     33                ParseNode( const CodeLocation& loc ) : Node(), location(loc) {}
    3434
    35         ParseNode( const ParseNode& o ) = default;
    36 };
     35                ParseNode( const ParseNode& o ) = default;
     36        };
    3737
    38 
    39 //=================================================================================================
    40 /// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
    41 /// remove only if there is a better solution
    42 /// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
    43 /// forward declarations
    44 inline void increment( const class ParseNode * node, Node::ref_type ref ) { node->increment( ref ); }
    45 inline void decrement( const class ParseNode * node, Node::ref_type ref ) { node->decrement( ref ); }
    4638}
    4739
  • src/AST/Pass.hpp

    r768b3b4f rb78129a  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
    3 //
    4 // The contents of this file are covered under the licence agreement in the
    5 // file "LICENCE" distributed with Cforall.
    6 //
    7 // Pass.hpp --
    8 //
    9 // Author           : Thierry Delisle
    10 // Created On       : Thu May 09 15::37::05 2019
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
    14 //
    15 
    161#pragma once
    17 // IWYU pragma: private, include "AST/Pass.hpp"
     2// IWYU pragma: private, include "Common/PassVisitor.h"
    183
    194#include <functional>
     
    216#include <stack>
    227
    23 #include "AST/Fwd.hpp"
    24 #include "AST/Node.hpp"
    25 #include "AST/Decl.hpp"
    26 #include "AST/Visitor.hpp"
    27 
    28 #include "SymTab/Indexer.h"
     8#include "Fwd.hpp"
     9#include "Node.hpp"
    2910
    3011// Private prelude header, needed for some of the magic tricks this class pulls off
    31 #include "AST/Pass.proto.hpp"
     12#include "Pass.proto.hpp"
    3213
    3314namespace ast {
     
    3920//
    4021// Several additional features are available through inheritance
    41 // | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the
    42 //                          current expression
     22// | WithTypeSubstitution - provides polymorphic TypeSubstitution * env for the current expression
    4323// | WithStmtsToAdd       - provides the ability to insert statements before or after the current
    4424//                          statement by adding new statements into stmtsToAddBefore or
    4525//                          stmtsToAddAfter respectively.
    46 // | WithDeclsToAdd       - provides the ability to insert declarations before or after the current
    47 //                          declarations by adding new DeclStmt into declsToAddBefore or
    48 //                          declsToAddAfter respectively.
    4926// | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children
    5027//                          to false in pre{visit,visit} to skip visiting children
     
    5330//                          automatically be restored to its previous value after the corresponding
    5431//                          postvisit/postmutate teminates.
    55 // | WithVisitorRef       - provides an pointer to the templated visitor wrapper
    56 // | WithIndexer          - provides indexer functionality (i.e. up-to-date symbol table)
    5732//-------------------------------------------------------------------------------------------------
    5833template< typename pass_t >
    5934class Pass final : public ast::Visitor {
    6035public:
    61         /// Forward any arguments to the pass constructor
    62         /// Propagate 'this' if necessary
    6336        template< typename... Args >
    6437        Pass( Args &&... args)
    65                 : pass( std::forward<Args>( args )... )
     38                : m_pass( std::forward<Args>( args )... )
    6639        {
    6740                // After the pass is constructed, check if it wants the have a pointer to the wrapping visitor
    6841                typedef Pass<pass_t> this_t;
    69                 this_t * const * visitor = __pass::visitor(pass, 0);
     42                this_t * const * visitor = __pass::visitor(m_pass, 0);
    7043                if(visitor) {
    7144                        *const_cast<this_t **>( visitor ) = this;
     
    7548        virtual ~Pass() = default;
    7649
    77         /// Storage for the actual pass
    78         pass_t pass;
    79 
    80         /// Visit function declarations
     50        pass_t m_pass;
     51
    8152        virtual DeclWithType *     visit( const ObjectDecl           * ) override final;
    8253        virtual DeclWithType *     visit( const FunctionDecl         * ) override final;
     
    174145        virtual TypeSubstitution * visit( const TypeSubstitution     * ) override final;
    175146
    176         friend void acceptAll( std::list< ptr<Decl> > & decls, Pass<pass_t>& visitor );
    177 private:
    178 
    179         bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(pass, 0); return ptr ? *ptr : true; }
    180 
    181 private:
    182         /// Logic to call the accept and mutate the parent if needed, delegates call to accept
     147private:
     148
     149        bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(m_pass, 0); return ptr ? *ptr : true; }
     150
     151private:
    183152        template<typename parent_t, typename child_t>
    184153        void maybe_accept(parent_t * & , typename parent_t::child_t *);
    185154
    186         Stmt * call_accept( const Stmt * );
    187         Expr * call_accept( const Expr * );
     155        ast::Statement  * call_accept( const ast::Statement * );
     156        ast::Expression * call_accept( const ast::Expression * );
    188157
    189158        template< template <class> class container_t >
    190         container_t< ptr<Stmt> > call_accept( const container_t< ptr<Stmt> > & );
     159        container_t< ast::ptr<ast::Statement> > call_accept( const container_t< ast::ptr<ast::Statement> > & );
    191160
    192161        template< template <class> class container_t, typename node_t >
    193         container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
    194 
    195 private:
    196         /// Internal RAII guard for indexer features
    197         struct guard_indexer {
    198                 guard_indexer( Pass<pass_t> & pass ): pass( pass ) { __pass::indexer::enter(pass, 0); }
    199                 ~guard_indexer()                                   { __pass::indexer::leave(pass, 0); }
     162        container_t< ast::ptr<node_t> > call_accept( const container_t< ast::ptr<node_t> > & container );
     163
     164private:
     165        struct indexer_guard {
    200166                Pass<pass_t> & pass;
     167
     168                indexer_guard( Pass<pass_t> & pass ) : pass( pass ) { __pass::indexer::enter(pass, 0); }
     169                ~indexer_guard()                                    { __pass::indexer::leave(pass, 0); }
    201170        };
    202171
    203         /// Internal RAII guard for scope features
    204         struct guard_scope {
    205                 guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); }
    206                 ~guard_scope()                                   { __pass::scope::leave(pass, 0); }
     172        indexer_guard make_indexer_guard() { return { *this }; }
     173
     174private:
     175        struct scope_guard {
    207176                Pass<pass_t> & pass;
     177
     178                scope_guard( Pass<pass_t> & pass ) : pass( pass ) { __pass::scope::enter(pass, 0); }
     179                ~scope_guard()                                    { __pass::scope::leave(pass, 0); }
    208180        };
    209 };
    210 
    211 template<typename pass_t>
    212 void acceptAll( std::list< ptr<Decl> >, Pass<pass_t>& visitor );
    213 
    214 //-------------------------------------------------------------------------------------------------
     181
     182        scope_guard make_scope_guard() { return { *this }; }
     183};
     184
     185//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     186// Guard value : RAII type to restore a value when the Pass finishes visiting this node
     187template<typename pass_t, typename T>
     188void GuardValue( pass_t * pass, T& val ) {
     189        pass->at_cleanup( [ val ]( void * newVal ) {
     190                * static_cast< T * >( newVal ) = val;
     191        }, static_cast< void * >( & val ) );
     192}
     193
     194//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    215195// PASS ACCESSORIES
    216 //-------------------------------------------------------------------------------------------------
     196//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     197
     198// Keep track of the type substitution
     199struct WithConstTypeSubstitution {
     200        const ast::TypeSubstitution * env = nullptr;
     201};
    217202
    218203template<typename T>
    219204using std_list = std::list<T>;
    220205
    221 /// Keep track of the polymorphic const TypeSubstitution * env for the current expression
    222 struct WithConstTypeSubstitution {
    223         const TypeSubstitution * env = nullptr;
    224 };
    225 
    226 /// Used if visitor requires added statements before or after the current node.
    227 /// The Pass template handles what *before* and *after* means automatically
     206// Used if visitor requires added statements before or after the current node.
     207// The Pass template handles what *before* and *after* means automatically
    228208template< template<class> class container_t = std_list >
    229209struct WithStmtsToAdd {
    230         container_t< ptr<Stmt> > stmtsToAddBefore;
    231         container_t< ptr<Stmt> > stmtsToAddAfter;
    232 };
    233 
    234 /// Used if visitor requires added declarations before or after the current node.
    235 /// The Pass template handles what *before* and *after* means automatically
     210        container_t< ast::ptr< ast::Statement > > stmtsToAddBefore;
     211        container_t< ast::ptr< ast::Statement > > stmtsToAddAfter;
     212};
     213
     214// Used if visitor requires added declarations before or after the current node.
     215// The Pass template handles what *before* and *after* means automatically
    236216template< template<class> class container_t = std_list >
    237217struct WithDeclsToAdd {
    238         container_t< ptr<Decl> > declsToAddBefore;
    239         container_t< ptr<Decl> > declsToAddAfter;
    240 };
    241 
    242 /// Use if visitation should stop at certain levels
    243 /// set visit_children false of all child nodes should be ignored
     218        ~WithDeclsToAdd() {
     219                assert( declsToAddBefore.empty() );
     220        }
     221
     222        container_t< ast::ptr< ast::Declaration > > declsToAddBefore;
     223        container_t< ast::ptr< ast::Declaration > > declsToAddAfter;
     224};
     225
     226// Use if visitation should stop at certain levels
     227// set visit_children false of all child nodes should be ignored
    244228struct WithShortCircuiting {
    245229        __pass::bool_ref visit_children;
    246230};
    247231
    248 /// Used to restore values/functions/etc. when the Pass finishes visiting this node
    249 class WithGuards {
    250         __pass::at_cleanup_t at_cleanup;
    251 
    252 public:
    253         /// When this node is finished being visited, restore the value of a variable
    254         template< typename T >
    255         void GuardValue( T& val ) {
    256                 at_cleanup( [ val ]( void * newVal ) {
    257                         * static_cast< T * >( newVal ) = val;
    258                 }, static_cast< void * >( & val ) );
    259         }
    260 
    261         /// On the object, all beginScope now and endScope when the current node is finished being visited
    262         template< typename T >
    263         void GuardScope( T& val ) {
    264                 val.beginScope();
    265                 at_cleanup( []( void * val ) {
    266                         static_cast< T * >( val )->endScope();
    267                 }, static_cast< void * >( & val ) );
    268         }
    269 
    270         /// When this node is finished being visited, call a function
    271         template< typename Func >
    272         void GuardAction( Func func ) {
    273                 at_cleanup( [func](void *) { func(); }, nullptr );
    274         }
    275 };
    276 
    277 /// Used to get a pointer to the pass with its wrapped type
    278 template<typename pass_t>
    279 struct WithVisitorRef {
    280         Pass<pass_t> * const visitor = nullptr;
    281 };
    282 
    283 /// Use when the templated visitor should update the indexer
     232// class WithGuards {
     233// protected:
     234//      WithGuards() = default;
     235//      ~WithGuards() = default;
     236
     237// public:
     238//      at_cleanup_t at_cleanup;
     239
     240//      template< typename T >
     241//      void GuardValue( T& val ) {
     242//              at_cleanup( [ val ]( void * newVal ) {
     243//                      * static_cast< T * >( newVal ) = val;
     244//              }, static_cast< void * >( & val ) );
     245//      }
     246
     247//      template< typename T >
     248//      void GuardScope( T& val ) {
     249//              val.beginScope();
     250//              at_cleanup( []( void * val ) {
     251//                      static_cast< T * >( val )->endScope();
     252//              }, static_cast< void * >( & val ) );
     253//      }
     254
     255//      template< typename Func >
     256//      void GuardAction( Func func ) {
     257//              at_cleanup( [func](__attribute__((unused)) void *) { func(); }, nullptr );
     258//      }
     259// };
     260
     261// template<typename pass_type>
     262// class WithVisitorRef {
     263// protected:
     264//      WithVisitorRef() {}
     265//      ~WithVisitorRef() {}
     266
     267// public:
     268//      PassVisitor<pass_type> * const visitor = nullptr;
     269// };
     270
    284271struct WithIndexer {
    285272        SymTab::Indexer indexer;
  • src/AST/Pass.impl.hpp

    r768b3b4f rb78129a  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
    3 //
    4 // The contents of this file are covered under the licence agreement in the
    5 // file "LICENCE" distributed with Cforall.
    6 //
    7 // Pass.impl.hpp --
    8 //
    9 // Author           : Thierry Delisle
    10 // Created On       : Thu May 09 15::37::05 2019
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
    14 //
    15 
    161#pragma once
    17 // IWYU pragma: private, include "AST/Pass.hpp"
     2// IWYU pragma: private, include "Pass.hpp"
    183
    194#define VISIT_START( node ) \
    20         using namespace ast; \
    215        /* back-up the visit children */ \
    22         __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
     6        __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(m_pass, 0) ); \
    237        /* setup the scope for passes that want to run code at exit */ \
    24         __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (pass, 0) ); \
     8        __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (m_pass, 0) ); \
    259        /* call the implementation of the previsit of this pass */ \
    26         __pass::previsit( pass, node, 0 );
     10        __pass::previsit( m_pass, node, 0 );
    2711
    2812#define VISIT( code ) \
     
    11498
    11599        template< typename pass_t >
    116         ast::Expr * Pass< pass_t >::call_accept( const ast::Expr * expr ) {
     100        ast::Expression * Pass< pass_t >::call_accept( const ast::Expression * expr ) {
    117101                __pedantic_pass_assert( __visit_children() );
    118102                __pedantic_pass_assert( expr );
    119103
    120                 const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
     104                const ast::TypeSubstitution ** env_ptr = __pass::env( m_pass, 0);
    121105                if ( env_ptr && expr->env ) {
    122106                        *env_ptr = expr->env;
     
    127111
    128112        template< typename pass_t >
    129         Stmt * Pass< pass_t >::call_accept( const Stmt * stmt ) {
     113        ast::Statement * Pass< pass_t >::call_accept( const ast::Statement * stmt ) {
    130114                __pedantic_pass_assert( __visit_children() );
    131115                __pedantic_pass_assert( stmt );
     116
     117                // add a few useful symbols to the scope
     118                using __pass::empty;
     119                using decls_t = typename std::remove_pointer< decltype(__decls_before()) >::type;
     120                using stmts_t = typename std::remove_pointer< decltype(__stmts_before()) >::type;
     121
     122                // get the stmts/decls that will need to be spliced in
     123                auto stmts_before = __pass::stmtsToAddBefore( m_pass, 0);
     124                auto stmts_after  = __pass::stmtsToAddAfter ( m_pass, 0);
     125                auto decls_before = __pass::declsToAddBefore( m_pass, 0);
     126                auto decls_after  = __pass::declsToAddAfter ( m_pass, 0);
     127
     128                // These may be modified by subnode but most be restored once we exit this statemnet.
     129                ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( m_pass, 0);  );
     130                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
     131                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after  );
     132                ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > __old_stmts_before( decls_before );
     133                ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after  );
     134
     135                // Now is the time to actually visit the node
     136                ast::Statement * nstmt = stmt->accept( *this );
     137
     138                // If the pass doesn't want to add anything then we are done
     139                if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
     140                        return nstmt;
     141                }
     142
     143                // Make sure that it is either adding statements or declartions but not both
     144                // this is because otherwise the order would be awkward to predict
     145                assert(( empty( stmts_before ) && empty( stmts_after ))
     146                    || ( empty( decls_before ) && empty( decls_after )) );
     147
     148                // Create a new Compound Statement to hold the new decls/stmts
     149                ast::CompoundStmt * compound = new ast::CompoundStmt( parent->*child.location );
     150
     151                // Take all the declarations that go before
     152                __pass::take_all( std::back_inserter( compound->kids ), decls_before );
     153                __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
     154
     155                // Insert the original declaration
     156                compound->kids.push_back( nstmt );
     157
     158                // Insert all the declarations that go before
     159                __pass::take_all( std::back_inserter( compound->kids ), decls_after );
     160                __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
     161
     162                return compound;
     163        }
     164
     165        template< typename pass_t >
     166        template< template <class> class container_t >
     167        container_t< ast::ptr<ast::Statement> > Pass< pass_t >::call_accept( const container_t< ast::ptr<ast::Statement> > & statements ) {
     168                __pedantic_pass_assert( __visit_children() );
     169                if( statements.empty() ) return {};
     170
     171                // We are going to aggregate errors for all these statements
     172                SemanticErrorException errors;
    132173
    133174                // add a few useful symbols to the scope
     
    141182
    142183                // These may be modified by subnode but most be restored once we exit this statemnet.
    143                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( pass, 0);  );
    144184                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
    145185                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after  );
     
    147187                ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after  );
    148188
    149                 // Now is the time to actually visit the node
    150                 ast::Statement * nstmt = stmt->accept( *this );
    151 
    152                 // If the pass doesn't want to add anything then we are done
    153                 if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
    154                         return nstmt;
    155                 }
    156 
    157                 // Make sure that it is either adding statements or declartions but not both
    158                 // this is because otherwise the order would be awkward to predict
    159                 assert(( empty( stmts_before ) && empty( stmts_after ))
    160                     || ( empty( decls_before ) && empty( decls_after )) );
    161 
    162                 // Create a new Compound Statement to hold the new decls/stmts
    163                 ast::CompoundStmt * compound = new ast::CompoundStmt( parent->*child.location );
    164 
    165                 // Take all the declarations that go before
    166                 __pass::take_all( std::back_inserter( compound->kids ), decls_before );
    167                 __pass::take_all( std::back_inserter( compound->kids ), stmts_before );
    168 
    169                 // Insert the original declaration
    170                 compound->kids.push_back( nstmt );
    171 
    172                 // Insert all the declarations that go before
    173                 __pass::take_all( std::back_inserter( compound->kids ), decls_after );
    174                 __pass::take_all( std::back_inserter( compound->kids ), stmts_after );
    175 
    176                 return compound;
    177         }
    178 
    179         template< typename pass_t >
    180         template< template <class> class container_t >
    181         container_t< ptr<Stmt> > Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    182                 __pedantic_pass_assert( __visit_children() );
    183                 if( statements.empty() ) return {};
    184 
    185                 // We are going to aggregate errors for all these statements
    186                 SemanticErrorException errors;
    187 
    188                 // add a few useful symbols to the scope
    189                 using __pass::empty;
    190 
    191                 // get the stmts/decls that will need to be spliced in
    192                 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
    193                 auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
    194                 auto decls_before = __pass::declsToAddBefore( pass, 0);
    195                 auto decls_after  = __pass::declsToAddAfter ( pass, 0);
    196 
    197                 // These may be modified by subnode but most be restored once we exit this statemnet.
    198                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
    199                 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after  );
    200                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > __old_stmts_before( decls_before );
    201                 ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after  );
    202 
    203189                // update pass statitistics
    204190                pass_visitor_stats.depth++;
     
    207193
    208194                bool mutated = false;
    209                 container_t< ptr<Stmt> > new_kids;
    210                 for( const Stmt * stmt : statements ) {
     195                container_t<ast::ptr< ast::Statement >> new_kids;
     196                for( const ast::Statement * stmt : statements ) {
    211197                        try {
    212198                                __pedantic_pass_assert( stmt );
     
    283269//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    284270
    285 template< typename pass_t >
    286 inline void ast::acceptAll( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
    287         // We are going to aggregate errors for all these statements
    288         SemanticErrorException errors;
    289 
    290         // add a few useful symbols to the scope
    291         using __pass::empty;
    292 
    293         // get the stmts/decls that will need to be spliced in
    294         auto decls_before = __pass::declsToAddBefore( pass, 0);
    295         auto decls_after  = __pass::declsToAddAfter ( pass, 0);
    296 
    297         // update pass statitistics
    298         pass_visitor_stats.depth++;
    299         pass_visitor_stats.max->push(pass_visitor_stats.depth);
    300         pass_visitor_stats.avg->push(pass_visitor_stats.depth);
    301 
    302         for ( std::list< ast::ptr<ast::Decl> >::iterator i = decls.begin(); ; ++i ) {
    303                 // splice in new declarations after previous decl
    304                 if ( !empty( decls_after ) ) { decls.splice( i, *decls_after ); }
    305 
    306                 if ( i == decls.end() ) break;
    307 
    308                 try {
    309                         // run visitor on declaration
    310                         ast::ptr<ast::Decl> & node = *i;
    311                         assert( node );
    312                         node = node->accept( visitor );
    313                 }
    314                 catch( SemanticErrorException &e ) {
    315                         errors.append( e );
    316                 }
    317 
    318                 // splice in new declarations before current decl
    319                 if ( !empty( decls_before ) ) { decls.splice( i, *decls_before ); }
    320         }
    321         pass_visitor_stats.depth--;
    322         if ( !errors.isEmpty() ) { throw errors; }
    323 }
    324 
    325271// A NOTE ON THE ORDER OF TRAVERSAL
    326272//
     
    343289// ObjectDecl
    344290template< typename pass_t >
    345 ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
     291ast::DeclarationWithType * Pass< pass_t >::mutate( ast::ObjectDecl * node ) {
    346292        VISIT_START( node );
    347293
    348294        VISIT(
    349295                {
    350                         indexer_guard guard { *this };
    351                         maybe_accept( node, ObjectDecl::type );
    352                 }
    353                 maybe_accept( node, ObjectDecl::init          );
    354                 maybe_accept( node, ObjectDecl::bitfieldWidth );
    355                 maybe_accept( node, ObjectDecl::attributes    );
     296                        auto guard = make_indexer_guard();
     297                        maybe_accept( node, ast::ObjectDecl::type );
     298                }
     299                maybe_accept( node, ast::ObjectDecl::init          );
     300                maybe_accept( node, ast::ObjectDecl::bitfieldWidth );
     301                maybe_accept( node, ast::ObjectDecl::attributes    );
    356302        )
    357303
    358         __pass::indexer::AddId( pass, 0, node );
    359 
    360         VISIT_END( DeclWithType, node );
     304        __pass::indexer::AddId( m_pass, 0, node );
     305
     306        VISIT_END( DeclarationWithType, node );
    361307}
    362308
     
    364310// Attribute
    365311template< typename pass_type >
    366 ast::Attribute * ast::Pass< pass_type >::visit( const ast::Attribute * node  )  {
     312ast::Attribute * ast::Pass< pass_type >::visit( ast::ptr<ast::Attribute> & node  )  {
    367313        VISIT_START(node);
    368314
     
    377323// TypeSubstitution
    378324template< typename pass_type >
    379 TypeSubstitution * PassVisitor< pass_type >::mutate( const TypeSubstitution * node ) {
     325TypeSubstitution * PassVisitor< pass_type >::mutate( TypeSubstitution * node ) {
    380326        MUTATE_START( node );
    381327
  • src/AST/Pass.proto.hpp

    r768b3b4f rb78129a  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
    3 //
    4 // The contents of this file are covered under the licence agreement in the
    5 // file "LICENCE" distributed with Cforall.
    6 //
    7 // Pass.impl.hpp --
    8 //
    9 // Author           : Thierry Delisle
    10 // Created On       : Thu May 09 15::37::05 2019
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
    14 //
    15 
    161#pragma once
    172// IWYU pragma: private, include "Pass.hpp"
    183
    194namespace ast {
    20 template<typename pass_type>
    21 class Pass;
    22 
    23 namespace __pass {
    24         typedef std::function<void( void * )> cleanup_func_t;
    25         typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t;
    26 
    27 
    28         // boolean reference that may be null
    29         // either refers to a boolean value or is null and returns true
    30         class bool_ref {
    31         public:
    32                 bool_ref() = default;
    33                 ~bool_ref() = default;
    34 
    35                 operator bool() { return m_ref ? *m_ref : true; }
    36                 bool operator=( bool val ) { assert(m_ref); return *m_ref = val; }
    37 
    38         private:
    39 
    40                 friend class visit_children_guard;
    41 
    42                 bool * set( bool * val ) {
    43                         bool * prev = m_ref;
    44                         m_ref = val;
    45                         return prev;
     5        template<typename pass_type>
     6        class Pass;
     7
     8        namespace __pass {
     9                typedef std::function<void( void * )> cleanup_func_t;
     10                typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t;
     11
     12
     13                // boolean reference that may be null
     14                // either refers to a boolean value or is null and returns true
     15                class bool_ref {
     16                public:
     17                        bool_ref() = default;
     18                        ~bool_ref() = default;
     19
     20                        operator bool() { return m_ref ? *m_ref : true; }
     21                        bool operator=( bool val ) { assert(m_ref); return *m_ref = val; }
     22
     23                private:
     24
     25                        friend class visit_children_guard;
     26
     27                        bool * set( bool * val ) {
     28                                bool * prev = m_ref;
     29                                m_ref = val;
     30                                return prev;
     31                        }
     32
     33                        bool * m_ref = nullptr;
     34                };
     35
     36                // Implementation of the guard value
     37                // Created inside the visit scope
     38                class guard_value {
     39                public:
     40                        guard_value( at_cleanup_t * at_cleanup ) {
     41                                if( at_cleanup ) {
     42                                        *at_cleanup = [this]( cleanup_func_t && func, void* val ) {
     43                                                push( std::move( func ), val );
     44                                        };
     45                                }
     46                        }
     47
     48                        ~guard_value() {
     49                                while( !cleanups.empty() ) {
     50                                        auto& cleanup = cleanups.top();
     51                                        cleanup.func( cleanup.val );
     52                                        cleanups.pop();
     53                                }
     54                        }
     55
     56                        void push( cleanup_func_t && func, void* val ) {
     57                                cleanups.emplace( std::move(func), val );
     58                        }
     59
     60                private:
     61                        struct cleanup_t {
     62                                cleanup_func_t func;
     63                                void * val;
     64
     65                                cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {}
     66                        };
     67
     68                        std::stack< cleanup_t > cleanups;
     69                };
     70
     71                // Guard structure implementation for whether or not children should be visited
     72                class visit_children_guard {
     73                public:
     74
     75                        visit_children_guard( bool_ref * ref )
     76                                : m_val ( true )
     77                                , m_prev( ref ? ref->set( &m_val ) : nullptr )
     78                                , m_ref ( ref )
     79                        {}
     80
     81                        ~visit_children_guard() {
     82                                if( m_ref ) {
     83                                        m_ref->set( m_prev );
     84                                }
     85                        }
     86
     87                        operator bool() { return m_val; }
     88
     89                private:
     90                        bool       m_val;
     91                        bool     * m_prev;
     92                        bool_ref * m_ref;
     93                };
     94
     95                //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     96                // Deep magic (a.k.a template meta programming) to make the templated visitor work
     97                // Basically the goal is to make 2 previsit
     98                // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of
     99                //     'pass.previsit( node )' that compiles will be used for that node for that type
     100                //     This requires that this option only compile for passes that actually define an appropriate visit.
     101                //     SFINAE will make sure the compilation errors in this function don't halt the build.
     102                //     See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE
     103                // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing.
     104                //     This is needed only to eliminate the need for passes to specify any kind of handlers.
     105                //     The second implementation only works because it has a lower priority. This is due to the bogus last parameter.
     106                //     The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0
     107                //     the first implementation takes priority in regards to overloading.
     108                //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     109                // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
     110                template<typename pass_t, typename node_t>
     111                static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
     112                        node = pass.previsit( node );
     113                        assert(node);
    46114                }
    47115
    48                 bool * m_ref = nullptr;
    49         };
    50 
    51         // Implementation of the guard value
    52         // Created inside the visit scope
    53         class guard_value {
    54         public:
    55                 /// Push onto the cleanup
    56                 guard_value( at_cleanup_t * at_cleanup ) {
    57                         if( at_cleanup ) {
    58                                 *at_cleanup = [this]( cleanup_func_t && func, void* val ) {
    59                                         push( std::move( func ), val );
    60                                 };
    61                         }
     116                template<typename pass_t, typename node_t>
     117                static inline auto previsit( pass_t &, const node_t *, long ) {}
     118
     119                // PostVisit : never mutates the passed pointer but may return a different node
     120                template<typename pass_t, typename node_t>
     121                static inline auto postvisit( pass_t & pass, const node_t * node, int ) -> decltype( pass.postvisit( node ), (const node_t *)nullptr ) {
     122                        return pass.postvisit( node );
    62123                }
    63124
    64                 ~guard_value() {
    65                         while( !cleanups.empty() ) {
    66                                 auto& cleanup = cleanups.top();
    67                                 cleanup.func( cleanup.val );
    68                                 cleanups.pop();
    69                         }
    70                 }
    71 
    72                 void push( cleanup_func_t && func, void* val ) {
    73                         cleanups.emplace( std::move(func), val );
    74                 }
    75 
    76         private:
    77                 struct cleanup_t {
    78                         cleanup_func_t func;
    79                         void * val;
    80 
    81                         cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {}
    82                 };
    83 
    84                 std::stack< cleanup_t > cleanups;
    85         };
    86 
    87         // Guard structure implementation for whether or not children should be visited
    88         class visit_children_guard {
    89         public:
    90 
    91                 visit_children_guard( bool_ref * ref )
    92                         : m_val ( true )
    93                         , m_prev( ref ? ref->set( &m_val ) : nullptr )
    94                         , m_ref ( ref )
    95                 {}
    96 
    97                 ~visit_children_guard() {
    98                         if( m_ref ) {
    99                                 m_ref->set( m_prev );
    100                         }
    101                 }
    102 
    103                 operator bool() { return m_val; }
    104 
    105         private:
    106                 bool       m_val;
    107                 bool     * m_prev;
    108                 bool_ref * m_ref;
    109         };
    110 
    111         //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    112         // Deep magic (a.k.a template meta programming) to make the templated visitor work
    113         // Basically the goal is to make 2 previsit
    114         // 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of
    115         //     'pass.previsit( node )' that compiles will be used for that node for that type
    116         //     This requires that this option only compile for passes that actually define an appropriate visit.
    117         //     SFINAE will make sure the compilation errors in this function don't halt the build.
    118         //     See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE
    119         // 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing.
    120         //     This is needed only to eliminate the need for passes to specify any kind of handlers.
    121         //     The second implementation only works because it has a lower priority. This is due to the bogus last parameter.
    122         //     The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0
    123         //     the first implementation takes priority in regards to overloading.
    124         //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    125         // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
    126         template<typename pass_t, typename node_t>
    127         static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
    128                 node = pass.previsit( node );
    129                 assert(node);
    130         }
    131 
    132         template<typename pass_t, typename node_t>
    133         static inline auto previsit( pass_t &, const node_t *, long ) {}
    134 
    135         // PostVisit : never mutates the passed pointer but may return a different node
    136         template<typename pass_t, typename node_t>
    137         static inline auto postvisit( pass_t & pass, const node_t * node, int ) -> decltype( pass.postvisit( node ), (const node_t *)nullptr ) {
    138                 return pass.postvisit( node );
    139         }
    140 
    141         template<typename pass_t, typename node_t>
    142         static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
    143 
    144         //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    145         // Deep magic (a.k.a template meta programming) continued
    146         // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit
    147         // from in order to get extra functionallity for example
    148         // class ErrorChecker : WithShortCircuiting { ... };
    149         // Pass<ErrorChecker> checker;
    150         // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting
    151         // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched
    152         //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    153         // For several accessories, the feature is enabled by detecting that a specific field is present
    154         // Use a macro the encapsulate the logic of detecting a particular field
    155         // The type is not strictly enforced but does match the accessory
    156         #define FIELD_PTR( name, default_type ) \
    157         template< typename pass_t > \
    158         static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
    159         \
    160         template< typename pass_t > \
    161         static inline default_type * name( pass_t &, long ) { return nullptr; }
    162 
    163         // List of fields and their expected types
    164         FIELD_PTR( env, const ast::TypeSubstitution )
    165         FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
    166         FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
    167         FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > )
    168         FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > )
    169         FIELD_PTR( visit_children, __pass::bool_ref )
    170         FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    171         FIELD_PTR( visitor, ast::Pass<pass_t> * const )
    172 
    173         // Remove the macro to make sure we don't clash
    174         #undef FIELD_PTR
    175 
    176         // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
    177         // All passes which have such functions are assumed desire this behaviour
    178         // detect it using the same strategy
    179         namespace scope {
    180                 template<typename pass_t>
    181                 static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {
    182                         pass.beginScope();
    183                 }
    184 
    185                 template<typename pass_t>
    186                 static inline void enter( pass_t &, long ) {}
    187 
    188                 template<typename pass_t>
    189                 static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {
    190                         pass.endScope();
    191                 }
    192 
    193                 template<typename pass_t>
    194                 static inline void leave( pass_t &, long ) {}
    195         };
    196 
    197         // Finally certain pass desire an up to date indexer automatically
    198         // detect the presence of a member name indexer and call all the members appropriately
    199         namespace indexer {
    200                 // Some simple scoping rules
    201                 template<typename pass_t>
    202                 static inline auto enter( pass_t & pass, int ) -> decltype( pass.indexer.enterScope(), void() ) {
    203                         pass.indexer.enterScope();
    204                 }
    205 
    206                 template<typename pass_t>
    207                 static inline auto enter( pass_t &, long ) {}
    208 
    209                 template<typename pass_t>
    210                 static inline auto leave( pass_t & pass, int ) -> decltype( pass.indexer.leaveScope(), void() ) {
    211                         pass.indexer.leaveScope();
    212                 }
    213 
    214                 template<typename pass_t>
    215                 static inline auto leave( pass_t &, long ) {}
    216 
    217                 // The indexer has 2 kind of functions mostly, 1 argument and 2 arguments
    218                 // Create macro to condense these common patterns
    219                 #define INDEXER_FUNC1( func, type ) \
    220                 template<typename pass_t> \
    221                 static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.indexer.func( arg ), void() ) {\
    222                         pass.indexer.func( arg ); \
    223                 } \
     125                template<typename pass_t, typename node_t>
     126                static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
     127
     128                //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     129                // Deep magic (a.k.a template meta programming) continued
     130                // To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit
     131                // from in order to get extra functionallity for example
     132                // class ErrorChecker : WithShortCircuiting { ... };
     133                // Pass<ErrorChecker> checker;
     134                // this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting
     135                // Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched
     136                //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     137                // For several accessories, the feature is enabled by detecting that a specific field is present
     138                // Use a macro the encapsulate the logic of detecting a particular field
     139                // The type is not strictly enforced but does match the accessory
     140                #define FIELD_PTR( name, default_type ) \
     141                template< typename pass_t > \
     142                static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
    224143                \
    225                 template<typename pass_t> \
    226                 static inline void func( pass_t &, long, type ) {}
    227 
    228                 #define INDEXER_FUNC2( func, type1, type2 ) \
    229                 template<typename pass_t> \
    230                 static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.indexer.func( arg1, arg2 ), void () ) {\
    231                         pass.indexer.func( arg1, arg2 ); \
    232                 } \
     144                template< typename pass_t > \
     145                static inline default_type * name( pass_t &, long ) { return nullptr; }
     146
     147                // List of fields and their expected types
     148                FIELD_PTR( env, const ast::TypeSubstitution )
     149                FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
     150                FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
     151                FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > )
     152                FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > )
     153                FIELD_PTR( visit_children, __pass::bool_ref )
     154                FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
     155                FIELD_PTR( visitor, ast::Pass<pass_t> * const )
     156
     157                // Remove the macro to make sure we don't clash
     158                #undef FIELD_PTR
     159
     160                // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
     161                // All passes which have such functions are assumed desire this behaviour
     162                // detect it using the same strategy
     163                namespace scope {
     164                        template<typename pass_t>
     165                        static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {
     166                                pass.beginScope();
     167                        }
     168
     169                        template<typename pass_t>
     170                        static inline void enter( pass_t &, long ) {}
     171
     172                        template<typename pass_t>
     173                        static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {
     174                                pass.endScope();
     175                        }
     176
     177                        template<typename pass_t>
     178                        static inline void leave( pass_t &, long ) {}
     179                };
     180
     181                // Finally certain pass desire an up to date indexer automatically
     182                // detect the presence of a member name indexer and call all the members appropriately
     183                namespace indexer {
     184                        // Some simple scoping rules
     185                        template<typename pass_t>
     186                        static inline auto enter( pass_t & pass, int ) -> decltype( pass.indexer.enterScope(), void() ) {
     187                                pass.indexer.enterScope();
     188                        }
     189
     190                        template<typename pass_t>
     191                        static inline auto enter( pass_t &, long ) {}
     192
     193                        template<typename pass_t>
     194                        static inline auto leave( pass_t & pass, int ) -> decltype( pass.indexer.leaveScope(), void() ) {
     195                                pass.indexer.leaveScope();
     196                        }
     197
     198                        template<typename pass_t>
     199                        static inline auto leave( pass_t &, long ) {}
     200
     201                        // The indexer has 2 kind of functions mostly, 1 argument and 2 arguments
     202                        // Create macro to condense these common patterns
     203                        #define INDEXER_FUNC1( func, type ) \
     204                        template<typename pass_t> \
     205                        static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.indexer.func( arg ), void() ) {\
     206                                pass.indexer.func( arg ); \
     207                        } \
    233208                        \
    234                 template<typename pass_t> \
    235                 static inline void func( pass_t &, long, type1, type2 ) {}
    236 
    237                 INDEXER_FUNC1( addId     , DeclWithType *  );
    238                 INDEXER_FUNC1( addType   , NamedTypeDecl * );
    239                 INDEXER_FUNC1( addStruct , StructDecl *    );
    240                 INDEXER_FUNC1( addEnum   , EnumDecl *      );
    241                 INDEXER_FUNC1( addUnion  , UnionDecl *     );
    242                 INDEXER_FUNC1( addTrait  , TraitDecl *     );
    243                 INDEXER_FUNC2( addWith   , std::list< Expression * > &, Node * );
    244 
    245                 // A few extra functions have more complicated behaviour, they are hand written
    246                 // template<typename pass_t>
    247                 // static inline auto addStructFwd( pass_t & pass, int, ast::StructDecl * decl ) -> decltype( pass.indexer.addStruct( decl ), void() ) {
    248                 //      ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
    249                 //      fwd->parameters = decl->parameters;
    250                 //      pass.indexer.addStruct( fwd );
    251                 // }
    252 
    253                 // template<typename pass_t>
    254                 // static inline void addStructFwd( pass_t &, long, ast::StructDecl * ) {}
    255 
    256                 // template<typename pass_t>
    257                 // static inline auto addUnionFwd( pass_t & pass, int, ast::UnionDecl * decl ) -> decltype( pass.indexer.addUnion( decl ), void() ) {
    258                 //      UnionDecl * fwd = new UnionDecl( decl->name );
    259                 //      fwd->parameters = decl->parameters;
    260                 //      pass.indexer.addUnion( fwd );
    261                 // }
    262 
    263                 // template<typename pass_t>
    264                 // static inline void addUnionFwd( pass_t &, long, ast::UnionDecl * ) {}
    265 
    266                 // template<typename pass_t>
    267                 // static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.indexer.addStruct( str ), void() ) {
    268                 //      if ( ! pass.indexer.lookupStruct( str ) ) {
    269                 //              pass.indexer.addStruct( str );
    270                 //      }
    271                 // }
    272 
    273                 // template<typename pass_t>
    274                 // static inline void addStruct( pass_t &, long, const std::string & ) {}
    275 
    276                 // template<typename pass_t>
    277                 // static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.indexer.addUnion( str ), void() ) {
    278                 //      if ( ! pass.indexer.lookupUnion( str ) ) {
    279                 //              pass.indexer.addUnion( str );
    280                 //      }
    281                 // }
    282 
    283                 // template<typename pass_t>
    284                 // static inline void addUnion( pass_t &, long, const std::string & ) {}
    285 
    286                 #undef INDEXER_FUNC1
    287                 #undef INDEXER_FUNC2
     209                        template<typename pass_t> \
     210                        static inline void func( pass_t &, long, type ) {}
     211
     212                        #define INDEXER_FUNC2( func, type1, type2 ) \
     213                        template<typename pass_t> \
     214                        static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.indexer.func( arg1, arg2 ), void () ) {\
     215                                pass.indexer.func( arg1, arg2 ); \
     216                        } \
     217                         \
     218                        template<typename pass_t> \
     219                        static inline void func( pass_t &, long, type1, type2 ) {}
     220
     221                        INDEXER_FUNC1( addId     , DeclarationWithType *       );
     222                        INDEXER_FUNC1( addType   , NamedTypeDecl *             );
     223                        INDEXER_FUNC1( addStruct , StructDecl *                );
     224                        INDEXER_FUNC1( addEnum   , EnumDecl *                  );
     225                        INDEXER_FUNC1( addUnion  , UnionDecl *                 );
     226                        INDEXER_FUNC1( addTrait  , TraitDecl *                 );
     227                        INDEXER_FUNC2( addWith   , std::list< Expression * > &, BaseSyntaxNode * );
     228
     229                        // A few extra functions have more complicated behaviour, they are hand written
     230                        template<typename pass_t>
     231                        static inline auto addStructFwd( pass_t & pass, int, ast::StructDecl * decl ) -> decltype( pass.indexer.addStruct( decl ), void() ) {
     232                                ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
     233                                fwd->parameters = decl->parameters;
     234                                pass.indexer.addStruct( fwd );
     235                        }
     236
     237                        template<typename pass_t>
     238                        static inline void addStructFwd( pass_t &, long, ast::StructDecl * ) {}
     239
     240                        template<typename pass_t>
     241                        static inline auto addUnionFwd( pass_t & pass, int, ast::UnionDecl * decl ) -> decltype( pass.indexer.addUnion( decl ), void() ) {
     242                                UnionDecl * fwd = new UnionDecl( decl->name );
     243                                fwd->parameters = decl->parameters;
     244                                pass.indexer.addUnion( fwd );
     245                        }
     246
     247                        template<typename pass_t>
     248                        static inline void addUnionFwd( pass_t &, long, ast::UnionDecl * ) {}
     249
     250                        template<typename pass_t>
     251                        static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.indexer.addStruct( str ), void() ) {
     252                                if ( ! pass.indexer.lookupStruct( str ) ) {
     253                                        pass.indexer.addStruct( str );
     254                                }
     255                        }
     256
     257                        template<typename pass_t>
     258                        static inline void addStruct( pass_t &, long, const std::string & ) {}
     259
     260                        template<typename pass_t>
     261                        static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.indexer.addUnion( str ), void() ) {
     262                                if ( ! pass.indexer.lookupUnion( str ) ) {
     263                                        pass.indexer.addUnion( str );
     264                                }
     265                        }
     266
     267                        template<typename pass_t>
     268                        static inline void addUnion( pass_t &, long, const std::string & ) {}
     269
     270                        #undef INDEXER_FUNC1
     271                        #undef INDEXER_FUNC2
     272                };
    288273        };
    289274};
    290 };
  • src/AST/Stmt.hpp

    r768b3b4f rb78129a  
    8989
    9090
    91 //=================================================================================================
    92 /// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
    93 /// remove only if there is a better solution
    94 /// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
    95 /// forward declarations
    96 inline void increment( const class Stmt * node, Node::ref_type ref ) { node->increment( ref ); }
    97 inline void decrement( const class Stmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    98 inline void increment( const class CompoundStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    99 inline void decrement( const class CompoundStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    100 inline void increment( const class ExprStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    101 inline void decrement( const class ExprStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    102 inline void increment( const class AsmStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    103 inline void decrement( const class AsmStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    104 inline void increment( const class DirectiveStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    105 inline void decrement( const class DirectiveStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    106 inline void increment( const class IfStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    107 inline void decrement( const class IfStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    108 inline void increment( const class WhileStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    109 inline void decrement( const class WhileStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    110 inline void increment( const class ForStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    111 inline void decrement( const class ForStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    112 inline void increment( const class SwitchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    113 inline void decrement( const class SwitchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    114 inline void increment( const class CaseStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    115 inline void decrement( const class CaseStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    116 inline void increment( const class BranchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    117 inline void decrement( const class BranchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    118 inline void increment( const class ReturnStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    119 inline void decrement( const class ReturnStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    120 inline void increment( const class ThrowStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    121 inline void decrement( const class ThrowStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    122 inline void increment( const class TryStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    123 inline void decrement( const class TryStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    124 inline void increment( const class CatchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    125 inline void decrement( const class CatchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    126 inline void increment( const class FinallyStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    127 inline void decrement( const class FinallyStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    128 inline void increment( const class WaitForStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    129 inline void decrement( const class WaitForStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    130 inline void increment( const class WithStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    131 inline void decrement( const class WithStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    132 inline void increment( const class DeclStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    133 inline void decrement( const class DeclStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    134 inline void increment( const class NullStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    135 inline void decrement( const class NullStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    136 inline void increment( const class ImplicitCtorDtorStmt * node, Node::ref_type ref ) { node->increment( ref ); }
    137 inline void decrement( const class ImplicitCtorDtorStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
    138 
    13991}
    14092
  • src/AST/StorageClasses.hpp

    r768b3b4f rb78129a  
    3333
    3434        /// Bitflag type for storage classes
    35         struct class_flags {
    36                 union {
    37                         unsigned int val;
    38                         struct {
    39                                 bool is_extern      : 1;
    40                                 bool is_static      : 1;
    41                                 bool is_auto        : 1;
    42                                 bool is_register    : 1;
    43                                 bool is_threadlocal : 1;
    44                         };
    45 
    46                         // MakeBitfieldPrint( NumClasses )
     35        union Classes {
     36                unsigned int val;
     37                struct {
     38                        bool is_extern      : 1;
     39                        bool is_static      : 1;
     40                        bool is_auto        : 1;
     41                        bool is_register    : 1;
     42                        bool is_threadlocal : 1;
    4743                };
    4844
    49                 constexpr class_flags( unsigned int val ) : val(val) {}
     45                MakeBitfield( Classes )
     46                MakeBitfieldPrint( NumClasses )
    5047        };
    5148
    52         using Classes = bitfield<class_flags>;
    5349}
    5450}
  • src/AST/Type.hpp

    r768b3b4f rb78129a  
    2424};
    2525
    26 
    27 
    28 //=================================================================================================
    29 /// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
    30 /// remove only if there is a better solution
    31 /// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
    32 /// forward declarations
    33 inline void increment( const class Type * node, Node::ref_type ref ) { node->increment( ref ); }
    34 inline void decrement( const class Type * node, Node::ref_type ref ) { node->decrement( ref ); }
    35 inline void increment( const class VoidType * node, Node::ref_type ref ) { node->increment( ref ); }
    36 inline void decrement( const class VoidType * node, Node::ref_type ref ) { node->decrement( ref ); }
    37 inline void increment( const class BasicType * node, Node::ref_type ref ) { node->increment( ref ); }
    38 inline void decrement( const class BasicType * node, Node::ref_type ref ) { node->decrement( ref ); }
    39 inline void increment( const class PointerType * node, Node::ref_type ref ) { node->increment( ref ); }
    40 inline void decrement( const class PointerType * node, Node::ref_type ref ) { node->decrement( ref ); }
    41 inline void increment( const class ArrayType * node, Node::ref_type ref ) { node->increment( ref ); }
    42 inline void decrement( const class ArrayType * node, Node::ref_type ref ) { node->decrement( ref ); }
    43 inline void increment( const class ReferenceType * node, Node::ref_type ref ) { node->increment( ref ); }
    44 inline void decrement( const class ReferenceType * node, Node::ref_type ref ) { node->decrement( ref ); }
    45 inline void increment( const class QualifiedType * node, Node::ref_type ref ) { node->increment( ref ); }
    46 inline void decrement( const class QualifiedType * node, Node::ref_type ref ) { node->decrement( ref ); }
    47 inline void increment( const class FunctionType * node, Node::ref_type ref ) { node->increment( ref ); }
    48 inline void decrement( const class FunctionType * node, Node::ref_type ref ) { node->decrement( ref ); }
    49 inline void increment( const class ReferenceToType * node, Node::ref_type ref ) { node->increment( ref ); }
    50 inline void decrement( const class ReferenceToType * node, Node::ref_type ref ) { node->decrement( ref ); }
    51 inline void increment( const class StructInstType * node, Node::ref_type ref ) { node->increment( ref ); }
    52 inline void decrement( const class StructInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
    53 inline void increment( const class UnionInstType * node, Node::ref_type ref ) { node->increment( ref ); }
    54 inline void decrement( const class UnionInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
    55 inline void increment( const class EnumInstType * node, Node::ref_type ref ) { node->increment( ref ); }
    56 inline void decrement( const class EnumInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
    57 inline void increment( const class TraitInstType * node, Node::ref_type ref ) { node->increment( ref ); }
    58 inline void decrement( const class TraitInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
    59 inline void increment( const class TypeInstType * node, Node::ref_type ref ) { node->increment( ref ); }
    60 inline void decrement( const class TypeInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
    61 inline void increment( const class TupleType * node, Node::ref_type ref ) { node->increment( ref ); }
    62 inline void decrement( const class TupleType * node, Node::ref_type ref ) { node->decrement( ref ); }
    63 inline void increment( const class TypeofType * node, Node::ref_type ref ) { node->increment( ref ); }
    64 inline void decrement( const class TypeofType * node, Node::ref_type ref ) { node->decrement( ref ); }
    65 inline void increment( const class AttrType * node, Node::ref_type ref ) { node->increment( ref ); }
    66 inline void decrement( const class AttrType * node, Node::ref_type ref ) { node->decrement( ref ); }
    67 inline void increment( const class VarArgsType * node, Node::ref_type ref ) { node->increment( ref ); }
    68 inline void decrement( const class VarArgsType * node, Node::ref_type ref ) { node->decrement( ref ); }
    69 inline void increment( const class ZeroType * node, Node::ref_type ref ) { node->increment( ref ); }
    70 inline void decrement( const class ZeroType * node, Node::ref_type ref ) { node->decrement( ref ); }
    71 inline void increment( const class OneType * node, Node::ref_type ref ) { node->increment( ref ); }
    72 inline void decrement( const class OneType * node, Node::ref_type ref ) { node->decrement( ref ); }
    73 inline void increment( const class GlobalScopeType * node, Node::ref_type ref ) { node->increment( ref ); }
    74 inline void decrement( const class GlobalScopeType * node, Node::ref_type ref ) { node->decrement( ref ); }
    75 
    7626}
    7727
  • src/AST/porting.md

    r768b3b4f rb78129a  
    9696
    9797`Expr`
    98 * Merged `inferParams`/`resnSlots` into union, as suggested by comment in old version
    99   * does imply get_/set_ API, and some care about moving backward
     98* Merged `inferParams`/`resnSlots` into union, as suggested by comment
    10099
    101100`Label`
  • src/Common/PassVisitor.impl.h

    r768b3b4f rb78129a  
    168168template< typename Container, typename pass_type >
    169169inline void maybeMutate_impl( Container & container, PassVisitor< pass_type > & mutator ) {
    170 
    171170        if ( ! mutator.get_visit_children() ) return;
    172171        SemanticErrorException errors;
     
    218217                try {
    219218                        func( *i );
    220                         assert( *i );
    221219                        assert(( empty( beforeStmts ) && empty( afterStmts ))
    222220                            || ( empty( beforeDecls ) && empty( afterDecls )) );
  • src/Common/PassVisitor.proto.h

    r768b3b4f rb78129a  
    222222INDEXER_FUNC2( addWith   , std::list< Expression * > &, BaseSyntaxNode * );
    223223
    224 #undef INDEXER_FUNC1
    225 #undef INDEXER_FUNC2
    226224
    227225template<typename pass_type>
  • src/SynTree/Declaration.h

    r768b3b4f rb78129a  
    7171        static Declaration *declFromId( UniqueId id );
    7272
     73  private:
     74        Type::StorageClasses storageClasses;
    7375        UniqueId uniqueId;
    74         Type::StorageClasses storageClasses;
    75   private:
    7676};
    7777
     
    213213                TypeDecl::Kind kind;
    214214                bool isComplete;
    215 
     215               
    216216                Data() : kind( (TypeDecl::Kind)-1 ), isComplete( false ) {}
    217217                Data( TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {}
    218218                Data( Kind kind, bool isComplete ) : kind( kind ), isComplete( isComplete ) {}
    219                 Data( const Data& d1, const Data& d2 )
     219                Data( const Data& d1, const Data& d2 ) 
    220220                : kind( d1.kind ), isComplete ( d1.isComplete || d2.isComplete ) {}
    221221
Note: See TracChangeset for help on using the changeset viewer.