Changes in / [f6e8c67:bbf2cb1]


Ignore:
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/jiada_liang_MMath/relatedwork.tex

    rf6e8c67 rbbf2cb1  
    22\label{s:RelatedWork}
    33
    4 In general, an \Newterm{algebraic data type} (ADT) is a composite type, \ie, a type formed by combining other types.
    5 Three common classes of algebraic types are \Newterm{array type}, \ie homogeneous types, \Newterm{product type}, \ie heterogeneous tuples and records (structures), and \Newterm{sum type}, \ie tagged product-types (unions).
    6 Enumerated types are a special case of product/sum types with non-mutable fields, \ie initialized (constructed) once at the type's declaration, possible restricted to compile-time initialization.
    7 Values of algebraic types are access by subscripting, field qualification, or type (pattern) matching.
    8 
    9 Enumeration types exist in many popular programming languages, both past and present, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, Haskell~\cite{Haskell} \CC, Go~\cite{Go}, Java~\cite{Java}, Modula-3~\cite{Modula-3}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}.
     4An enumeration type exist in many popular programming languages, both past and present, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, \CC, Go~\cite{Go}, Java~\cite{Java}, Modula-3~\cite{Modula-3}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}, and the algebraic data-type in functional programming.
    105Among theses languages, there are a large set of overlapping features, but each language has its own unique extensions and restrictions.
    116
     7
    128\section{Pascal}
    13 \lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
     9
     10\lstnewenvironment{pascal}[1][]{% necessary
     11\lstset{
     12language=pascal,
     13escapechar=\$,                                                  % LaTeX escape in code
     14moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
     15}% lstset
     16\lstset{#1}% necessary
     17}{}
    1418
    1519Classic Pascal has the \lstinline[language=pascal]{const} declaration binding a name to a constant literal/expression.
     
    1822                 PI = 3.14159;   Plus = '+';   Fred = 'Fred';
    1923\end{pascal}
    20 Here, there is no enumeration because there is no specific type (pseudo enumeration).
    21 Hence, there is no notion of a (possibly ordered) set, modulo the \lstinline[language=pascal]{set of} type.
    22 The type of each constant name (enumerator) is inferred from the constant-expression type.
     24The enumerator type is inferred from the constant-expression type.
     25There is no notion of an ordered set, modulo the \lstinline[language=pascal]{set of} type.
    2326
    2427Free Pascal~\cite[\S~3.1.1]{FreePascal} is a modern, object-oriented version of classic Pascal, with a C-style enumeration type.
     
    3942
    4043\section{Ada}
    41 \lstnewenvironment{ada}[1][]{\lstset{language=[2005]Ada,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},literate={'}{\ttfamily'\!}1}\lstset{#1}}{}
     44
     45\lstnewenvironment{ada}[1][]{% necessary
     46\lstset{
     47language=[2005]Ada,
     48escapechar=\$,                                                  % LaTeX escape in code
     49moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
     50literate={'}{\ttfamily'\!}1                             % remove '-' literate as comment
     51}% lstset
     52\lstset{#1}% necessary
     53}{}
    4254
    4355An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
    4456\begin{ada}
    45 type RGB is ( Red, Green, Blue ); -- 3 literals (enumerators)
    46 \end{ada}
    47 Object initialization and assignment are restricted to the enumerators of this type.
     57type RGB is ( @Red@, @Green@, Blue ); -- 3 literals (enumerators)
     58\end{ada}
     59No other enumerators are assignable to objects of this type.
    4860Enumerators without an explicitly designated constant value are auto-initialized: from left to right, starting at zero or the next explicitly initialized constant, incrementing by 1.
    4961To explicitly set enumerator values, \emph{all} enumerators must be set in \emph{ascending} order, \ie there is no auto-initialization.
     
    5668(0, 10, RED)  (1, 20, GREEN)  (2, 30, BLUE)
    5769\end{ada}
    58 Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same, \eg @Red@ and @RED@ (a questionable design decision).
    5970
    6071Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope.
    61 The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of enumerators, which is always ascending.
     72Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same name (a questionable design decision).
     73The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relation is given implicitly by the sequence of enumerators, which is always ascending.
    6274
    6375Ada enumerators are overloadable.
     
    124136\begin{ada}
    125137type Operator is ( '+', '-', '*', '/' );
     138Op : Operator;
    126139\end{ada}
    127140which is syntactic sugar for the label and not character literals from the predefined type @Character@.
    128 The purpose is strictly readability using character literals rather than names.
    129 \begin{ada}
    130 Op : Operator := '+';
    131 if Op = '+' or else Op = '-' then ... ;
    132 elsif Op = '*' or else Op = '/' then ... ; end if;
    133 \end{ada}
    134 Interestingly, arrays of character enumerators can be treated as strings.
     141The purpose is readability using character literals rather than names.
     142\begin{ada}
     143Op := '+';
     144case Op is                    -- all enumerators must appear
     145        when '+' => ... ;
     146        when '-' => ... ;
     147        when '*' => ... ;
     148        when '/' => ... ;
     149end case;
     150\end{ada}
     151Arrays of character enumerators can be treated as strings.
    135152\begin{ada}
    136153Ops : array( 0..3 ) of Operator;
    137154Ops := @"+-*/"@;            -- string assignment to array elements
    138155Ops := @"+-" & "*/"@;   -- string concatenation and assignment
     156for Op of Ops loop
     157        Put_Line( Operator'Image( Op ) );
     158end loop;
    139159\end{ada}
    140160Ada's @Character@ type is defined as a character enumeration across all Latin-1 characters.
    141161
    142 Ada's boolean type is also a special enumeration, which can be used in conditions.
     162Ada's boolean type is defined as a special enumeration, which can be used in conditions.
    143163\begin{ada}
    144164type Boolean is (False, True); -- False / True not keywords
     
    157177Hence, the ordering of the enumerators is crucial to provide the necessary ranges.
    158178
    159 An enumeration type can be used in the Ada \lstinline[language=ada]{case} (all enumerators must appear or a default) or iterating constructs.
     179An enumeration type can be used in the Ada \lstinline[language=ada]{case} (switch) and iterating constructs.
    160180\begin{cquote}
    161181\lstDeleteShortInline@
     
    213233\section{\CC}
    214234\label{s:C++RelatedWork}
    215 \lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
     235
     236\lstnewenvironment{c++}[1][]{% necessary
     237\lstset{
     238language=[GNU]C++,
     239escapechar=\$,                                                  % LaTeX escape in code
     240moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
     241}% lstset
     242\lstset{#1}% necessary
     243}{}
    216244
    217245\CC is largely backwards compatible with C, so it inherited C's enumerations.
     
    260288enum class E { A, B, C };
    261289E e = @E::@A;                                                   $\C{// qualified enumerator}$
    262 e = B;                                                                  $\C{// error: B not in scope}$
     290e = B;                                                                  $\C{// B not in scope}$
    263291\end{c++}
    264292\CC{20} supports explicit unscoping with a \lstinline[language=c++]{using enum} declaration.
     
    275303enum class srgb @: signed char@ { Red = -1, Green = 0, Blue = 1 };
    276304\end{c++}
    277 There is no implicit conversion from the \lstinline[language=c++]{enum class} type to its declared type.
     305There is no implicit conversion from the \lstinline[language=c++]{enum class} type and to its type.
    278306\begin{c++}
    279307rgb crgb = rgb::Red;
    280 char ch = rgb::Red;   ch = crgb;                $\C{// error}$
     308char ch = rgb::Red;   ch = crgb;                $\C{// disallowed}$
    281309\end{c++}
    282 Finally, enumerations can be used in the @switch@ statement but there is no mechanism to iterate through an enumeration.
    283 An enumeration type cannot declare an array dimension but can be used as a subscript.
    284 There is no mechanism to subtype or inherit from enumerations.
     310Finally, there is no mechanism to iterate through an enumeration nor use the enumeration type to declare an array dimension.
    285311
    286312
    287313\section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE
    288 \label{s:Csharp}
    289 \lstnewenvironment{csharp}[1][]{\lstset{language=[Sharp]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
     314
     315\lstnewenvironment{csharp}[1][]{% necessary
     316\lstset{
     317language=[Sharp]C,
     318escapechar=\$,                                                  % LaTeX escape in code
     319moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
     320}% lstset
     321\lstset{#1}% necessary
     322}{}
    290323
    291324% https://www.tutorialsteacher.com/codeeditor?cid=cs-mk8Ojx
    292325
    293 \Csharp is a dynamically-typed programming-language with a scoped, integral enumeration-type similar to the C/\CC enumeration.
     326\Csharp is a dynamically-typed programming-language with a scoped, integral enumeration-type similar to C/\CC enumeration.
    294327\begin{csharp}
    295 enum Weekday : byte { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun@,@ };
     328enum Weekday : byte { Monday, Tuesday, Wednesday, Thursday@ = 10@, Friday, Saturday, Sunday@,@ };
    296329\end{csharp}
    297 The default underlying type is @int@, with auto-incrementing, implicit/explicit initialization, terminator comma, and optional integral typing (default @int@).
     330The default underlying type is @int@, with auto-incrementing, implicit/explicit initialization, terminator comma, and optional integral typing (default @int@)
    298331A method cannot be defined in an enumeration type.
    299332As well, there is an explicit bidirectional conversion between an enumeration and its integral type, and an implicit conversion to the enumerator label in display contexts.
    300333\begin{csharp}
    301 int day = (int)Weekday.Fri;             $\C{// day == 10}$
    302 Weekday weekday = (Weekdays)42;         $\C{// weekday == 42, logically invalid}$
    303 Console.WriteLine( Weekday.Fri ); $\C{// print Fri}$
    304 string mon = Weekday.Mon.ToString(); $\C{// mon == "Mon"}$
     334int day = (int)Weekday.Friday;                  $\C{// day == 10}$
     335Weekday weekday = (Weekdays)42;                 $\C{// weekday == 42}$
     336Console.WriteLine( Weekday.Friday );    $\C{// print Friday}$
     337string mon = Weekday.Monday.ToString();
    305338\end{csharp}
    306339
    307 The @Enum.GetValues@ pseudo-method retrieves an array of the enumeration constants for looping over an enumeration type or variable (expensive operation).
     340The @Enum.GetValues@ pseudo-method retrieves an array of the enumeration constants for looping over an enumeration type or variable.
    308341\begin{csharp}
    309342foreach ( Weekday constant in @Enum.GetValues@( typeof(Weekday) ) ) {
     
    315348\begin{csharp}
    316349@[Flags]@ public enum Weekday {
    317         None = 0x0, Mon = 0x1, Tue = 0x2, Wed = 0x4,
    318         Thu = 0x8, Fri = 0x10, Sat = 0x20, Sun = 0x40,
    319         Weekend = @Sat | Sun@,
    320         Weekdays = @Mon | Tue | Wed | Thu | Fri@
    321 }
    322 Weekday meetings = @Weekday.Mon | Weekday.Wed@; // 0x5
     350        None = 0x0, Monday = 0x1, Tuesday = 0x2, Wednesday = 0x4,
     351        Thursday = 0x8, Friday = 0x10, Saturday = 0x20, Sunday = 0x40,
     352        Weekend = @Saturday | Sunday@,
     353        Weekdays = @Monday | Tuesday | Wednesday | Thursday | Friday@
     354}
     355Weekday meetings = @Weekday.Monday | Weekday.Wednesday@; // 0x5
    323356\end{csharp}
    324357
    325 \VRef[Figure]{CsharpFreeVersusClass} shows an enumeration with free routines for manipulation, and embedding the enumeration and operations into an enumeration class.
    326 The key observation is that an enumeration class is just a structuring mechanism without any additional semantics.
    327 
    328 % https://learn.microsoft.com/en-us/dotnet/api/system.enum?view=net-8.0
    329 
    330 \begin{figure}
    331 \centering
    332 \lstDeleteShortInline@
    333 \begin{tabular}{@{}l|l@{}}
    334 \multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
    335 \hline
     358\Csharp supports an enumeration class to embed enumeration operations, where the enumerators are objects.
    336359\begin{csharp}
    337 public class Program {
    338 
    339         enum Weekday {
    340                 Mon, Tue, Wed, Thu, Fri, Sat, Sun };
    341 
    342         static bool isWeekday( Weekday wd ) {
    343                 return wd <= Weekday.Fri;
    344         }
    345         static bool isWeekend( Weekday wd ) {
    346                 return Weekday.Sat <= wd;
    347         }
    348 
    349 
    350         public static void Main() {
    351                 Weekday day = Weekday.Sat;
    352 
    353                 Console.WriteLine( isWeekday( day ) );
    354                 Console.WriteLine( isWeekend( day ) );
    355         }
     360public class PaymentType : Enumeration {
     361    public static readonly PaymentType DebitCard = new PaymentType(0);
     362    public static readonly PaymentType CreditCard = new PaymentType(1);
     363    private PaymentType(int value, [CallerMemberName] string name = null) : base(value, name) { }
    356364}
    357365\end{csharp}
    358 &
    359 \begin{csharp}
    360 public class Program {
    361         public @class@ WeekDay : Enumeration {
    362                 public enum Day {
    363                                 Mon, Tue, Wed, Thu, Fri, Sat, Sun };
    364                 public enum Day2 : Day {
    365                                 XXX, YYY };
    366                 Day day;
    367                 public bool isWeekday() {
    368                         return day <= Day.Fri;
    369                 }
    370                 public bool isWeekend() {
    371                         return day > Day.Fri;
    372                 }
    373                 public WeekDay( Day d ) { day = d; }
    374         }
    375         public static void Main() {
    376                 WeekDay cday = new
    377                                 WeekDay( WeekDay.Day.Sat );
    378                 Console.WriteLine( cday.isWeekday() );
    379                 Console.WriteLine( cday.isWeekend() );
    380         }
    381 }
    382 \end{csharp}
    383 \end{tabular}
    384 \lstMakeShortInline@
    385 \caption{\Csharp: Free Routine Versus Class Enumeration}
    386 \label{CsharpFreeVersusClass}
    387 \end{figure}
     366Find a meaningful example and test it.
    388367
    389368
    390369\section{Golang}
    391 \lstnewenvironment{Go}[1][]{\lstset{language=Go,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    392 
    393 Golang provides pseudo-enumeration similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
     370
     371\lstnewenvironment{Go}[1][]{% necessary
     372\lstset{
     373language=Go,
     374escapechar=\$,                                                  % LaTeX escape in code
     375moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
     376}% lstset
     377\lstset{#1}% necessary
     378}{}
     379
     380The Golang enumeration is similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
    394381\begin{Go}
    395382const ( R = 0; G; B )                                   $\C{// implicit: 0 0 0}$
     
    414401Auto-incrementing stops after an explicit initialization.
    415402\begin{Go}
    416 const ( Mon = iota; Tue; Wed; // 0, 1, 2
    417          @Thu = 10@; Fri; Sat; Sun ) // 10, 10, 10, 10
     403const ( Monday = iota; Tuesday; Wednesday; // 0, 1, 2
     404         @Thursday = 10@; Friday; Saturday; Sunday ) // 10, 10, 10, 10
    418405\end{Go}
    419406Auto-incrementing can be restarted with an expression containing \emph{one} \lstinline[language=Go]{iota}.
    420407\begin{Go}
    421408const ( V1 = iota; V2; @V3 = 7;@ V4 = @iota@; V5 ) // 0 1 7 3 4
    422 const ( Mon = iota; Tue; Wed; // 0, 1, 2
    423          @Thu = 10;@ Fri = @iota - Wed + Thu - 1@; Sat; Sun ) // 10, 11, 12, 13
     409const ( Monday = iota; Tuesday; Wednesday; // 0, 1, 2
     410         @Thursday = 10;@ Friday = @iota - Wednesday + Thursday - 1@; Saturday; Sunday ) // 10, 11, 12, 13
    424411\end{Go}
    425412Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier.
    426413
    427 Basic switch and looping are possible.
    428 \begin{cquote}
    429 \lstDeleteShortInline@
    430 \setlength{\tabcolsep}{15pt}
    431 \begin{tabular}{@{}ll@{}}
    432 \begin{Go}
    433 day := Mon;
    434 switch day {
    435   case Mon, Tue, Wed, Thu, Fri:
    436         fmt.Println( "weekday" );
    437   case Sat, Sun:
    438         fmt.Println( "weekend" );
    439 }
    440 \end{Go}
    441 &
    442 \begin{Go}
    443 
    444 for i := Mon; i <= Sun; i += 1 {
    445         fmt.Println( i )
    446 }
    447 
    448 
    449 
    450 \end{Go}
    451 \end{tabular}
    452 \lstMakeShortInline@
    453 \end{cquote}
    454 However, the loop prints the values from 0 to 13 because there is no actual enumeration.
    455 
    456414
    457415\section{Java}
    458 \lstnewenvironment{Java}[1][]{\lstset{language=Java,morekeywords={enum,assert,strictfp},
    459         escapechar=\$,moredelim=**[is][\color{red}]{!}{!},}\lstset{#1}}{}
    460 
    461 Every enumeration in Java is an enumeration class.
    462 For a basic enumeration
    463 \begin{Java}
    464 enum Weekday { Mon, Tue, Wed, Thu, Fri, Sat, Sun };
    465 Weekday day = Weekday.Sat;
    466 \end{Java}
    467 the scoped enumerators are an ordered list of @final@ methods of type integer, ordered left to right starting at 0, increasing by 1.
    468 The value of an enumeration instance is restricted to the enumeration's enumerators.
    469 There is an implicit @int@ variable in the enumeration used to store the value of an enumeration instance.
    470 The position (ordinal) and label are accessible, where the value is the same as the position.
    471 \begin{Java}
    472 System.out.println( day.!ordinal()! + " " + day.!name()! ); // 5 Sat
    473 \end{Java}
    474 There is an inverse function @valueOf@ from string to enumerator.
    475 \begin{Java}
    476 day = Weekday.valueOf( "Wed" );
    477 \end{Java}
    478 There are no implicit conversions to/from an enumerator and its underlying type.
    479 Like \Csharp, \VRef[Figure]{f:JavaFreeVersusClass} shows the same example for an enumeration with free routines for manipulation, and embedding the enumeration and operations into an enumeration class.
    480 
    481 \begin{figure}
    482 \centering
    483 \lstDeleteShortInline@
    484 \begin{tabular}{@{}l|l@{}}
    485 \multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
    486 \hline
    487 \begin{Java}
    488 enum Weekday !{!
    489         Mon, Tue, Wed, Thu, Fri, Sat, Sun !}!;
    490 
    491 static boolean isWeekday( Weekday wd ) {
    492         return wd.ordinal() <= Weekday.Fri.ordinal();
    493 }
    494 static boolean isWeekend( Weekday wd ) {
    495         return Weekday.Fri.ordinal() < wd.ordinal();
    496 }
    497 
    498 public static void main( String[] args ) {
    499         Weekday day = Weekday.Sat;
    500         System.out.println( isWeekday( day ) );
    501         System.out.println( isWeekend( day ) );
    502 }
    503 \end{Java}
    504 &
    505 \begin{Java}
    506 enum Weekday !{!
    507         Mon, Tue, Wed, Thu, Fri, Sat, Sun;
    508 
    509         public boolean isWeekday() {
    510                 return ordinal() <= Weekday.Fri.ordinal();
    511         }
    512         public boolean isWeekend() {
    513                 return Weekday.Fri.ordinal() < ordinal();
    514         }
    515 !}!
    516 public static void main( String[] args ) {
    517         WeekDay day = WeekDay.Sat;
    518         System.out.println( day.isWeekday() );
    519         System.out.println( day.isWeekend() );
    520 }
    521 \end{Java}
    522 \end{tabular}
    523 \lstMakeShortInline@
    524 \caption{Java: Free Routine Versus Class Enumeration}
    525 \label{f:JavaFreeVersusClass}
    526 \end{figure}
    527 
    528 To explicitly assign enumerator values and/or use a non-@int@ enumeration type (any Java type may be used), the enumeration must specify an explicit type in the enumeration class and a constructor.
    529 \begin{Java}
    530 enum Weekday {
    531         Mon!(1)!, Tue!(2)!, Wed!(3)!, Thu!(4)!, Fri!(5)!, Sat!(6)!, Sun!(7)!; // must appear first
    532         private !long! day;                                     $\C{// underlying enumeration type}$
    533         private Weekday( !long! d ) { day = d; } $\C{// used to initialize enumerators}$
    534 };
    535 Weekday day = Weekday.Sat;
    536 \end{Java}
    537 If an enumerator initialization is a runtime expression, the expression is executed once at the point the enumeration is declaraed.
    538 
    539 The position, value, and label are accessible.
    540 \begin{Java}
    541 System.out.println( !day.ordinal()! + " " + !day.day! + " " + !day.name()! );  // 5 6 Sat
    542 \end{Java}
    543 The constructor is private so only initialization or assignment can be used to set an enumeration, which ensures only corresponding enumerator values are allowed.
    544 
    545 An enumeration can appear in a @switch@ statement, but no ranges.
    546 \begin{Java}
    547 switch ( day ) {
    548   case Mon: case Tue: case Wed: case Thu: case Fri:
    549         System.out.println( "weekday" );
    550         break;
    551   case Sat: case Sun:
    552         System.out.println( "weekend" );
    553         break;
    554 }
    555 \end{Java}
    556 Like \Csharp, looping over an enumeration is done using method @values@, which returns the array of enumerator values (expensive operation).
    557 \begin{Java}
    558 for ( Weekday iday : Weekday.values() ) {
    559         System.out.print( iday.ordinal() + iday.day + " " +  iday.name() + ",  " );
    560 }
    561 0 1 Mon,  1 2 Tue,  2 3 Wed,  3 4 Thu,  4 5 Fri,  5 6 Sat,  6 7 Sun, 
    562 \end{Java}
    563 
    564 As well, Java provides an @EnumSet@ where the underlying type is an efficient set of bits, one per enumeration \see{\Csharp \lstinline{Flags}, \VRef{s:Csharp}}, providing (logical) operations on groups of enumerators.
    565 There is also a specialized version of @HashMap@ with enumerator keys, which has performance benefits.
    566 
    567 Enumeration inheritence is disallowed because an enumeration is @final@.
    568 
     416
     417\lstnewenvironment{Java}[1][]{% necessary
     418\lstset{
     419language=Java,
     420escapechar=\$,                                                  % LaTeX escape in code
     421moredelim=**[is][\color{red}]{`}{`},    % red highlighting @...@
     422}% lstset
     423\lstset{#1}% necessary
     424}{}
     425
     426Here's a quick and simple example of an enum that defines the status of a pizza order; the order status can be ORDERED, READY or DELIVERED:
     427\begin{Java}
     428public enum PizzaStatus {
     429    ORDERED,
     430    READY,
     431    DELIVERED;
     432}
     433\end{Java}
     434Additionally, enums come with many useful methods that we would otherwise need to write if we were using traditional public static final constants.
     435
     436\paragraph{Custom Enum Methods}
     437
     438Now that we have a basic understanding of what enums are and how we can use them, we'll take our previous example to the next level by defining some extra API methods on the enum:
     439\begin{Java}
     440public class Pizza {
     441    private PizzaStatus status;
     442    public enum PizzaStatus {
     443        ORDERED,
     444        READY,
     445        DELIVERED;
     446    }
     447    public boolean isDeliverable() {
     448        if (getStatus() == PizzaStatus.READY) {
     449            return true;
     450        }
     451        return false;
     452    }
     453    // Methods that set and get the status variable.
     454}
     455\end{Java}
     456
     457\paragraph{Comparing Enum Types Using "==" Operator}
     458
     459Since enum types ensure that only one instance of the constants exist in the JVM, we can safely use the "==" operator to compare two variables, like we did in the above example.
     460Furthermore, the "==" operator provides compile-time and run-time safety.
     461
     462First, we'll look at run-time safety in the following snippet, where we'll use the "==" operator to compare statuses.
     463Either value can be null and we won't get a NullPointerException. Conversely, if we use the equals method, we will get a NullPointerException:
     464\begin{Java}
     465if(testPz.getStatus().equals(Pizza.PizzaStatus.DELIVERED));
     466if(testPz.getStatus() == Pizza.PizzaStatus.DELIVERED);
     467\end{Java}
     468As for compile-time safety, let's look at an example where we'll determine that an enum of a different type is equal by comparing it using the equals method.
     469This is because the values of the enum and the getStatus method coincidentally are the same;
     470however, logically the comparison should be false. We avoid this issue by using the "==" operator.
     471
     472The compiler will flag the comparison as an incompatibility error:
     473\begin{Java}
     474if(testPz.getStatus().equals(TestColor.GREEN));
     475if(testPz.getStatus() == TestColor.GREEN);
     476\end{Java}
     477
     478\paragraph{Using Enum Types in Switch Statements}
     479
     480We can use enum types in switch statements also:
     481\begin{Java}
     482public int getDeliveryTimeInDays() {
     483    switch (status) {
     484        case ORDERED: return 5;
     485        case READY: return 2;
     486        case DELIVERED: return 0;
     487    }
     488    return 0;
     489}
     490\end{Java}
     491
     492\paragraph{Fields, Methods and Constructors in Enums}
     493
     494We can define constructors, methods, and fields inside enum types, which makes them very powerful.
     495
     496Next, let's extend the example above by implementing the transition from one stage of a pizza order to another.
     497We'll see how we can get rid of the if and switch statements used before:
     498\begin{Java}
     499public class Pizza {
     500    private PizzaStatus status;
     501    public enum PizzaStatus {
     502        ORDERED (5){
     503            @Override
     504            public boolean isOrdered() {
     505                return true;
     506            }
     507        },
     508        READY (2){
     509            @Override
     510            public boolean isReady() {
     511                return true;
     512            }
     513        },
     514        DELIVERED (0){
     515            @Override
     516            public boolean isDelivered() {
     517                return true;
     518            }
     519        };
     520
     521        private int timeToDelivery;
     522        public boolean isOrdered() {return false;}
     523        public boolean isReady() {return false;}
     524        public boolean isDelivered(){return false;}
     525        public int getTimeToDelivery() {
     526            return timeToDelivery;
     527        }
     528        PizzaStatus (int timeToDelivery) {
     529            this.timeToDelivery = timeToDelivery;
     530        }
     531    }
     532    public boolean isDeliverable() {
     533        return this.status.isReady();
     534    }
     535    public void printTimeToDeliver() {
     536        System.out.println("Time to delivery is " +
     537          this.getStatus().getTimeToDelivery());
     538    }
     539    // Methods that set and get the status variable.
     540}
     541\end{Java}
     542The test snippet below demonstrates how this works:
     543\begin{Java}
     544@Test
     545public void givenPizaOrder_whenReady_thenDeliverable() {
     546    Pizza testPz = new Pizza();
     547    testPz.setStatus(Pizza.PizzaStatus.READY);
     548    assertTrue(testPz.isDeliverable());
     549}
     550\end{Java}
     551
     552\paragraph{EnumSet and EnumMap}
     553
     554\paragraph{EnumSet}
     555
     556The EnumSet is a specialized Set implementation that's meant to be used with Enum types.
     557
     558Compared to a HashSet, it's a very efficient and compact representation of a particular Set of Enum constants, owing to the internal Bit Vector Representation that's used.
     559It also provides a type-safe alternative to traditional int-based "bit flags," allowing us to write concise code that's more readable and maintainable.
     560
     561The EnumSet is an abstract class that has two implementations, RegularEnumSet and JumboEnumSet, one of which is chosen depending on the number of constants in the enum at the time of instantiation.
     562
     563Therefore, it's a good idea to use this set whenever we want to work with a collection of enum constants in most scenarios (like subsetting, adding, removing, and bulk operations like containsAll and removeAll), and use Enum.values() if we just want to iterate over all possible constants.
     564
     565In the code snippet below, we can see how to use EnumSet to create a subset of constants:
     566\begin{Java}
     567public class Pizza {
     568    private static EnumSet<PizzaStatus> undeliveredPizzaStatuses =
     569      EnumSet.of(PizzaStatus.ORDERED, PizzaStatus.READY);
     570    private PizzaStatus status;
     571    public enum PizzaStatus {
     572        ...
     573    }
     574    public boolean isDeliverable() {
     575        return this.status.isReady();
     576    }
     577    public void printTimeToDeliver() {
     578        System.out.println("Time to delivery is " +
     579          this.getStatus().getTimeToDelivery() + " days");
     580    }
     581    public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
     582        return input.stream().filter(
     583          (s) -> undeliveredPizzaStatuses.contains(s.getStatus()))
     584            .collect(Collectors.toList());
     585    }
     586    public void deliver() {
     587        if (isDeliverable()) {
     588            PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy()
     589              .deliver(this);
     590            this.setStatus(PizzaStatus.DELIVERED);
     591        }
     592    }
     593    // Methods that set and get the status variable.
     594}
     595\end{Java}
     596
     597Executing the following test demonstrates the power of the EnumSet implementation of the Set interface:
     598\begin{Java}
     599@Test
     600public void givenPizaOrders_whenRetrievingUnDeliveredPzs_thenCorrectlyRetrieved() {
     601    List<Pizza> pzList = new ArrayList<>();
     602    Pizza pz1 = new Pizza();
     603    pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
     604
     605    Pizza pz2 = new Pizza();
     606    pz2.setStatus(Pizza.PizzaStatus.ORDERED);
     607
     608    Pizza pz3 = new Pizza();
     609    pz3.setStatus(Pizza.PizzaStatus.ORDERED);
     610
     611    Pizza pz4 = new Pizza();
     612    pz4.setStatus(Pizza.PizzaStatus.READY);
     613
     614    pzList.add(pz1);
     615    pzList.add(pz2);
     616    pzList.add(pz3);
     617    pzList.add(pz4);
     618
     619    List<Pizza> undeliveredPzs = Pizza.getAllUndeliveredPizzas(pzList);
     620    assertTrue(undeliveredPzs.size() == 3);
     621}
     622\end{Java}
     623
     624\paragraph{EnumMap}
     625
     626EnumMap is a specialized Map implementation meant to be used with enum constants as keys.
     627Compared to its counterpart HashMap, it's an efficient and compact implementation that's internally represented as an array:
     628\begin{Java}
     629EnumMap<Pizza.PizzaStatus, Pizza> map;
     630\end{Java}
     631Let's look at an example of how we can use it in practice:
     632\begin{Java}
     633public static EnumMap<PizzaStatus, List<Pizza>>
     634  groupPizzaByStatus(List<Pizza> pizzaList) {
     635    EnumMap<PizzaStatus, List<Pizza>> pzByStatus =
     636      new EnumMap<PizzaStatus, List<Pizza>>(PizzaStatus.class);
     637   
     638    for (Pizza pz : pizzaList) {
     639        PizzaStatus status = pz.getStatus();
     640        if (pzByStatus.containsKey(status)) {
     641            pzByStatus.get(status).add(pz);
     642        } else {
     643            List<Pizza> newPzList = new ArrayList<Pizza>();
     644            newPzList.add(pz);
     645            pzByStatus.put(status, newPzList);
     646        }
     647    }
     648    return pzByStatus;
     649}
     650\end{Java}
     651Executing the following test demonstrates the power of the EnumMap implementation of the Map interface:
     652\begin{Java}
     653@Test
     654public void givenPizaOrders_whenGroupByStatusCalled_thenCorrectlyGrouped() {
     655    List<Pizza> pzList = new ArrayList<>();
     656    Pizza pz1 = new Pizza();
     657    pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
     658
     659    Pizza pz2 = new Pizza();
     660    pz2.setStatus(Pizza.PizzaStatus.ORDERED);
     661
     662    Pizza pz3 = new Pizza();
     663    pz3.setStatus(Pizza.PizzaStatus.ORDERED);
     664
     665    Pizza pz4 = new Pizza();
     666    pz4.setStatus(Pizza.PizzaStatus.READY);
     667
     668    pzList.add(pz1);
     669    pzList.add(pz2);
     670    pzList.add(pz3);
     671    pzList.add(pz4);
     672
     673    EnumMap<Pizza.PizzaStatus,List<Pizza>> map = Pizza.groupPizzaByStatus(pzList);
     674    assertTrue(map.get(Pizza.PizzaStatus.DELIVERED).size() == 1);
     675    assertTrue(map.get(Pizza.PizzaStatus.ORDERED).size() == 2);
     676    assertTrue(map.get(Pizza.PizzaStatus.READY).size() == 1);
     677}
     678\end{Java}
     679
     680\paragraph{Singleton Pattern}
     681
     682Normally, implementing a class using the Singleton pattern is quite non-trivial.
     683Enums provide a quick and easy way of implementing singletons.
     684
     685In addition, since the enum class implements the Serializable interface under the hood, the class is guaranteed to be a singleton by the JVM.
     686This is unlike the conventional implementation, where we have to ensure that no new instances are created during deserialization.
     687
     688In the code snippet below, we see how we can implement a singleton pattern:
     689\begin{Java}
     690public enum PizzaDeliverySystemConfiguration {
     691    INSTANCE;
     692    PizzaDeliverySystemConfiguration() {
     693        // Initialization configuration which involves
     694        // overriding defaults like delivery strategy
     695    }
     696
     697    private PizzaDeliveryStrategy deliveryStrategy = PizzaDeliveryStrategy.NORMAL;
     698
     699    public static PizzaDeliverySystemConfiguration getInstance() {
     700        return INSTANCE;
     701    }
     702
     703    public PizzaDeliveryStrategy getDeliveryStrategy() {
     704        return deliveryStrategy;
     705    }
     706}
     707\end{Java}
     708
     709\paragraph{Strategy Pattern}
     710
     711Conventionally, the Strategy pattern is written by having an interface that is implemented by different classes.
     712
     713Adding a new strategy means adding a new implementation class.
     714With enums, we can achieve this with less effort, and adding a new implementation means simply defining another instance with some implementation.
     715
     716The code snippet below shows how to implement the Strategy pattern:
     717\begin{Java}
     718public enum PizzaDeliveryStrategy {
     719    EXPRESS {
     720        @Override
     721        public void deliver(Pizza pz) {
     722            System.out.println("Pizza will be delivered in express mode");
     723        }
     724    },
     725    NORMAL {
     726        @Override
     727        public void deliver(Pizza pz) {
     728            System.out.println("Pizza will be delivered in normal mode");
     729        }
     730    };
     731
     732    public abstract void deliver(Pizza pz);
     733}
     734\end{Java}
     735Then we add the following method to the Pizza class:
     736\begin{Java}
     737public void deliver() {
     738    if (isDeliverable()) {
     739        PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy()
     740          .deliver(this);
     741        this.setStatus(PizzaStatus.DELIVERED);
     742    }
     743}
     744
     745@Test
     746public void givenPizaOrder_whenDelivered_thenPizzaGetsDeliveredAndStatusChanges() {
     747    Pizza pz = new Pizza();
     748    pz.setStatus(Pizza.PizzaStatus.READY);
     749    pz.deliver();
     750    assertTrue(pz.getStatus() == Pizza.PizzaStatus.DELIVERED);
     751}
     752\end{Java}
     753
     7548. Java 8 and Enums
     755
     756We can rewrite the Pizza class in Java 8, and see how the methods getAllUndeliveredPizzas() and groupPizzaByStatus() become so concise with the use of lambdas and the Stream APIs:
     757\begin{Java}
     758public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
     759    return input.stream().filter(
     760      (s) -> !deliveredPizzaStatuses.contains(s.getStatus()))
     761        .collect(Collectors.toList());
     762}
     763
     764public static EnumMap<PizzaStatus, List<Pizza>>
     765  groupPizzaByStatus(List<Pizza> pzList) {
     766    EnumMap<PizzaStatus, List<Pizza>> map = pzList.stream().collect(
     767      Collectors.groupingBy(Pizza::getStatus,
     768      () -> new EnumMap<>(PizzaStatus.class), Collectors.toList()));
     769    return map;
     770}
     771\end{Java}
    569772
    570773
    571774\section{Modula-3}
    572775
    573 
    574 
    575776\section{Rust}
    576 \lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    577 
    578 Enumerations
    579 \begin{rust}
    580         Syntax
    581         Enumeration :
    582            enum IDENTIFIER  GenericParams? WhereClause? { EnumItems? }
    583 
    584         EnumItems :
    585            EnumItem ( , EnumItem )* ,?
    586 
    587         EnumItem :
    588            OuterAttribute* Visibility?
    589            IDENTIFIER ( EnumItemTuple | EnumItemStruct )? EnumItemDiscriminant?
    590 
    591         EnumItemTuple :
    592            ( TupleFields? )
    593 
    594         EnumItemStruct :
    595            { StructFields? }
    596 
    597         EnumItemDiscriminant :
    598            = Expression
    599 \end{rust}
    600 An enumeration, also referred to as an enum, is a simultaneous definition of a nominal enumerated type as well as a set of constructors, that can be used to create or pattern-match values of the corresponding enumerated type.
    601 
    602 Enumerations are declared with the keyword enum.
    603 
    604 An example of an enum item and its use:
    605 \begin{rust}
    606 enum Animal {
    607         Dog,
    608         Cat,
    609 }
    610 
    611 let mut a: Animal = Animal::Dog;
    612 a = Animal::Cat;
    613 \end{rust}
    614 Enum constructors can have either named or unnamed fields:
    615 \begin{rust}
    616 enum Animal {
    617         Dog(String, f64),
    618         Cat { name: String, weight: f64 },
    619 }
    620 
    621 let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2);
    622 a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
    623 \end{rust}
    624 In this example, Cat is a struct-like enum variant, whereas Dog is simply called an enum variant.
    625 
    626 An enum where no constructors contain fields are called a field-less enum. For example, this is a fieldless enum:
    627 \begin{rust}
    628 enum Fieldless {
    629         Tuple(),
    630         Struct{},
    631         Unit,
    632 }
    633 \end{rust}
    634 If a field-less enum only contains unit variants, the enum is called an unit-only enum. For example:
    635 \begin{rust}
    636 enum Enum {
    637         Foo = 3,
    638         Bar = 2,
    639         Baz = 1,
    640 }
    641 \end{rust}
    642 
    643 \subsection{Discriminants}
    644 
    645 Each enum instance has a discriminant: an integer logically associated to it that is used to determine which variant it holds.
    646 
    647 Under the default representation, the discriminant is interpreted as an isize value. However, the compiler is allowed to use a smaller type (or another means of distinguishing variants) in its actual memory layout.
    648 
    649 \subsection{Assigning discriminant values}
    650 
    651 \subsection{Explicit discriminants}
    652 
    653 In two circumstances, the discriminant of a variant may be explicitly set by following the variant name with = and a constant expression:
    654 
    655         if the enumeration is "unit-only".
    656 
    657         if a primitive representation is used. For example:
    658 \begin{rust}
    659         #[repr(u8)]
    660         enum Enum {
    661                 Unit = 3,
    662                 Tuple(u16),
    663                 Struct {
    664                         a: u8,
    665                         b: u16,
    666                 } = 1,
    667         }
    668 \end{rust}
    669 
    670 \subsection{Implicit discriminants}
    671 
    672 If a discriminant for a variant is not specified, then it is set to one higher than the discriminant of the previous variant in the declaration. If the discriminant of the first variant in the declaration is unspecified, then it is set to zero.
    673 \begin{rust}
    674 enum Foo {
    675         Bar,                    // 0
    676         Baz = 123,        // 123
    677         Quux,              // 124
    678 }
    679 
    680 let baz_discriminant = Foo::Baz as u32;
    681 assert_eq!(baz_discriminant, 123);
    682 \end{rust}
    683 
    684 \subsection{Restrictions}
    685 
    686 It is an error when two variants share the same discriminant.
    687 \begin{rust}
    688 enum SharedDiscriminantError {
    689         SharedA = 1,
    690         SharedB = 1
    691 }
    692 
    693 enum SharedDiscriminantError2 {
    694         Zero,      // 0
    695         One,            // 1
    696         OneToo = 1  // 1 (collision with previous!)
    697 }
    698 \end{rust}
    699 It is also an error to have an unspecified discriminant where the previous discriminant is the maximum value for the size of the discriminant.
    700 \begin{rust}
    701 #[repr(u8)]
    702 enum OverflowingDiscriminantError {
    703         Max = 255,
    704         MaxPlusOne // Would be 256, but that overflows the enum.
    705 }
    706 
    707 #[repr(u8)]
    708 enum OverflowingDiscriminantError2 {
    709         MaxMinusOne = 254, // 254
    710         Max,                       // 255
    711         MaxPlusOne               // Would be 256, but that overflows the enum.
    712 }
    713 \end{rust}
    714 
    715 \subsection{Accessing discriminant}
    716 
    717 \begin{rust}
    718 Via mem::discriminant
    719 \end{rust}
    720 @mem::discriminant@ returns an opaque reference to the discriminant of an enum value which can be compared. This cannot be used to get the value of the discriminant.
    721 
    722 \subsection{Casting}
    723 
    724 If an enumeration is unit-only (with no tuple and struct variants), then its discriminant can be directly accessed with a numeric cast; e.g.:
    725 \begin{rust}
    726 enum Enum {
    727         Foo,
    728         Bar,
    729         Baz,
    730 }
    731 
    732 assert_eq!(0, Enum::Foo as isize);
    733 assert_eq!(1, Enum::Bar as isize);
    734 assert_eq!(2, Enum::Baz as isize);
    735 \end{rust}
    736 Field-less enums can be casted if they do not have explicit discriminants, or where only unit variants are explicit.
    737 \begin{rust}
    738 enum Fieldless {
    739         Tuple(),
    740         Struct{},
    741         Unit,
    742 }
    743 
    744 assert_eq!(0, Fieldless::Tuple() as isize);
    745 assert_eq!(1, Fieldless::Struct{} as isize);
    746 assert_eq!(2, Fieldless::Unit as isize);
    747 \end{rust}
    748 \begin{rust}
    749 #[repr(u8)]
    750 enum FieldlessWithDiscrimants {
    751         First = 10,
    752         Tuple(),
    753         Second = 20,
    754         Struct{},
    755         Unit,
    756 }
    757 
    758 assert_eq!(10, FieldlessWithDiscrimants::First as u8);
    759 assert_eq!(11, FieldlessWithDiscrimants::Tuple() as u8);
    760 assert_eq!(20, FieldlessWithDiscrimants::Second as u8);
    761 assert_eq!(21, FieldlessWithDiscrimants::Struct{} as u8);
    762 assert_eq!(22, FieldlessWithDiscrimants::Unit as u8);
    763 \end{rust}
    764 
    765 \subsection{Pointer casting}
    766 
    767 If the enumeration specifies a primitive representation, then the discriminant may be reliably accessed via unsafe pointer casting:
    768 \begin{rust}
    769 #[repr(u8)]
    770 enum Enum {
    771         Unit,
    772         Tuple(bool),
    773         Struct{a: bool},
    774 }
    775 
    776 impl Enum {
    777         fn discriminant(&self) -> u8 {
    778                 unsafe { *(self as *const Self as *const u8) }
    779         }
    780 }
    781 
    782 let unit_like = Enum::Unit;
    783 let tuple_like = Enum::Tuple(true);
    784 let struct_like = Enum::Struct{a: false};
    785 
    786 assert_eq!(0, unit_like.discriminant());
    787 assert_eq!(1, tuple_like.discriminant());
    788 assert_eq!(2, struct_like.discriminant());
    789 \end{rust}
    790 
    791 \subsection{Zero-variant enums}
    792 
    793 Enums with zero variants are known as zero-variant enums. As they have no valid values, they cannot be instantiated.
    794 \begin{rust}
    795 enum ZeroVariants {}
    796 \end{rust}
    797 Zero-variant enums are equivalent to the never type, but they cannot be coerced into other types.
    798 \begin{rust}
    799 let x: ZeroVariants = panic!();
    800 let y: u32 = x; // mismatched type error
    801 \end{rust}
    802 
    803 \subsection{Variant visibility}
    804 
    805 Enum variants syntactically allow a Visibility annotation, but this is rejected when the enum is validated. This allows items to be parsed with a unified syntax across different contexts where they are used.
    806 \begin{rust}
    807 macro_rules! mac_variant {
    808         ($vis:vis $name:ident) => {
    809                 enum $name {
    810                         $vis Unit,
    811 
    812                         $vis Tuple(u8, u16),
    813 
    814                         $vis Struct { f: u8 },
    815                 }
    816         }
    817 }
    818 
    819 // Empty `vis` is allowed.
    820 mac_variant! { E }
    821 
    822 // This is allowed, since it is removed before being validated.
    823 #[cfg(FALSE)]
    824 enum E {
    825         pub U,
    826         pub(crate) T(u8),
    827         pub(super) T { f: String }
    828 }
    829 \end{rust}
    830777
    831778
    832779\section{Swift}
    833 \lstnewenvironment{swift}[1][]{\lstset{language=Swift,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    834 
    835 % https://www.programiz.com/swift/online-compiler
    836 
    837 A Swift enumeration provides a heterogenous set of enumerators, like a tagged @union@, where the field name is the enumerator and its list of type parameters form its type.
    838 \begin{swift}
    839 enum Many {
    840         case Mon, Tue, Wed, Thu, Fri, Sat, Sun // basic enumerator
    841         case code( String ) // string enumerator
    842         case tuple( Int, Int, Int ) // tuple enumerator
    843 };
    844 var day = Many.Sat; // qualification to resolve type
    845 print( day );
    846 day = .Wed // no qualification after type resolved
    847 print( day );
    848 day = .code( "ABC" );
    849 print( day );
    850 day = .tuple( 1, 2, 3 );
    851 print( day );
    852 
    853 Sat
    854 Wed
    855 code("ABC")
    856 tuple(1, 2, 3)
    857 \end{swift}
    858 
     780
     781\lstnewenvironment{swift}[1][]{% necessary
     782\lstset{
     783language=Swift,
     784escapechar=\$,                                                  % LaTeX escape in code
     785moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
     786}% lstset
     787\lstset{#1}% necessary
     788}{}
     789
     790Model custom types that define a list of possible values.
    859791
    860792An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.
     
    876808\paragraph{Enumeration Syntax}
    877809
     810You introduce enumerations with the @enum@ keyword and place their entire definition within a pair of braces:
     811\begin{swift}
     812enum SomeEnumeration {
     813        // enumeration definition goes here
     814}
     815\end{swift}
     816Here's an example for the four main points of a compass:
     817\begin{swift}
     818enum CompassPoint {
     819        case north
     820        case south
     821        case east
     822        case west
     823}
     824\end{swift}
     825The values defined in an enumeration (such as @north@, @south@, @east@, and @west@) are its enumeration cases.
     826You use the @case@ keyword to introduce new enumeration cases.
    878827
    879828Note:
     
    11901139
    11911140\section{Python}
    1192 \lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    1193 
    1194 An @Enum@ is a set of symbolic names bound to unique values.
    1195 They are similar to global variables, but they offer a more useful @repr()@, grouping, type-safety, and a few other features.
    1196 
    1197 They are most useful when you have a variable that can take one of a limited selection of values. For example, the days of the week:
    1198 \begin{python}
    1199 >>> from enum import Enum
    1200 >>> class Weekday(Enum):
    1201 ...    MONDAY = 1
    1202 ...    TUESDAY = 2
    1203 ...    WEDNESDAY = 3
    1204 ...    THURSDAY = 4
    1205 ...    FRIDAY = 5
    1206 ...    SATURDAY = 6
    1207 ...    SUNDAY = 7
    1208 \end{python}
    1209 Or perhaps the RGB primary colors:
    1210 \begin{python}
    1211 >>> from enum import Enum
    1212 >>> class Color(Enum):
    1213 ...    RED = 1
    1214 ...    GREEN = 2
    1215 ...    BLUE = 3
    1216 \end{python}
    1217 As you can see, creating an @Enum@ is as simple as writing a class that inherits from @Enum@ itself.
    1218 
    1219 Note: Case of Enum Members
    1220 
    1221 Because Enums are used to represent constants, and to help avoid issues with name clashes between mixin-class methods/attributes and enum names, we strongly recommend using @UPPER_CASE@ names for members, and will be using that style in our examples.
    1222 
    1223 Depending on the nature of the enum a member's value may or may not be important, but either way that value can be used to get the corresponding member:
    1224 \begin{python}
    1225 >>> Weekday(3)
    1226 <Weekday.WEDNESDAY: 3>
    1227 \end{python}
    1228 As you can see, the @repr()@ of a member shows the enum name, the member name, and the value.
    1229 The @str()@ of a member shows only the enum name and member name:
    1230 \begin{python}
    1231 print(Weekday.THURSDAY)
    1232 Weekday.THURSDAY
    1233 \end{python}
    1234 The type of an enumeration member is the enum it belongs to:
    1235 \begin{python}
    1236 >>> type(Weekday.MONDAY)
    1237 <enum 'Weekday'>
    1238 isinstance(Weekday.FRIDAY, Weekday)
    1239 True
    1240 \end{python}
    1241 Enum members have an attribute that contains just their name:
    1242 \begin{python}
    1243 >>> print(Weekday.TUESDAY.name)
    1244 TUESDAY
    1245 \end{python}
    1246 Likewise, they have an attribute for their value:
    1247 \begin{python}
    1248 >>> Weekday.WEDNESDAY.value
    1249 3
    1250 \end{python}
    1251 Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added.
    1252 For example, @datetime.date@ has two methods for returning the weekday: @weekday()@ and @isoweekday()@.
    1253 The difference is that one of them counts from 0-6 and the other from 1-7.
    1254 Rather than keep track of that ourselves we can add a method to the @Weekday@ enum to extract the day from the date instance and return the matching enum member:
    1255 \begin{python}
    1256 $@$classmethod
    1257 def from_date(cls, date):
    1258     return cls(date.isoweekday())
    1259 \end{python}
    1260 The complete Weekday enum now looks like this:
    1261 \begin{python}
    1262 >>> class Weekday(Enum):
    1263 ...    MONDAY = 1
    1264 ...    TUESDAY = 2
    1265 ...    WEDNESDAY = 3
    1266 ...    THURSDAY = 4
    1267 ...    FRIDAY = 5
    1268 ...    SATURDAY = 6
    1269 ...    SUNDAY = 7
    1270 ...    #
    1271 ...    $@$classmethod
    1272 ...    def from_date(cls, date):
    1273 ...        return cls(date.isoweekday())
    1274 \end{python}
    1275 Now we can find out what today is! Observe:
    1276 \begin{python}
    1277 >>> from datetime import date
    1278 >>> Weekday.from_date(date.today())     
    1279 <Weekday.TUESDAY: 2>
    1280 \end{python}
    1281 Of course, if you're reading this on some other day, you'll see that day instead.
    1282 
    1283 This Weekday enum is great if our variable only needs one day, but what if we need several? Maybe we're writing a function to plot chores during a week, and don't want to use a @list@ -- we could use a different type of @Enum@:
    1284 \begin{python}
    1285 >>> from enum import Flag
    1286 >>> class Weekday(Flag):
    1287 ...    MONDAY = 1
    1288 ...    TUESDAY = 2
    1289 ...    WEDNESDAY = 4
    1290 ...    THURSDAY = 8
    1291 ...    FRIDAY = 16
    1292 ...    SATURDAY = 32
    1293 ...    SUNDAY = 64
    1294 \end{python}
    1295 We've changed two things: we're inherited from @Flag@, and the values are all powers of 2.
    1296 
    1297 Just like the original @Weekday@ enum above, we can have a single selection:
    1298 \begin{python}
    1299 >>> first_week_day = Weekday.MONDAY
    1300 >>> first_week_day
    1301 <Weekday.MONDAY: 1>
    1302 \end{python}
    1303 But @Flag@ also allows us to combine several members into a single variable:
    1304 \begin{python}
    1305 >>> weekend = Weekday.SATURDAY | Weekday.SUNDAY
    1306 >>> weekend
    1307 <Weekday.SATURDAY|SUNDAY: 96>
    1308 \end{python}
    1309 You can even iterate over a @Flag@ variable:
    1310 \begin{python}
    1311 >>> for day in weekend:
    1312 ...    print(day)
    1313 Weekday.SATURDAY
    1314 Weekday.SUNDAY
    1315 \end{python}
    1316 Okay, let's get some chores set up:
    1317 \begin{python}
    1318 >>> chores_for_ethan = {
    1319 ...    'feed the cat': Weekday.MONDAY | Weekday.WEDNESDAY | Weekday.FRIDAY,
    1320 ...    'do the dishes': Weekday.TUESDAY | Weekday.THURSDAY,
    1321 ...    'answer SO questions': Weekday.SATURDAY,
    1322 ...    }
    1323 \end{python}
    1324 And a function to display the chores for a given day:
    1325 \begin{python}
    1326 >>> def show_chores(chores, day):
    1327 ...    for chore, days in chores.items():
    1328 ...        if day in days:
    1329 ...            print(chore)
    1330 >>> show_chores(chores_for_ethan, Weekday.SATURDAY)
    1331 answer SO questions
    1332 \end{python}
    1333 In cases where the actual values of the members do not matter, you can save yourself some work and use @auto()@ for the values:
    1334 \begin{python}
    1335 >>> from enum import auto
    1336 >>> class Weekday(Flag):
    1337 ...    MONDAY = auto()
    1338 ...    TUESDAY = auto()
    1339 ...    WEDNESDAY = auto()
    1340 ...    THURSDAY = auto()
    1341 ...    FRIDAY = auto()
    1342 ...    SATURDAY = auto()
    1343 ...    SUNDAY = auto()
    1344 ...    WEEKEND = SATURDAY | SUNDAY
    1345 \end{python}
    1346 
    1347 \subsection{Programmatic access to enumeration members and their attributes}
    1348 
    1349 Sometimes it's useful to access members in enumerations programmatically (i.e. situations where @Color.RED@ won't do because the exact color is not known at program-writing time).
    1350 @Enum@ allows such access:
    1351 \begin{python}
    1352 >>> Color(1)
    1353 <Color.RED: 1>
    1354 >>> Color(3)
    1355 <Color.BLUE: 3>
    1356 \end{python}
    1357 If you want to access enum members by name, use item access:
    1358 \begin{python}
    1359 Color['RED']
    1360 <Color.RED: 1>
    1361 
    1362 Color['GREEN']
    1363 <Color.GREEN: 2>
    1364 \end{python}
    1365 If you have an enum member and need its name or value:
    1366 \begin{python}
    1367 >>> member = Color.RED
    1368 >>> member.name
    1369 'RED'
    1370 >>> member.value
    1371 1
    1372 \end{python}
    1373 
    1374 \subsection{Duplicating enum members and values}
    1375 
    1376 Having two enum members with the same name is invalid:
    1377 \begin{python}
    1378 >>> class Shape(Enum):
    1379 ...    SQUARE = 2
    1380 ...    SQUARE = 3
    1381 ...
    1382 Traceback (most recent call last):
    1383 ...
    1384 TypeError: 'SQUARE' already defined as 2
    1385 \end{python}
    1386 However, an enum member can have other names associated with it.
    1387 Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@.
    1388 By-value lookup of the value of @A@ will return the member @A@.
    1389 By-name lookup of @A@ will return the member @A@.
    1390 By-name lookup of @B@ will also return the member @A@:
    1391 \begin{python}
    1392 >>> class Shape(Enum):
    1393 ...    SQUARE = 2
    1394 ...    DIAMOND = 1
    1395 ...    CIRCLE = 3
    1396 ...    ALIAS_FOR_SQUARE = 2
    1397 ...
    1398 >>> Shape.SQUARE
    1399 <Shape.SQUARE: 2>
    1400 >>> Shape.ALIAS_FOR_SQUARE
    1401 <Shape.SQUARE: 2>
    1402 >>> Shape(2)
    1403 <Shape.SQUARE: 2>
    1404 \end{python}
    1405 
    1406 Note: Attempting to create a member with the same name as an already defined attribute (another member, a method, etc.) or attempting to create an attribute with the same name as a member is not allowed.
    1407 
    1408 \subsection{Ensuring unique enumeration values}
    1409 
    1410 By default, enumerations allow multiple names as aliases for the same value.
    1411 When this behavior isn't desired, you can use the @unique()@ decorator:
    1412 \begin{python}
    1413 >>> from enum import Enum, unique
    1414 >>> $@$unique
    1415 ... class Mistake(Enum):
    1416 ...     ONE = 1
    1417 ...     TWO = 2
    1418 ...     THREE = 3
    1419 ...     FOUR = 3
    1420 ...
    1421 Traceback (most recent call last):
    1422 ...
    1423 ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
    1424 \end{python}
    1425 
    1426 \subsection{Using automatic values}
    1427 
    1428 If the exact value is unimportant you can use @auto@:
    1429 \begin{python}
    1430 >>> from enum import Enum, auto
    1431 >>> class Color(Enum):
    1432 ...     RED = auto()
    1433 ...     BLUE = auto()
    1434 ...     GREEN = auto()
    1435 ...
    1436 >>> [member.value for member in Color]
    1437 [1, 2, 3]
    1438 \end{python}
    1439 The values are chosen by \_generate\_next\_value\_(), which can be overridden:
    1440 \begin{python}
    1441 >>> class AutoName(Enum):
    1442 ...     $@$staticmethod
    1443 ...     def _generate_next_value_(name, start, count, last_values):
    1444 ...         return name
    1445 ...
    1446 >>> class Ordinal(AutoName):
    1447 ...     NORTH = auto()
    1448 ...     SOUTH = auto()
    1449 ...     EAST = auto()
    1450 ...     WEST = auto()
    1451 ...
    1452 >>> [member.value for member in Ordinal]
    1453 ['NORTH', 'SOUTH', 'EAST', 'WEST']
    1454 \end{python}
    1455 Note The @_generate_next_value_()@ method must be defined before any members.
    1456 
    1457 \subsection{Iteration}
    1458 
    1459 Iterating over the members of an enum does not provide the aliases:
    1460 \begin{python}
    1461 >>> list(Shape)
    1462 [<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
    1463 >>> list(Weekday)
    1464 [<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>,
    1465 <Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]
    1466 \end{python}
    1467 Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Weekday.WEEKEND@ aren't shown.
    1468 
    1469 The special attribute @__members__@ is a read-only ordered mapping of names to members.
    1470 It includes all names defined in the enumeration, including the aliases:
    1471 \begin{python}
    1472 >>> for name, member in Shape.__members__.items():
    1473 ...     name, member
    1474 ...
    1475 ('SQUARE', <Shape.SQUARE: 2>)
    1476 ('DIAMOND', <Shape.DIAMOND: 1>)
    1477 ('CIRCLE', <Shape.CIRCLE: 3>)
    1478 ('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)
    1479 \end{python}
    1480 The @__members__@ attribute can be used for detailed programmatic access to the enumeration members.
    1481 For example, finding all the aliases:
    1482 \begin{python}
    1483 >>> [name for name, member in Shape.__members__.items() if member.name != name]
    1484 ['ALIAS_FOR_SQUARE']
    1485 \end{python}
    1486 Note: Aliases for flags include values with multiple flags set, such as 3, and no flags set, i.e. 0.
    1487 
    1488 \subsection{Comparisons}
    1489 
    1490 Enumeration members are compared by identity:
    1491 \begin{python}
    1492 >>> Color.RED is Color.RED
    1493 True
    1494 >>> Color.RED is Color.BLUE
    1495 False
    1496 >>> Color.RED is not Color.BLUE
    1497 True
    1498 \end{python}
    1499 Ordered comparisons between enumeration values are not supported.
    1500 Enum members are not integers (but see @IntEnum@ below):
    1501 \begin{python}
    1502 >>> Color.RED < Color.BLUE
    1503 Traceback (most recent call last):
    1504   File "<stdin>", line 1, in <module>
    1505 TypeError: '<' not supported between instances of 'Color' and 'Color'
    1506 \end{python}
    1507 Equality comparisons are defined though:
    1508 \begin{python}
    1509 >>> Color.BLUE == Color.RED
    1510 False
    1511 >>> Color.BLUE != Color.RED
    1512 True
    1513 >>> Color.BLUE == Color.BLUE
    1514 True
    1515 \end{python}
    1516 Comparisons against non-enumeration values will always compare not equal (again, @IntEnum@ was explicitly designed to behave differently, see below):
    1517 \begin{python}
    1518 >>> Color.BLUE == 2
    1519 False
    1520 \end{python}
    1521 
    1522 Warning: It is possible to reload modules -- if a reloaded module contains enums, they will be recreated, and the new members may not compare identical/equal to the original members.
    1523 
    1524 \subsection{Allowed members and attributes of enumerations}
    1525 
    1526 Most of the examples above use integers for enumeration values.
    1527 Using integers is short and handy (and provided by default by the Functional API), but not strictly enforced.
    1528 In the vast majority of use-cases, one doesn't care what the actual value of an enumeration is.
    1529 But if the value is important, enumerations can have arbitrary values.
    1530 
    1531 Enumerations are Python classes, and can have methods and special methods as usual. If we have this enumeration:
    1532 \begin{python}
    1533 >>> class Mood(Enum):
    1534 ...     FUNKY = 1
    1535 ...     HAPPY = 3
    1536 ...
    1537 ...     def describe(self):
    1538 ...         # self is the member here
    1539 ...         return self.name, self.value
    1540 ...
    1541 ...     def __str__(self):
    1542 ...         return 'my custom str! {0}'.format(self.value)
    1543 ...
    1544 ...     $@$classmethod
    1545 ...
    1546 ...     def favorite_mood(cls):
    1547 ...         # cls here is the enumeration
    1548 ...         return cls.HAPPY
    1549 ...
    1550 \end{python}
    1551 Then:
    1552 \begin{python}
    1553 >>> Mood.favorite_mood()
    1554 <Mood.HAPPY: 3>
    1555 >>> Mood.HAPPY.describe()
    1556 ('HAPPY', 3)
    1557 >>> str(Mood.FUNKY)
    1558 'my custom str! 1'
    1559 \end{python}
    1560 The rules for what is allowed are as follows: names that start and end with a single underscore are reserved by enum and cannot be used;
    1561 all other attributes defined within an enumeration will become members of this enumeration, with the exception of special methods (@__str__()@, @__add__()@, etc.), descriptors (methods are also descriptors), and variable names listed in @_ignore_@.
    1562 
    1563 Note: if your enumeration defines @__new__()@ and/or @__init__()@, any value(s) given to the enum member will be passed into those methods.
    1564 See Planet for an example.
    1565 
    1566 Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
    1567 it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
    1568 See When to use @__new__()@ vs. @__init__()@ for more details.
    1569 
    1570 \subsection{Restricted Enum subclassing}
    1571 
    1572 A new @Enum@ class must have one base enum class, up to one concrete data type, and as many object-based mixin classes as needed.
    1573 The order of these base classes is:
    1574 \begin{python}
    1575 class EnumName([mix-in, ...,] [data-type,] base-enum):
    1576     pass
    1577 \end{python}
    1578 Also, subclassing an enumeration is allowed only if the enumeration does not define any members.
    1579 So this is forbidden:
    1580 \begin{python}
    1581 >>> class MoreColor(Color):
    1582 ...     PINK = 17
    1583 ...
    1584 Traceback (most recent call last):
    1585 ...
    1586 TypeError: <enum 'MoreColor'> cannot extend <enum 'Color'>
    1587 \end{python}
    1588 But this is allowed:
    1589 \begin{python}
    1590 >>> class Foo(Enum):
    1591 ...     def some_behavior(self):
    1592 ...         pass
    1593 ...
    1594 >>> class Bar(Foo):
    1595 ...     HAPPY = 1
    1596 ...     SAD = 2
    1597 ...
    1598 \end{python}
    1599 Allowing subclassing of enums that define members would lead to a violation of some important invariants of types and instances.
    1600 On the other hand, it makes sense to allow sharing some common behavior between a group of enumerations. (See OrderedEnum for an example.)
    1601 
    1602 \subsection{Dataclass support}
    1603 
    1604 When inheriting from a @dataclass@, the @__repr__()@ omits the inherited class' name.
    1605 For example:
    1606 \begin{python}
    1607 >>> from dataclasses import dataclass, field
    1608 >>> $@$dataclass
    1609 ... class CreatureDataMixin:
    1610 ...     size: str
    1611 ...     legs: int
    1612 ...     tail: bool = field(repr=False, default=True)
    1613 ...
    1614 >>> class Creature(CreatureDataMixin, Enum):
    1615 ...     BEETLE = 'small', 6
    1616 ...     DOG = 'medium', 4
    1617 ...
    1618 >>> Creature.DOG
    1619 <Creature.DOG: size='medium', legs=4>
    1620 \end{python}
    1621 Use the @dataclass()@ argument repr=False to use the standard @repr()@.
    1622 
    1623 Changed in version 3.12: Only the dataclass fields are shown in the value area, not the dataclass' name.
    1624 
    1625 \subsection{Pickling}
    1626 
    1627 Enumerations can be pickled and unpickled:
    1628 \begin{python}
    1629 >>> from test.test_enum import Fruit
    1630 >>> from pickle import dumps, loads
    1631 >>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
    1632 True
    1633 \end{python}
    1634 The usual restrictions for pickling apply: picklable enums must be defined in the top level of a module, since unpickling requires them to be importable from that module.
    1635 
    1636 Note: With pickle protocol version 4 it is possible to easily pickle enums nested in other classes.
    1637 
    1638 It is possible to modify how enum members are pickled/unpickled by defining @__reduce_ex__()@ in the enumeration class.
    1639 The default method is by-value, but enums with complicated values may want to use by-name:
    1640 \begin{python}
    1641 >>> import enum
    1642 >>> class MyEnum(enum.Enum):
    1643 ...     __reduce_ex__ = enum.pickle_by_enum_name
    1644 \end{python}
    1645 Note: Using by-name for flags is not recommended, as unnamed aliases will not unpickle.
    1646 
    1647 \subsection{Functional API}
    1648 
    1649 The @Enum@ class is callable, providing the following functional API:
    1650 \begin{python}
    1651 >>> Animal = Enum('Animal', 'ANT BEE CAT DOG')
    1652 >>> Animal
    1653 <enum 'Animal'>
    1654 >>> Animal.ANT
    1655 <Animal.ANT: 1>
    1656 >>> list(Animal)
    1657 [<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]
    1658 \end{python}
    1659 The semantics of this API resemble @namedtuple@.
    1660 The first argument of the call to @Enum@ is the name of the enumeration.
    1661 
    1662 The second argument is the source of enumeration member names.
    1663 It can be a whitespace-separated string of names, a sequence of names, a sequence of 2-tuples with key/value pairs, or a mapping (e.g. dictionary) of names to values.
    1664 The last two options enable assigning arbitrary values to enumerations;
    1665 the others auto-assign increasing integers starting with 1 (use the @start@ parameter to specify a different starting value).
    1666 A new class derived from @Enum@ is returned.
    1667 In other words, the above assignment to Animal is equivalent to:
    1668 \begin{python}
    1669 >>> class Animal(Enum):
    1670 ...     ANT = 1
    1671 ...     BEE = 2
    1672 ...     CAT = 3
    1673 ...     DOG = 4
    1674 ...
    1675 \end{python}
    1676 The reason for defaulting to 1 as the starting number and not 0 is that 0 is @False@ in a boolean sense, but by default enum members all evaluate to @True@.
    1677 
    1678 Pickling enums created with the functional API can be tricky as frame stack implementation details are used to try and figure out which module the enumeration is being created in (e.g. it will fail if you use a utility function in a separate module, and also may not work on IronPython or Jython).
    1679 The solution is to specify the module name explicitly as follows:
    1680 \begin{python}
    1681 >>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)
    1682 \end{python}
    1683 Warning: If module is not supplied, and @Enum@ cannot determine what it is, the new @Enum@ members will not be unpicklable; to keep errors closer to the source, pickling will be disabled.
    1684 
    1685 The new pickle protocol 4 also, in some circumstances, relies on @__qualname__@ being set to the location where pickle will be able to find the class.
    1686 For example, if the class was made available in class SomeData in the global scope:
    1687 \begin{python}
    1688 >>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')
    1689 \end{python}
    1690 The complete signature is:
    1691 \begin{python}
    1692 Enum(
    1693     value='NewEnumName',
    1694     names=<...>,
    1695     *,
    1696     module='...',
    1697     qualname='...',
    1698     type=<mixed-in class>,
    1699     start=1,
    1700     )
    1701 \end{python}
    1702 \begin{itemize}
    1703 \item
    1704 @value@: What the new enum class will record as its name.
    1705 \item
    1706 @names@: The enum members.
    1707 This can be a whitespace- or comma-separated string (values will start at 1 unless otherwise specified):
    1708 \begin{python}
    1709 'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'
    1710 \end{python}
    1711 or an iterator of names:
    1712 \begin{python}
    1713 ['RED', 'GREEN', 'BLUE']
    1714 \end{python}
    1715 or an iterator of (name, value) pairs:
    1716 \begin{python}
    1717 [('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]
    1718 \end{python}
    1719 or a mapping:
    1720 \begin{python}
    1721 {'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}
    1722 \end{python}
    1723 \item
    1724 module: name of module where new enum class can be found.
    1725 \item
    1726 @qualname@: where in module new enum class can be found.
    1727 \item
    1728 @type@: type to mix in to new enum class.
    1729 \item
    1730 @start@: number to start counting at if only names are passed in.
    1731 \end{itemize}
    1732 Changed in version 3.5: The start parameter was added.
    1733 
    1734 \subsection{Derived Enumerations}
    1735 
    1736 \subsection{IntEnum}
    1737 
    1738 The first variation of @Enum@ that is provided is also a subclass of @int@.
    1739 Members of an @IntEnum@ can be compared to integers;
    1740 by extension, integer enumerations of different types can also be compared to each other:
    1741 \begin{python}
    1742 >>> from enum import IntEnum
    1743 >>> class Shape(IntEnum):
    1744 ...     CIRCLE = 1
    1745 ...     SQUARE = 2
    1746 ...
    1747 >>> class Request(IntEnum):
    1748 ...     POST = 1
    1749 ...     GET = 2
    1750 ...
    1751 >>> Shape == 1
    1752 False
    1753 >>> Shape.CIRCLE == 1
    1754 True
    1755 >>> Shape.CIRCLE == Request.POST
    1756 True
    1757 \end{python}
    1758 However, they still can't be compared to standard @Enum@ enumerations:
    1759 \begin{python}
    1760 >>> class Shape(IntEnum):
    1761 ...     CIRCLE = 1
    1762 ...     SQUARE = 2
    1763 ...
    1764 >>> class Color(Enum):
    1765 ...     RED = 1
    1766 ...     GREEN = 2
    1767 ...
    1768 >>> Shape.CIRCLE == Color.RED
    1769 False
    1770 \end{python}
    1771 @IntEnum@ values behave like integers in other ways you'd expect:
    1772 \begin{python}
    1773 >>> int(Shape.CIRCLE)
    1774 1
    1775 >>> ['a', 'b', 'c'][Shape.CIRCLE]
    1776 'b'
    1777 >>> [i for i in range(Shape.SQUARE)]
    1778 [0, 1]
    1779 \end{python}
    1780 
    1781 \subsection{StrEnum}
    1782 
    1783 The second variation of @Enum@ that is provided is also a subclass of @str@.
    1784 Members of a @StrEnum@ can be compared to strings;
    1785 by extension, string enumerations of different types can also be compared to each other.
    1786 
    1787 New in version 3.11.
    1788 
    1789 \subsection{IntFlag}
    1790 
    1791 The next variation of @Enum@ provided, @IntFlag@, is also based on @int@.
    1792 The difference being @IntFlag@ members can be combined using the bitwise operators (@&, |, ^, ~@) and the result is still an @IntFlag@ member, if possible.
    1793 Like @IntEnum@, @IntFlag@ members are also integers and can be used wherever an int is used.
    1794 
    1795 Note: Any operation on an IntFlag member besides the bit-wise operations will lose the @IntFlag@ membership.
    1796 
    1797 Bit-wise operations that result in invalid @IntFlag@ values will lose the @IntFlag@ membership.
    1798 See @FlagBoundary@ for details.
    1799 
    1800 New in version 3.6.
    1801 
    1802 Changed in version 3.11.
    1803 
    1804 Sample @IntFlag@ class:
    1805 \begin{python}
    1806 >>> from enum import IntFlag
    1807 >>> class Perm(IntFlag):
    1808 ...     R = 4
    1809 ...     W = 2
    1810 ...     X = 1
    1811 ...
    1812 >>> Perm.R | Perm.W
    1813 <Perm.R|W: 6>
    1814 >>> Perm.R + Perm.W
    1815 6
    1816 >>> RW = Perm.R | Perm.W
    1817 >>> Perm.R in RW
    1818 True
    1819 \end{python}
    1820 It is also possible to name the combinations:
    1821 \begin{python}
    1822 >>> class Perm(IntFlag):
    1823 ...     R = 4
    1824 ...     W = 2
    1825 ...     X = 1
    1826 ...     RWX = 7
    1827 ...
    1828 >>> Perm.RWX
    1829 <Perm.RWX: 7>
    1830 >>> ~Perm.RWX
    1831 <Perm: 0>
    1832 >>> Perm(7)
    1833 <Perm.RWX: 7>
    1834 \end{python}
    1835 Note: Named combinations are considered aliases. Aliases do not show up during iteration, but can be returned from by-value lookups.
    1836 
    1837 Changed in version 3.11.
    1838 
    1839 Another important difference between @IntFlag@ and @Enum@ is that if no flags are set (the value is 0), its boolean evaluation is @False@:
    1840 \begin{python}
    1841 >>> Perm.R & Perm.X
    1842 <Perm: 0>
    1843 >>> bool(Perm.R & Perm.X)
    1844 False
    1845 \end{python}
    1846 Because @IntFlag@ members are also subclasses of int they can be combined with them (but may lose @IntFlag@ membership:
    1847 \begin{python}
    1848 >>> Perm.X | 4
    1849 <Perm.R|X: 5>
    1850 
    1851 >>> Perm.X + 8
    1852 9
    1853 \end{python}
    1854 Note: The negation operator, @~@, always returns an @IntFlag@ member with a positive value:
    1855 \begin{python}
    1856 >>> (~Perm.X).value == (Perm.R|Perm.W).value == 6
    1857 True
    1858 \end{python}
    1859 @IntFlag@ members can also be iterated over:
    1860 \begin{python}
    1861 >>> list(RW)
    1862 [<Perm.R: 4>, <Perm.W: 2>]
    1863 \end{python}
    1864 New in version 3.11.
    1865 
    1866 \subsection{Flag}
    1867 
    1868 The last variation is @Flag@.
    1869 Like @IntFlag@, @Flag@ members can be combined using the bitwise operators (@&, |, ^, ~@).
    1870 Unlike @IntFlag@, they cannot be combined with, nor compared against, any other @Flag@ enumeration, nor @int@.
    1871 While it is possible to specify the values directly it is recommended to use @auto@ as the value and let @Flag@ select an appropriate value.
    1872 
    1873 New in version 3.6.
    1874 
    1875 Like @IntFlag@, if a combination of @Flag@ members results in no flags being set, the boolean evaluation is @False@:
    1876 \begin{python}
    1877 >>> from enum import Flag, auto
    1878 >>> class Color(Flag):
    1879 ...     RED = auto()
    1880 ...     BLUE = auto()
    1881 ...     GREEN = auto()
    1882 ...
    1883 >>> Color.RED & Color.GREEN
    1884 <Color: 0>
    1885 >>> bool(Color.RED & Color.GREEN)
    1886 False
    1887 \end{python}
    1888 Individual flags should have values that are powers of two (1, 2, 4, 8, ...), while combinations of flags will not:
    1889 \begin{python}
    1890 >>> class Color(Flag):
    1891 ...     RED = auto()
    1892 ...     BLUE = auto()
    1893 ...     GREEN = auto()
    1894 ...     WHITE = RED | BLUE | GREEN
    1895 ...
    1896 >>> Color.WHITE
    1897 <Color.WHITE: 7>
    1898 \end{python}
    1899 Giving a name to the ``no flags set'' condition does not change its boolean value:
    1900 \begin{python}
    1901 >>> class Color(Flag):
    1902 ...     BLACK = 0
    1903 ...     RED = auto()
    1904 ...     BLUE = auto()
    1905 ...     GREEN = auto()
    1906 ...
    1907 >>> Color.BLACK
    1908 <Color.BLACK: 0>
    1909 >>> bool(Color.BLACK)
    1910 False
    1911 \end{python}
    1912 @Flag@ members can also be iterated over:
    1913 \begin{python}
    1914 >>> purple = Color.RED | Color.BLUE
    1915 >>> list(purple)
    1916 [<Color.RED: 1>, <Color.BLUE: 2>]
    1917 \end{python}
    1918 New in version 3.11.
    1919 
    1920 Note: For the majority of new code, @Enum@ and @Flag@ are strongly recommended, since @IntEnum@ and @IntFlag@ break some semantic promises of an enumeration (by being comparable to integers, and thus by transitivity to other unrelated enumerations).
    1921 @IntEnum@ and @IntFlag@ should be used only in cases where @Enum@ and @Flag@ will not do;
    1922 for example, when integer constants are replaced with enumerations, or for interoperability with other systems.
    1923 
    1924 \subsection{Others}
    1925 
    1926 While @IntEnum@ is part of the enum module, it would be very simple to implement independently:
    1927 \begin{python}
    1928 class IntEnum(int, Enum):
    1929     pass
    1930 \end{python}
    1931 This demonstrates how similar derived enumerations can be defined;
    1932 for example a @FloatEnum@ that mixes in float instead of @int@.
    1933 
    1934 Some rules:
    1935 \begin{itemize}
    1936 \item
    1937 When subclassing @Enum@, mix-in types must appear before @Enum@ itself in the sequence of bases, as in the @IntEnum@ example above.
    1938 \item
    1939 Mix-in types must be subclassable.
    1940 For example, @bool@ and @range@ are not subclassable and will throw an error during Enum creation if used as the mix-in type.
    1941 \item
    1942 While @Enum@ can have members of any type, once you mix in an additional type, all the members must have values of that type, e.g. @int@ above.
    1943 This restriction does not apply to mix-ins which only add methods and don't specify another type.
    1944 \item
    1945 When another data type is mixed in, the value attribute is not the same as the enum member itself, although it is equivalent and will compare equal.
    1946 \item
    1947 A data type is a mixin that defines @__new__()@, or a @dataclass@
    1948 \item
    1949 \%-style formatting: @%s@ and @%r@ call the @Enum@ class's @__str__()@ and @__repr__()@ respectively; other codes (such as @%i@ or @%h@ for @IntEnum@) treat the enum member as its mixed-in type.
    1950 \item
    1951 Formatted string literals, @str.format()@, and format() will use the enum's @__str__()@ method.
    1952 \end{itemize}
    1953 Note: Because @IntEnum@, @IntFlag@, and @StrEnum@ are designed to be drop-in replacements for existing constants, their @__str__()@ method has been reset to their data types' @__str__()@ method.
    1954 
    1955 \subsection{When to use \lstinline{__new__()} vs. \lstinline{__init__()}}
    1956 
    1957 @__new__()@ must be used whenever you want to customize the actual value of the @Enum@ member.
    1958 Any other modifications may go in either @__new__()@ or @__init__()@, with @__init__()@ being preferred.
    1959 
    1960 For example, if you want to pass several items to the constructor, but only want one of them to be the value:
    1961 \begin{python}
    1962 >>> class Coordinate(bytes, Enum):
    1963 ...     """
    1964 ...     Coordinate with binary codes that can be indexed by the int code.
    1965 ...     """
    1966 ...     def __new__(cls, value, label, unit):
    1967 ...         obj = bytes.__new__(cls, [value])
    1968 ...         obj._value_ = value
    1969 ...         obj.label = label
    1970 ...         obj.unit = unit
    1971 ...         return obj
    1972 ...     PX = (0, 'P.X', 'km')
    1973 ...     PY = (1, 'P.Y', 'km')
    1974 ...     VX = (2, 'V.X', 'km/s')
    1975 ...     VY = (3, 'V.Y', 'km/s')
    1976 
    1977 >>> print(Coordinate['PY'])
    1978 Coordinate.PY
    1979 
    1980 >>> print(Coordinate(3))
    1981 Coordinate.VY
    1982 \end{python}
    1983 Warning: Do not call @super().__new__()@, as the lookup-only @__new__@ is the one that is found; instead, use the data type directly.
    1984 
    1985 \subsection{Finer Points}
    1986 
    1987 Supported @__dunder__@ names
    1988 
    1989 @__members__@ is a read-only ordered mapping of member\_name:member items. It is only available on the class.
    1990 
    1991 @__new__()@, if specified, must create and return the enum members; it is also a very good idea to set the member's @_value_@ appropriately. Once all the members are created it is no longer used.
    1992 Supported @_sunder_@ names
    1993 \begin{itemize}
    1994 \item
    1995 @_name_@ -- name of the member
    1996 \item
    1997 @_value_@ -- value of the member; can be set / modified in @__new__@
    1998 \item
    1999 @_missing_@ -- a lookup function used when a value is not found; may be overridden
    2000 \item
    2001 @_ignore_@ -- a list of names, either as a @list@ or a @str@, that will not be transformed into members, and will be removed from the final class
    2002 \item
    2003 @_order_@ -- used in Python 2/3 code to ensure member order is consistent (class attribute, removed during class creation)
    2004 \item
    2005 @_generate_@next@_value_@ -- used by the Functional API and by @auto@ to get an appropriate value for an enum member; may be overridden
    2006 \end{itemize}
    2007 Note: For standard @Enum@ classes the next value chosen is the last value seen incremented by one.
    2008 
    2009 For @Flag@ classes the next value chosen will be the next highest power-of-two, regardless of the last value seen.
    2010 
    2011 New in version 3.6: @_missing_@, @_order_@, @_generate_@next@_value_@
    2012 
    2013 New in version 3.7: @_ignore_@
    2014 
    2015 To help keep Python 2 / Python 3 code in sync an @_order_@ attribute can be provided.
    2016 It will be checked against the actual order of the enumeration and raise an error if the two do not match:
    2017 \begin{python}
    2018 >>> class Color(Enum):
    2019 ...     _order_ = 'RED GREEN BLUE'
    2020 ...     RED = 1
    2021 ...     BLUE = 3
    2022 ...     GREEN = 2
    2023 ...
    2024 Traceback (most recent call last):
    2025 ...
    2026 TypeError: member order does not match _order_:
    2027   ['RED', 'BLUE', 'GREEN']
    2028   ['RED', 'GREEN', 'BLUE']
    2029 \end{python}
    2030 Note: In Python 2 code the @_order_@ attribute is necessary as definition order is lost before it can be recorded.
    2031 
    2032 \subsection{\lstinline{_Private__names}}
    2033 
    2034 Private names are not converted to enum members, but remain normal attributes.
    2035 
    2036 Changed in version 3.11.
    2037 
    2038 \subsection{\lstinline{Enum} member type}
    2039 
    2040 @Enum@ members are instances of their enum class, and are normally accessed as @EnumClass.member@.
    2041 In certain situations, such as writing custom enum behavior, being able to access one member directly from another is useful, and is supported;
    2042 however, in order to avoid name clashes between member names and attributes/methods from mixed-in classes, upper-case names are strongly recommended.
    2043 
    2044 Changed in version 3.5.
    2045 
    2046 \subsection{Creating members that are mixed with other data types}
    2047 
    2048 When subclassing other data types, such as @int@ or @str@, with an @Enum@, all values after the = @are@ passed to that data type's constructor. For example:
    2049 \begin{python}
    2050 >>> class MyEnum(IntEnum):      # help(int) -> int(x, base=10) -> integer
    2051 ...     example = '11', 16      # so x='11' and base=16
    2052 ...
    2053 MyEnum.example.value        # and hex(11) is...
    2054 17
    2055 \end{python}
    2056 
    2057 \subsection{\lstinline{Boolean} value of \lstinline{Enum} classes and members}
    2058 
    2059 Enum classes that are mixed with non-@Enum@ types (such as @int@, @str@, etc.) are evaluated according to the mixed-in type's rules;
    2060 otherwise, all members evaluate as @True@.
    2061 To make your own enum's boolean evaluation depend on the member's value add the following to your class:
    2062 \begin{python}
    2063 def __bool__(self):
    2064     return bool(self.value)
    2065 \end{python}
    2066 Plain @Enum@ classes always evaluate as @True@.
    2067 
    2068 \subsection{\lstinline{Enum} classes with methods}
    2069 
    2070 If you give your enum subclass extra methods, like the Planet class below, those methods will show up in a dir() of the member, but not of the class:
    2071 \begin{python}
    2072 >>> dir(Planet)                         
    2073 ['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS',
    2074  '__class__', '__doc__', '__members__', '__module__']
    2075 >>> dir(Planet.EARTH)                   
    2076 ['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value']
    2077 \end{python}
    2078 
    2079 \subsection{Combining members of \lstinline{Flag}}
    2080 
    2081 Iterating over a combination of @Flag@ members will only return the members that are comprised of a single bit:
    2082 \begin{python}
    2083 >>> class Color(Flag):
    2084 ...     RED = auto()
    2085 ...     GREEN = auto()
    2086 ...     BLUE = auto()
    2087 ...     MAGENTA = RED | BLUE
    2088 ...     YELLOW = RED | GREEN
    2089 ...     CYAN = GREEN | BLUE
    2090 ...
    2091 >>> Color(3)  # named combination
    2092 <Color.YELLOW: 3>
    2093 >>> Color(7)      # not named combination
    2094 <Color.RED|GREEN|BLUE: 7>
    2095 \end{python}
    2096 
    2097 \subsection{\lstinline{Flag} and \lstinline{IntFlag} minutia}
    2098 
    2099 Using the following snippet for our examples:
    2100 \begin{python}
    2101 >>> class Color(IntFlag):
    2102 ...     BLACK = 0
    2103 ...     RED = 1
    2104 ...     GREEN = 2
    2105 ...     BLUE = 4
    2106 ...     PURPLE = RED | BLUE
    2107 ...     WHITE = RED | GREEN | BLUE
    2108 ...
    2109 \end{python}
    2110 the following are true:
    2111 \begin{itemize}
    2112 \item
    2113 single-bit flags are canonical
    2114 \item
    2115 multi-bit and zero-bit flags are aliases
    2116 \item
    2117 only canonical flags are returned during iteration:
    2118 \begin{python}
    2119 >>> list(Color.WHITE)
    2120 [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
    2121 \end{python}
    2122 negating a flag or flag set returns a new flag/flag set with the corresponding positive integer value:
    2123 \begin{python}
    2124 >>> Color.BLUE
    2125 <Color.BLUE: 4>
    2126 
    2127 >>> ~Color.BLUE
    2128 <Color.RED|GREEN: 3>
    2129 \end{python}
    2130 \item
    2131 names of pseudo-flags are constructed from their members' names:
    2132 \begin{python}
    2133 >>> (Color.RED | Color.GREEN).name
    2134 'RED|GREEN'
    2135 \end{python}
    2136 \item
    2137 multi-bit flags, aka aliases, can be returned from operations:
    2138 \begin{python}
    2139 >>> Color.RED | Color.BLUE
    2140 <Color.PURPLE: 5>
    2141 
    2142 >>> Color(7)  # or Color(-1)
    2143 <Color.WHITE: 7>
    2144 
    2145 >>> Color(0)
    2146 <Color.BLACK: 0>
    2147 \end{python}
    2148 \item
    2149 membership / containment checking: zero-valued flags are always considered to be contained:
    2150 \begin{python}
    2151 >>> Color.BLACK in Color.WHITE
    2152 True
    2153 \end{python}
    2154 otherwise, only if all bits of one flag are in the other flag will True be returned:
    2155 \begin{python}
    2156 >>> Color.PURPLE in Color.WHITE
    2157 True
    2158 
    2159 >>> Color.GREEN in Color.PURPLE
    2160 False
    2161 \end{python}
    2162 \end{itemize}
    2163 There is a new boundary mechanism that controls how out-of-range / invalid bits are handled: @STRICT@, @CONFORM@, @EJECT@, and @KEEP@:
    2164 \begin{itemize}
    2165 \item
    2166 @STRICT@ --> raises an exception when presented with invalid values
    2167 \item
    2168 @CONFORM@ --> discards any invalid bits
    2169 \item
    2170 @EJECT@ --> lose Flag status and become a normal int with the given value
    2171 \item
    2172 @KEEP@ --> keep the extra bits
    2173 \begin{itemize}
    2174 \item
    2175 keeps Flag status and extra bits
    2176 \item
    2177 extra bits do not show up in iteration
    2178 \item
    2179 extra bits do show up in repr() and str()
    2180 \end{itemize}
    2181 \end{itemize}
    2182 The default for @Flag@ is @STRICT@, the default for @IntFlag@ is @EJECT@, and the default for @_convert_@ is @KEEP@ (see @ssl.Options@ for an example of when @KEEP@ is needed).
    2183 
    2184 \section{How are Enums and Flags different?}
    2185 
    2186 Enums have a custom metaclass that affects many aspects of both derived @Enum@ classes and their instances (members).
    2187 
    2188 \subsection{Enum Classes}
    2189 
    2190 The @EnumType@ metaclass is responsible for providing the @__contains__()@, @__dir__()@, @__iter__()@ and other methods that allow one to do things with an @Enum@ class that fail on a typical class, such as @list(Color)@ or @some_enum_var@ in @Color@.
    2191 @EnumType@ is responsible for ensuring that various other methods on the final @Enum@ class are correct (such as @__new__()@, @__getnewargs__()@, @__str__()@ and @__repr__()@).
    2192 
    2193 \subsection{Flag Classes}
    2194 
    2195 Flags have an expanded view of aliasing: to be canonical, the value of a flag needs to be a power-of-two value, and not a duplicate name.
    2196 So, in addition to the @Enum@ definition of alias, a flag with no value (a.k.a. 0) or with more than one power-of-two value (e.g. 3) is considered an alias.
    2197 
    2198 \subsection{Enum Members (aka instances)}
    2199 
    2200 The most interesting thing about enum members is that they are singletons.
    2201 @EnumType@ creates them all while it is creating the enum class itself, and then puts a custom @__new__()@ in place to ensure that no new ones are ever instantiated by returning only the existing member instances.
    2202 
    2203 \subsection{Flag Members}
    2204 
    2205 Flag members can be iterated over just like the @Flag@ class, and only the canonical members will be returned.
    2206 For example:
    2207 \begin{python}
    2208 >>> list(Color)
    2209 [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
    2210 \end{python}
    2211 (Note that BLACK, PURPLE, and WHITE do not show up.)
    2212 
    2213 Inverting a flag member returns the corresponding positive value, rather than a negative value -- for example:
    2214 \begin{python}
    2215 >>> ~Color.RED
    2216 <Color.GREEN|BLUE: 6>
    2217 \end{python}
    2218 Flag members have a length corresponding to the number of power-of-two values they contain. For example:
    2219 \begin{python}
    2220 >>> len(Color.PURPLE)
    2221 2
    2222 \end{python}
    2223 
    2224 \subsection{Enum Cookbook}
    2225 
    2226 While @Enum@, @IntEnum@, @StrEnum@, @Flag@, and @IntFlag@ are expected to cover the majority of use-cases, they cannot cover them all. Here are recipes for some different types of enumerations that can be used directly, or as examples for creating one's own.
    2227 
    2228 \subsection{Omitting values}
    2229 
    2230 In many use-cases, one doesn't care what the actual value of an enumeration is. There are several ways to define this type of simple enumeration:
    2231 \begin{itemize}
    2232 \item
    2233 use instances of auto for the value
    2234 \item
    2235 use instances of object as the value
    2236 \item
    2237 use a descriptive string as the value
    2238 \item
    2239 use a tuple as the value and a custom @__new__()@ to replace the tuple with an @int@ value
    2240 \end{itemize}
    2241 Using any of these methods signifies to the user that these values are not important, and also enables one to add, remove, or reorder members without having to renumber the remaining members.
    2242 
    2243 \subsection{Using \lstinline{auto}}
    2244 
    2245 Using @auto@ would look like:
    2246 \begin{python}
    2247 >>> class Color(Enum):
    2248 ...     RED = auto()
    2249 ...     BLUE = auto()
    2250 ...     GREEN = auto()
    2251 ...
    2252 >>> Color.GREEN
    2253 <Color.GREEN: 3>
    2254 \end{python}
    2255 
    2256 \subsection{Using \lstinline{object}}
    2257 
    2258 Using @object@ would look like:
    2259 \begin{python}
    2260 >>> class Color(Enum):
    2261 ...     RED = object()
    2262 ...     GREEN = object()
    2263 ...     BLUE = object()
    2264 ...
    2265 >>> Color.GREEN                         
    2266 <Color.GREEN: <object object at 0x...>>
    2267 \end{python}
    2268 This is also a good example of why you might want to write your own @__repr__()@:
    2269 \begin{python}
    2270 >>> class Color(Enum):
    2271 ...     RED = object()
    2272 ...     GREEN = object()
    2273 ...     BLUE = object()
    2274 ...     def __repr__(self):
    2275 ...         return "<%s.%s>" % (self.__class__.__name__, self._name_)
    2276 ...
    2277 >>> Color.GREEN
    2278 <Color.GREEN>
    2279 \end{python}
    2280 
    2281 \subsection{Using a descriptive string}
    2282 
    2283 Using a string as the value would look like:
    2284 \begin{python}
    2285 >>> class Color(Enum):
    2286 ...     RED = 'stop'
    2287 ...     GREEN = 'go'
    2288 ...     BLUE = 'too fast!'
    2289 ...
    2290 >>> Color.GREEN
    2291 <Color.GREEN: 'go'>
    2292 \end{python}
    2293 
    2294 \subsection{Using a custom \lstinline{__new__()}}
    2295 
    2296 Using an auto-numbering @__new__()@ would look like:
    2297 \begin{python}
    2298 >>> class AutoNumber(Enum):
    2299 ...     def __new__(cls):
    2300 ...         value = len(cls.__members__) + 1
    2301 ...         obj = object.__new__(cls)
    2302 ...         obj._value_ = value
    2303 ...         return obj
    2304 ...
    2305 >>> class Color(AutoNumber):
    2306 ...     RED = ()
    2307 ...     GREEN = ()
    2308 ...     BLUE = ()
    2309 ...
    2310 >>> Color.GREEN
    2311 <Color.GREEN: 2>
    2312 \end{python}
    2313 To make a more general purpose @AutoNumber@, add @*args@ to the signature:
    2314 \begin{python}
    2315 >>> class AutoNumber(Enum):
    2316 ...     def __new__(cls, *args):      # this is the only change from above
    2317 ...         value = len(cls.__members__) + 1
    2318 ...         obj = object.__new__(cls)
    2319 ...         obj._value_ = value
    2320 ...         return obj
    2321 \end{python}
    2322 Then when you inherit from @AutoNumber@ you can write your own @__init__@ to handle any extra arguments:
    2323 \begin{python}
    2324 >>> class Swatch(AutoNumber):
    2325 ...     def __init__(self, pantone='unknown'):
    2326 ...         self.pantone = pantone
    2327 ...     AUBURN = '3497'
    2328 ...     SEA_GREEN = '1246'
    2329 ...     BLEACHED_CORAL = () # New color, no Pantone code yet!
    2330 ...
    2331 >>> Swatch.SEA_GREEN
    2332 <Swatch.SEA_GREEN: 2>
    2333 >>> Swatch.SEA_GREEN.pantone
    2334 '1246'
    2335 >>> Swatch.BLEACHED_CORAL.pantone
    2336 'unknown'
    2337 \end{python}
    2338 Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
    2339 it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
    2340 
    2341 Warning: Do not call @super().__new__()@, as the lookup-only @__new__@ is the one that is found;
    2342 instead, use the data type directly -- e.g.:
    2343 \begin{python}
    2344 obj = int.__new__(cls, value)
    2345 \end{python}
    2346 
    2347 \subsection{OrderedEnum}
    2348 
    2349 An ordered enumeration that is not based on @IntEnum@ and so maintains the normal @Enum@ invariants (such as not being comparable to other enumerations):
    2350 \begin{python}
    2351 >>> class OrderedEnum(Enum):
    2352 ...     def __ge__(self, other):
    2353 ...         if self.__class__ is other.__class__:
    2354 ...             return self.value >= other.value
    2355 ...         return NotImplemented
    2356 ...     def __gt__(self, other):
    2357 ...         if self.__class__ is other.__class__:
    2358 ...             return self.value > other.value
    2359 ...         return NotImplemented
    2360 ...     def __le__(self, other):
    2361 ...         if self.__class__ is other.__class__:
    2362 ...             return self.value <= other.value
    2363 ...         return NotImplemented
    2364 ...     def __lt__(self, other):
    2365 ...         if self.__class__ is other.__class__:
    2366 ...             return self.value < other.value
    2367 ...         return NotImplemented
    2368 ...
    2369 >>> class Grade(OrderedEnum):
    2370 ...     A = 5
    2371 ...     B = 4
    2372 ...     C = 3
    2373 ...     D = 2
    2374 ...     F = 1
    2375 >>> Grade.C < Grade.A
    2376 True
    2377 \end{python}
    2378 
    2379 \subsection{DuplicateFreeEnum}
    2380 
    2381 Raises an error if a duplicate member value is found instead of creating an alias:
    2382 \begin{python}
    2383 >>> class DuplicateFreeEnum(Enum):
    2384 ...     def __init__(self, *args):
    2385 ...         cls = self.__class__
    2386 ...         if any(self.value == e.value for e in cls):
    2387 ...             a = self.name
    2388 ...             e = cls(self.value).name
    2389 ...             raise ValueError(
    2390 ...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"
    2391 ...                 % (a, e))
    2392 >>> class Color(DuplicateFreeEnum):
    2393 ...     RED = 1
    2394 ...     GREEN = 2
    2395 ...     BLUE = 3
    2396 ...     GRENE = 2
    2397 ...
    2398 Traceback (most recent call last):
    2399   ...
    2400 ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'
    2401 \end{python}
    2402 Note: This is a useful example for subclassing Enum to add or change other behaviors as well as disallowing aliases.
    2403 If the only desired change is disallowing aliases, the @unique()@ decorator can be used instead.
    2404 
    2405 \subsection{Planet}
    2406 
    2407 If @__new__()@ or @__init__()@ is defined, the value of the enum member will be passed to those methods:
    2408 \begin{python}
    2409 >>> class Planet(Enum):
    2410 ...     MERCURY = (3.303e+23, 2.4397e6)
    2411 ...     VENUS   = (4.869e+24, 6.0518e6)
    2412 ...     EARTH   = (5.976e+24, 6.37814e6)
    2413 ...     MARS    = (6.421e+23, 3.3972e6)
    2414 ...     JUPITER = (1.9e+27,   7.1492e7)
    2415 ...     SATURN  = (5.688e+26, 6.0268e7)
    2416 ...     URANUS  = (8.686e+25, 2.5559e7)
    2417 ...     NEPTUNE = (1.024e+26, 2.4746e7)
    2418 ...     def __init__(self, mass, radius):
    2419 ...         self.mass = mass       # in kilograms
    2420 ...         self.radius = radius   # in meters
    2421 ...     $\@$property
    2422 ...     def surface_gravity(self):
    2423 ...         # universal gravitational constant  (m3 kg-1 s-2)
    2424 ...         G = 6.67300E-11
    2425 ...         return G * self.mass / (self.radius * self.radius)
    2426 ...
    2427 >>> Planet.EARTH.value
    2428 (5.976e+24, 6378140.0)
    2429 >>> Planet.EARTH.surface_gravity
    2430 9.802652743337129
    2431 \end{python}
    2432 
    2433 \subsection{TimePeriod}
    2434 
    2435 An example to show the @_ignore_@ attribute in use:
    2436 \begin{python}
    2437 >>> from datetime import timedelta
    2438 >>> class Period(timedelta, Enum):
    2439 ...     "different lengths of time"
    2440 ...     _ignore_ = 'Period i'
    2441 ...     Period = vars()
    2442 ...     for i in range(367):
    2443 ...         Period['day_%d' % i] = i
    2444 ...
    2445 >>> list(Period)[:2]
    2446 [<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
    2447 >>> list(Period)[-2:]
    2448 [<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]
    2449 \end{python}
    2450 
    2451 \subsection{Subclassing EnumType}
    2452 
    2453 While most enum needs can be met by customizing @Enum@ subclasses, either with class decorators or custom functions, @EnumType@ can be subclassed to provide a different Enum experience.
    2454 
    24551141
    24561142\section{Algebraic Data Type}
  • src/Parser/DeclarationNode.cc

    rf6e8c67 rbbf2cb1  
    8282
    8383DeclarationNode::~DeclarationNode() {
    84         delete name;
    85 
    8684//      delete variable.name;
    8785        delete variable.assertions;
     
    10199DeclarationNode * DeclarationNode::clone() const {
    102100        DeclarationNode * newnode = new DeclarationNode;
    103         newnode->next = maybeCopy( next );
     101        newnode->set_next( maybeCopy( get_next() ) );
    104102        newnode->name = name ? new string( *name ) : nullptr;
    105103
     104        newnode->builtin = NoBuiltinType;
    106105        newnode->type = maybeCopy( type );
    107106        newnode->inLine = inLine;
     
    171170
    172171void DeclarationNode::printList( std::ostream & os, int indent ) const {
    173         ParseList::printList( os, indent );
     172        ParseNode::printList( os, indent );
    174173        if ( hasEllipsis ) {
    175174                os << string( indent, ' ' )  << "and a variable number of other arguments" << endl;
     
    434433        DeclarationNode * newnode = new DeclarationNode;
    435434        newnode->type = new TypeData( TypeData::Builtin );
    436         newnode->type->builtintype = bt;
     435        newnode->builtin = bt;
     436        newnode->type->builtintype = newnode->builtin;
    437437        return newnode;
    438438} // DeclarationNode::newBuiltinType
     
    554554} // DeclarationNode::copySpecifiers
    555555
     556static void addQualifiersToType( TypeData *& src, TypeData * dst ) {
     557        if ( dst->base ) {
     558                addQualifiersToType( src, dst->base );
     559        } else if ( dst->kind == TypeData::Function ) {
     560                dst->base = src;
     561                src = nullptr;
     562        } else {
     563                dst->qualifiers |= src->qualifiers;
     564        } // if
     565} // addQualifiersToType
     566
    556567DeclarationNode * DeclarationNode::addQualifiers( DeclarationNode * q ) {
    557568        if ( ! q ) { return this; }                                                     // empty qualifier
     
    569580        } // if
    570581
     582        if ( q->type->forall ) {                                                        // forall qualifier ?
     583                if ( type->forall ) {                                                   // polymorphic routine ?
     584                        type->forall->appendList( q->type->forall ); // augment forall qualifier
     585                } else {
     586                        if ( type->kind == TypeData::Aggregate ) {      // struct/union ?
     587                                if ( type->aggregate.params ) {                 // polymorphic ?
     588                                        type->aggregate.params->appendList( q->type->forall ); // augment forall qualifier
     589                                } else {                                                                // not polymorphic
     590                                        type->aggregate.params = q->type->forall; // set forall qualifier
     591                                } // if
     592                        } else {                                                                        // not polymorphic
     593                                type->forall = q->type->forall;                 // make polymorphic routine
     594                        } // if
     595                } // if
     596                q->type->forall = nullptr;                                              // forall qualifier moved
     597        } // if
     598
    571599        checkQualifiers( type, q->type );
    572         BuiltinType const builtin = type->builtintype;
    573600        if ( (builtin == Zero || builtin == One) && q->type->qualifiers.any() && error.length() == 0 ) {
    574601                SemanticWarning( yylloc, Warning::BadQualifiersZeroOne, builtinTypeNames[builtin] );
    575602        } // if
    576         type = ::addQualifiers( q->type, type );
    577         q->type = nullptr;
     603        addQualifiersToType( q->type, type );
    578604
    579605        delete q;
     
    581607} // addQualifiers
    582608
     609static void addTypeToType( TypeData *& src, TypeData *& dst ) {
     610        if ( src->forall && dst->kind == TypeData::Function ) {
     611                if ( dst->forall ) {
     612                        dst->forall->appendList( src->forall );
     613                } else {
     614                        dst->forall = src->forall;
     615                } // if
     616                src->forall = nullptr;
     617        } // if
     618        if ( dst->base ) {
     619                addTypeToType( src, dst->base );
     620        } else {
     621                switch ( dst->kind ) {
     622                case TypeData::Unknown:
     623                        src->qualifiers |= dst->qualifiers;
     624                        dst = src;
     625                        src = nullptr;
     626                        break;
     627                case TypeData::Basic:
     628                        dst->qualifiers |= src->qualifiers;
     629                        if ( src->kind != TypeData::Unknown ) {
     630                                assert( src->kind == TypeData::Basic );
     631
     632                                if ( dst->basictype == DeclarationNode::NoBasicType ) {
     633                                        dst->basictype = src->basictype;
     634                                } else if ( src->basictype != DeclarationNode::NoBasicType )
     635                                        SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
     636                                                                   DeclarationNode::basicTypeNames[ dst->basictype ],
     637                                                                   DeclarationNode::basicTypeNames[ src->basictype ] );
     638                                if ( dst->complextype == DeclarationNode::NoComplexType ) {
     639                                        dst->complextype = src->complextype;
     640                                } else if ( src->complextype != DeclarationNode::NoComplexType )
     641                                        SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
     642                                                                   DeclarationNode::complexTypeNames[ src->complextype ],
     643                                                                   DeclarationNode::complexTypeNames[ src->complextype ] );
     644                                if ( dst->signedness == DeclarationNode::NoSignedness ) {
     645                                        dst->signedness = src->signedness;
     646                                } else if ( src->signedness != DeclarationNode::NoSignedness )
     647                                        SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
     648                                                                   DeclarationNode::signednessNames[ dst->signedness ],
     649                                                                   DeclarationNode::signednessNames[ src->signedness ] );
     650                                if ( dst->length == DeclarationNode::NoLength ) {
     651                                        dst->length = src->length;
     652                                } else if ( dst->length == DeclarationNode::Long && src->length == DeclarationNode::Long ) {
     653                                        dst->length = DeclarationNode::LongLong;
     654                                } else if ( src->length != DeclarationNode::NoLength )
     655                                        SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
     656                                                                   DeclarationNode::lengthNames[ dst->length ],
     657                                                                   DeclarationNode::lengthNames[ src->length ] );
     658                        } // if
     659                        break;
     660                default:
     661                        switch ( src->kind ) {
     662                        case TypeData::Aggregate:
     663                        case TypeData::Enum:
     664                                dst->base = new TypeData( TypeData::AggregateInst );
     665                                dst->base->aggInst.aggregate = src;
     666                                if ( src->kind == TypeData::Aggregate ) {
     667                                        dst->base->aggInst.params = maybeCopy( src->aggregate.actuals );
     668                                } // if
     669                                dst->base->qualifiers |= src->qualifiers;
     670                                src = nullptr;
     671                                break;
     672                        default:
     673                                if ( dst->forall ) {
     674                                        dst->forall->appendList( src->forall );
     675                                } else {
     676                                        dst->forall = src->forall;
     677                                } // if
     678                                src->forall = nullptr;
     679                                dst->base = src;
     680                                src = nullptr;
     681                        } // switch
     682                } // switch
     683        } // if
     684}
     685
    583686DeclarationNode * DeclarationNode::addType( DeclarationNode * o, bool copyattr ) {
    584         if ( !o ) return this;
    585 
    586         checkSpecifiers( o );
    587         copySpecifiers( o, copyattr );
    588         if ( o->type ) {
    589                 type = ::addType( o->type, type, o->attributes );
    590                 o->type = nullptr;
    591         } // if
    592         if ( o->bitfieldWidth ) {
    593                 bitfieldWidth = o->bitfieldWidth;
    594         } // if
    595 
    596         // there may be typedefs chained onto the type
    597         if ( o->next ) {
    598                 set_last( o->next->clone() );
    599         } // if
    600 
     687        if ( o ) {
     688                checkSpecifiers( o );
     689                copySpecifiers( o, copyattr );
     690                if ( o->type ) {
     691                        if ( ! type ) {
     692                                if ( o->type->kind == TypeData::Aggregate || o->type->kind == TypeData::Enum ) {
     693                                        // Hide type information aggregate instances.
     694                                        type = new TypeData( TypeData::AggregateInst );
     695                                        type->aggInst.aggregate = o->type;      // change ownership
     696                                        type->aggInst.aggregate->aggregate.attributes.swap( o->attributes ); // change ownership                                       
     697                                        if ( o->type->kind == TypeData::Aggregate ) {
     698                                                type->aggInst.hoistType = o->type->aggregate.body;
     699                                                type->aggInst.params = maybeCopy( o->type->aggregate.actuals );
     700                                        } else {
     701                                                type->aggInst.hoistType = o->type->enumeration.body;
     702                                        } // if
     703                                        type->qualifiers |= o->type->qualifiers;
     704                                } else {
     705                                        type = o->type;
     706                                } // if
     707                                o->type = nullptr;                                              // change ownership
     708                        } else {
     709                                addTypeToType( o->type, type );
     710                        } // if
     711                } // if
     712                if ( o->bitfieldWidth ) {
     713                        bitfieldWidth = o->bitfieldWidth;
     714                } // if
     715
     716                // there may be typedefs chained onto the type
     717                if ( o->get_next() ) {
     718                        set_last( o->get_next()->clone() );
     719                } // if
     720        } // if
    601721        delete o;
     722
    602723        return this;
    603724}
    604725
    605726DeclarationNode * DeclarationNode::addEnumBase( DeclarationNode * o ) {
    606         if ( o && o->type ) {
    607                 type->base = o->type;
     727        if ( o && o->type) {
     728                type->base= o->type;
    608729        } // if
    609730        delete o;
     
    624745        if ( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS ) {
    625746                if ( variable.assertions ) {
    626                         variable.assertions->set_last( assertions );
     747                        variable.assertions->appendList( assertions );
    627748                } else {
    628749                        variable.assertions = assertions;
     
    635756        case TypeData::Symbolic:
    636757                if ( type->symbolic.assertions ) {
    637                         type->symbolic.assertions->set_last( assertions );
     758                        type->symbolic.assertions->appendList( assertions );
    638759                } else {
    639760                        type->symbolic.assertions = assertions;
     
    689810DeclarationNode * DeclarationNode::setBase( TypeData * newType ) {
    690811        if ( type ) {
    691                 type->setLastBase( newType );
     812                TypeData * prevBase = type;
     813                TypeData * curBase = type->base;
     814                while ( curBase != nullptr ) {
     815                        prevBase = curBase;
     816                        curBase = curBase->base;
     817                } // while
     818                prevBase->base = newType;
    692819        } else {
    693820                type = newType;
     
    730857                assert( p->type->kind == TypeData::Pointer || p->type->kind == TypeData::Reference );
    731858                if ( type ) {
    732                         p->type->base = makeNewBase( type );
     859                        switch ( type->kind ) {
     860                        case TypeData::Aggregate:
     861                        case TypeData::Enum:
     862                                p->type->base = new TypeData( TypeData::AggregateInst );
     863                                p->type->base->aggInst.aggregate = type;
     864                                if ( type->kind == TypeData::Aggregate ) {
     865                                        p->type->base->aggInst.params = maybeCopy( type->aggregate.actuals );
     866                                } // if
     867                                p->type->base->qualifiers |= type->qualifiers;
     868                                break;
     869
     870                        default:
     871                                p->type->base = type;
     872                        } // switch
    733873                        type = nullptr;
    734874                } // if
     
    740880}
    741881
     882static TypeData * findLast( TypeData * a ) {
     883        assert( a );
     884        TypeData * cur = a;
     885        while ( cur->base ) {
     886                cur = cur->base;
     887        } // while
     888        return cur;
     889}
     890
    742891DeclarationNode * DeclarationNode::addNewArray( DeclarationNode * a ) {
    743892        if ( ! a ) return this;
    744893        assert( a->type->kind == TypeData::Array );
     894        TypeData * lastArray = findLast( a->type );
    745895        if ( type ) {
    746                 a->type->setLastBase( makeNewBase( type ) );
     896                switch ( type->kind ) {
     897                case TypeData::Aggregate:
     898                case TypeData::Enum:
     899                        lastArray->base = new TypeData( TypeData::AggregateInst );
     900                        lastArray->base->aggInst.aggregate = type;
     901                        if ( type->kind == TypeData::Aggregate ) {
     902                                lastArray->base->aggInst.params = maybeCopy( type->aggregate.actuals );
     903                        } // if
     904                        lastArray->base->qualifiers |= type->qualifiers;
     905                        break;
     906                default:
     907                        lastArray->base = type;
     908                } // switch
    747909                type = nullptr;
    748910        } // if
     
    798960DeclarationNode * DeclarationNode::cloneBaseType( DeclarationNode * o, bool copyattr ) {
    799961        if ( ! o ) return nullptr;
     962
    800963        o->copySpecifiers( this, copyattr );
    801964        if ( type ) {
    802                 o->type = ::cloneBaseType( type, o->type );
     965                TypeData * srcType = type;
     966
     967                // search for the base type by scanning off pointers and array designators
     968                while ( srcType->base ) {
     969                        srcType = srcType->base;
     970                } // while
     971
     972                TypeData * newType = srcType->clone();
     973                if ( newType->kind == TypeData::AggregateInst ) {
     974                        // don't duplicate members
     975                        if ( newType->aggInst.aggregate->kind == TypeData::Enum ) {
     976                                delete newType->aggInst.aggregate->enumeration.constants;
     977                                newType->aggInst.aggregate->enumeration.constants = nullptr;
     978                                newType->aggInst.aggregate->enumeration.body = false;
     979                        } else {
     980                                assert( newType->aggInst.aggregate->kind == TypeData::Aggregate );
     981                                delete newType->aggInst.aggregate->aggregate.fields;
     982                                newType->aggInst.aggregate->aggregate.fields = nullptr;
     983                                newType->aggInst.aggregate->aggregate.body = false;
     984                        } // if
     985                        // don't hoist twice
     986                        newType->aggInst.hoistType = false;
     987                } // if
     988
     989                newType->forall = maybeCopy( type->forall );
     990                if ( ! o->type ) {
     991                        o->type = newType;
     992                } else {
     993                        addTypeToType( newType, o->type );
     994                        delete newType;
     995                } // if
    803996        } // if
    804997        return o;
     
    9061099        std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList );
    9071100
    908         for ( const DeclarationNode * cur = firstNode ; cur ; cur = cur->next ) {
     1101        for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
    9091102                try {
    9101103                        bool extracted_named = false;
     
    9741167        std::back_insert_iterator<std::vector<ast::ptr<ast::DeclWithType>>> out( outputList );
    9751168
    976         for ( const DeclarationNode * cur = firstNode; cur; cur = cur->next ) {
     1169        for ( const DeclarationNode * cur = firstNode; cur; cur = strict_next( cur ) ) {
    9771170                try {
    9781171                        ast::Decl * decl = cur->build();
     
    10241217        std::back_insert_iterator<std::vector<ast::ptr<ast::Type>>> out( outputList );
    10251218
    1026         for ( const DeclarationNode * cur = firstNode ; cur ; cur = cur->next ) {
     1219        for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
    10271220                try {
    10281221                        * out++ = cur->buildType();
  • src/Parser/DeclarationNode.h

    rf6e8c67 rbbf2cb1  
    1919
    2020struct TypeData;
    21 struct InitializerNode;
    22 
    23 struct DeclarationNode final : public ParseList<DeclarationNode> {
     21class InitializerNode;
     22
     23struct DeclarationNode : public ParseNode {
    2424        // These enumerations must harmonize with their names in DeclarationNode.cc.
    2525        enum BasicType {
     
    108108        DeclarationNode * cloneBaseType( DeclarationNode * newdecl, bool = true );
    109109
     110        DeclarationNode * appendList( DeclarationNode * node ) {
     111                return (DeclarationNode *)set_last( node );
     112        }
     113
    110114        virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
    111115        virtual void printList( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
     
    125129        DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
    126130
    127         const std::string * name = nullptr;
     131        DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }
    128132
    129133        struct Variable_t {
     
    140144        };
    141145        StaticAssert_t assert;
     146
     147        BuiltinType builtin = NoBuiltinType;
    142148
    143149        TypeData * type = nullptr;
     
    171177}
    172178
     179template<typename NodeType>
     180NodeType * strict_next( NodeType * node ) {
     181        ParseNode * next = node->get_next();
     182        if ( nullptr == next ) return nullptr;
     183        if ( NodeType * ret = dynamic_cast<NodeType *>( next ) ) return ret;
     184        SemanticError( next->location, "internal error, non-homogeneous nodes founds in buildList processing." );
     185}
     186
    173187// This generic buildList is here along side its overloads.
    174188template<typename AstType, typename NodeType,
     
    179193        std::back_insert_iterator<Container<ast::ptr<AstType>, Args...>> out( output );
    180194
    181         for ( NodeType * cur = firstNode ; cur ; cur = cur->next ) {
     195        for ( NodeType * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
    182196                try {
    183197                        AstType * node = dynamic_cast<AstType *>( maybeBuild( cur ) );
  • src/Parser/ExpressionNode.h

    rf6e8c67 rbbf2cb1  
    1818#include "ParseNode.h"
    1919
    20 struct InitializerNode;
     20class InitializerNode;
    2121
    22 struct ExpressionNode final : public ParseList<ExpressionNode> {
     22class ExpressionNode final : public ParseNode {
     23public:
    2324        ExpressionNode( ast::Expr * expr = nullptr ) : expr( expr ) {}
    2425        virtual ~ExpressionNode() {}
    2526        virtual ExpressionNode * clone() const override {
    2627                if ( nullptr == expr ) return nullptr;
    27                 ExpressionNode * node = new ExpressionNode( ast::shallowCopy( expr.get() ) );
    28                 node->next = maybeCopy( next );
    29                 return node;
     28                return static_cast<ExpressionNode*>(
     29                        (new ExpressionNode( ast::shallowCopy( expr.get() ) ))->set_next( maybeCopy( get_next() ) ));
    3030        }
    3131
  • src/Parser/InitializerNode.cc

    rf6e8c67 rbbf2cb1  
    3636                : expr( _expr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ), isDelete( false ) {
    3737        if ( aggrp )
    38                 kids = next;
     38                kids = dynamic_cast< InitializerNode * >( get_next() );
    3939
    4040        if ( kids )
     
    4848
    4949        if ( aggrp )
    50                 kids = next;
     50                kids = dynamic_cast< InitializerNode * >( get_next() );
    5151
    5252        if ( kids )
    53                 next = nullptr;
     53                set_next( nullptr );
    5454} // InitializerNode::InitializerNode
    5555
     
    7373                        while ( curdes != nullptr) {
    7474                                curdes->printOneLine(os);
    75                                 curdes = curdes->next;
     75                                curdes = (ExpressionNode *)(curdes->get_next());
    7676                                if ( curdes ) os << ", ";
    7777                        } // while
     
    8787
    8888        InitializerNode *moreInit;
    89         if ( ( moreInit = next ) ) {
     89        if ( (moreInit = dynamic_cast< InitializerNode * >( get_next() ) ) ) {
    9090                moreInit->printOneLine( os );
    9191        } // if
     
    9898                std::vector<ast::ptr<ast::Designation>> designlist;
    9999                InitializerNode * child = next_init();
    100                 for ( ; child != nullptr ; child = child->next ) {
     100                for ( ; child != nullptr ; child = dynamic_cast< InitializerNode * >( child->get_next() ) ) {
    101101                        std::deque<ast::ptr<ast::Expr>> desList;
    102102                        buildList( child->designator, desList );
  • src/Parser/InitializerNode.h

    rf6e8c67 rbbf2cb1  
    1818#include "ParseNode.h"
    1919
    20 struct InitializerNode final : public ParseList<InitializerNode> {
     20class InitializerNode : public ParseNode {
     21public:
    2122        InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr );
    2223        InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr );
  • src/Parser/ParseNode.h

    rf6e8c67 rbbf2cb1  
    3333
    3434struct DeclarationNode;
    35 struct InitializerNode;
    36 struct ExpressionNode;
     35class InitializerNode;
     36class ExpressionNode;
    3737struct StatementNode;
    3838
     
    4545extern YYLTYPE yylloc;
    4646
    47 struct ParseNode {
    48         ParseNode() {}
    49         virtual ~ParseNode() {}
     47class ParseNode {
     48  public:
     49        ParseNode() {};
     50        virtual ~ParseNode() { delete next; delete name; };
    5051        virtual ParseNode * clone() const = 0;
    5152
    52         virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
     53        ParseNode * get_next() const { return next; }
     54        ParseNode * set_next( ParseNode * newlink ) { next = newlink; return this; }
    5355
    54         static int indent_by;
    55 
    56         CodeLocation location = yylloc;
    57 }; // ParseNode
    58 
    59 /// Only ever use in the form `struct NAME final : public ParseList<NAME>`!
    60 template<typename Next>
    61 struct ParseList : public ParseNode {
    62         ParseList() {}
    63         virtual ~ParseList() { delete next; };
    64         virtual ParseList<Next> * clone() const = 0;
    65 
    66         Next * get_last() {
    67                 Next * current = static_cast<Next *>( this );
    68                 while ( current->next != nullptr ) current = current->next;
     56        ParseNode * get_last() {
     57                ParseNode * current;
     58                for ( current = this; current->get_next() != nullptr; current = current->get_next() );
    6959                return current;
    7060        }
    71         Next * set_last( Next * newlast ) {
    72                 if ( newlast != nullptr ) get_last()->next = newlast;
    73                 return static_cast<Next *>( this );
     61        ParseNode * set_last( ParseNode * newlast ) {
     62                if ( newlast != nullptr ) get_last()->set_next( newlast );
     63                return this;
    7464        }
    7565
     66        virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
    7667        virtual void printList( std::ostream & os, int indent = 0 ) const {
    7768                print( os, indent );
     
    7970        }
    8071
    81         Next * next = nullptr;
    82 };
     72        static int indent_by;
     73
     74        ParseNode * next = nullptr;
     75        const std::string * name = nullptr;
     76        CodeLocation location = yylloc;
     77}; // ParseNode
    8378
    8479// Must harmonize with OperName.
  • src/Parser/StatementNode.cc

    rf6e8c67 rbbf2cb1  
    5454                StatementNode * nextStmt = new StatementNode(
    5555                        new ast::DeclStmt( decl->location, maybeBuild( decl ) ) );
    56                 next = nextStmt;
    57                 if ( decl->next ) {
    58                         next->next = new StatementNode( decl->next );
    59                         decl->next = nullptr;
     56                set_next( nextStmt );
     57                if ( decl->get_next() ) {
     58                        get_next()->set_next( new StatementNode( dynamic_cast< DeclarationNode * >(decl->get_next()) ) );
     59                        decl->set_next( 0 );
    6060                } // if
    6161        } else {
    62                 if ( decl->next ) {
    63                         next = new StatementNode( decl->next );
    64                         decl->next = nullptr;
     62                if ( decl->get_next() ) {
     63                        set_next( new StatementNode( dynamic_cast< DeclarationNode * >( decl->get_next() ) ) );
     64                        decl->set_next( 0 );
    6565                } // if
    6666                agg = decl;
     
    8787        ClauseNode * prev = this;
    8888        // find end of list and maintain previous pointer
    89         for ( ClauseNode * curr = prev; curr != nullptr; curr = curr->next ) {
    90                 ClauseNode * node = curr;
     89        for ( ClauseNode * curr = prev; curr != nullptr; curr = (ClauseNode *)curr->get_next() ) {
     90                ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr);
    9191                assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
    9292                prev = curr;
    9393        } // for
    94         ClauseNode * node = prev;
     94        ClauseNode * node = dynamic_cast< ClauseNode * >(prev);
    9595        // convert from StatementNode list to Statement list
    9696        std::vector<ast::ptr<ast::Stmt>> stmts;
     
    332332        clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
    333333
    334         ExpressionNode * next = targetExpr->next;
    335         targetExpr->next = nullptr;
     334        ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
     335        targetExpr->set_next( nullptr );
    336336        buildMoveList( next, clause->target_args );
    337337
  • src/Parser/StatementNode.h

    rf6e8c67 rbbf2cb1  
    1818#include "ParseNode.h"
    1919
    20 struct StatementNode final : public ParseList<StatementNode> {
     20struct StatementNode final : public ParseNode {
    2121        StatementNode() : stmt( nullptr ) {}
    2222        StatementNode( ast::Stmt * stmt ) : stmt( stmt ) {}
     
    3939}; // StatementNode
    4040
    41 struct ClauseNode final : public ParseList<ClauseNode> {
     41struct ClauseNode final : public ParseNode {
    4242        ClauseNode( ast::StmtClause * clause ) : clause( clause ) {}
    4343        virtual ~ClauseNode() {}
     44
     45        ClauseNode * set_last( ParseNode * newlast ) {
     46                ParseNode::set_last( newlast );
     47        return this;
     48    }
    4449
    4550        virtual ClauseNode * clone() const final { assert( false ); return nullptr; }
  • src/Parser/TypeData.cc

    rf6e8c67 rbbf2cb1  
    479479
    480480
    481 TypeData * TypeData::getLastBase() {
    482         TypeData * cur = this;
    483         while ( cur->base ) cur = cur->base;
    484         return cur;
    485 }
    486 
    487 void TypeData::setLastBase( TypeData * newBase ) {
    488         getLastBase()->base = newBase;
    489 }
    490 
    491 // Takes ownership of src.
    492 static void addQualifiersToType( TypeData * dst, TypeData * src ) {
    493         if ( dst->base ) {
    494                 addQualifiersToType( dst->base, src );
    495         } else if ( dst->kind == TypeData::Function ) {
    496                 dst->base = src;
    497                 src = nullptr;
    498     } else {
    499                 dst->qualifiers |= src->qualifiers;
    500                 delete src;
    501         } // if
    502 }
    503 
    504 // Takes ownership of all arguments, gives ownership of return value.
    505 TypeData * addQualifiers( TypeData * ltype, TypeData * rtype ) {
    506         if ( ltype->forall ) {
    507                 if ( rtype->forall ) {
    508                         rtype->forall->set_last( ltype->forall );
    509                 } else if ( TypeData::Aggregate != rtype->kind ) {
    510                         rtype->forall = ltype->forall;
    511                 } else if ( rtype->aggregate.params ) {
    512                         rtype->aggregate.params->set_last( ltype->forall );
    513                 } else {
    514                         rtype->aggregate.params = ltype->forall;
    515                 }
    516                 ltype->forall = nullptr;
    517         }
    518 
    519         addQualifiersToType( rtype, ltype );
    520         return rtype;
    521 }
    522 
    523 // Helper for addType and cloneBaseType.
    524 static void addTypeToType( TypeData *& dst, TypeData *& src ) {
    525         if ( src->forall && dst->kind == TypeData::Function ) {
    526                 if ( dst->forall ) {
    527                         dst->forall->set_last( src->forall );
    528                 } else {
    529                         dst->forall = src->forall;
    530                 } // if
    531                 src->forall = nullptr;
    532         } // if
    533         if ( dst->base ) {
    534                 addTypeToType( dst->base, src );
    535                 return;
    536         }
    537         switch ( dst->kind ) {
    538         case TypeData::Unknown:
    539                 src->qualifiers |= dst->qualifiers;
    540                 // LEAKS dst?
    541                 dst = src;
    542                 src = nullptr;
    543                 break;
    544         case TypeData::Basic:
    545                 dst->qualifiers |= src->qualifiers;
    546                 if ( src->kind != TypeData::Unknown ) {
    547                         assert( src->kind == TypeData::Basic );
    548 
    549                         if ( dst->basictype == DeclarationNode::NoBasicType ) {
    550                                 dst->basictype = src->basictype;
    551                         } else if ( src->basictype != DeclarationNode::NoBasicType ) {
    552                                 SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
    553                                         DeclarationNode::basicTypeNames[ dst->basictype ],
    554                                         DeclarationNode::basicTypeNames[ src->basictype ] );
    555                         }
    556                         if ( dst->complextype == DeclarationNode::NoComplexType ) {
    557                                 dst->complextype = src->complextype;
    558                         } else if ( src->complextype != DeclarationNode::NoComplexType ) {
    559                                 SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
    560                                         DeclarationNode::complexTypeNames[ src->complextype ],
    561                                         DeclarationNode::complexTypeNames[ src->complextype ] );
    562                         }
    563                         if ( dst->signedness == DeclarationNode::NoSignedness ) {
    564                                 dst->signedness = src->signedness;
    565                         } else if ( src->signedness != DeclarationNode::NoSignedness ) {
    566                                 SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
    567                                         DeclarationNode::signednessNames[ dst->signedness ],
    568                                         DeclarationNode::signednessNames[ src->signedness ] );
    569                         }
    570                         if ( dst->length == DeclarationNode::NoLength ) {
    571                                 dst->length = src->length;
    572                         } else if ( dst->length == DeclarationNode::Long && src->length == DeclarationNode::Long ) {
    573                                 dst->length = DeclarationNode::LongLong;
    574                         } else if ( src->length != DeclarationNode::NoLength ) {
    575                                 SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
    576                                         DeclarationNode::lengthNames[ dst->length ],
    577                                         DeclarationNode::lengthNames[ src->length ] );
    578                         }
    579                 } // if
    580                 break;
    581         default:
    582                 switch ( src->kind ) {
    583                 case TypeData::Aggregate:
    584                 case TypeData::Enum:
    585                         dst->base = new TypeData( TypeData::AggregateInst );
    586                         dst->base->aggInst.aggregate = src;
    587                         if ( src->kind == TypeData::Aggregate ) {
    588                                 dst->base->aggInst.params = maybeCopy( src->aggregate.actuals );
    589                         } // if
    590                         dst->base->qualifiers |= src->qualifiers;
    591                         src = nullptr;
    592                         break;
    593                 default:
    594                         if ( dst->forall ) {
    595                                 dst->forall->set_last( src->forall );
    596                         } else {
    597                                 dst->forall = src->forall;
    598                         } // if
    599                         src->forall = nullptr;
    600                         dst->base = src;
    601                         src = nullptr;
    602                 } // switch
    603         } // switch
    604 }
    605 
    606 // Takes ownership of all arguments, gives ownership of return value.
    607 TypeData * addType( TypeData * ltype, TypeData * rtype, std::vector<ast::ptr<ast::Attribute>> & attributes ) {
    608         if ( rtype ) {
    609                 addTypeToType( rtype, ltype );
    610                 return rtype;
    611         } else {
    612                 if ( ltype->kind == TypeData::Aggregate || ltype->kind == TypeData::Enum ) {
    613                         // Hide type information aggregate instances.
    614                         rtype = new TypeData( TypeData::AggregateInst );
    615                         rtype->aggInst.aggregate = ltype;
    616                         rtype->aggInst.aggregate->aggregate.attributes.swap( attributes ); // change ownership
    617                         if ( ltype->kind == TypeData::Aggregate ) {
    618                                 rtype->aggInst.hoistType = ltype->aggregate.body;
    619                                 rtype->aggInst.params = maybeCopy( ltype->aggregate.actuals );
    620                         } else {
    621                                 rtype->aggInst.hoistType = ltype->enumeration.body;
    622                         } // if
    623                         rtype->qualifiers |= ltype->qualifiers;
    624                 } else {
    625                         rtype = ltype;
    626                 } // if
    627                 return rtype;
    628         } // if
    629 }
    630 
    631 // Takes ownership of both arguments, gives ownership of return value.
    632 TypeData * cloneBaseType( TypeData * type, TypeData * other ) {
    633         TypeData * newType = type->getLastBase()->clone();
    634         if ( newType->kind == TypeData::AggregateInst ) {
    635                 // don't duplicate members
    636                 if ( newType->aggInst.aggregate->kind == TypeData::Enum ) {
    637                         delete newType->aggInst.aggregate->enumeration.constants;
    638                         newType->aggInst.aggregate->enumeration.constants = nullptr;
    639                         newType->aggInst.aggregate->enumeration.body = false;
    640                 } else {
    641                         assert( newType->aggInst.aggregate->kind == TypeData::Aggregate );
    642                         delete newType->aggInst.aggregate->aggregate.fields;
    643                         newType->aggInst.aggregate->aggregate.fields = nullptr;
    644                         newType->aggInst.aggregate->aggregate.body = false;
    645                 } // if
    646                 // don't hoist twice
    647                 newType->aggInst.hoistType = false;
    648         } // if
    649         newType->forall = maybeCopy( type->forall );
    650 
    651         if ( other ) {
    652                 addTypeToType( other, newType );
    653                 delete newType;
    654                 return other;
    655         } // if
    656         return newType;
    657 }
    658 
    659 TypeData * makeNewBase( TypeData * type ) {
    660         switch ( type->kind ) {
    661         case TypeData::Aggregate:
    662         case TypeData::Enum: {
    663                 TypeData * out = new TypeData( TypeData::AggregateInst );
    664                 out->aggInst.aggregate = type;
    665                 if ( TypeData::Aggregate == type->kind ) {
    666                         out->aggInst.params = maybeCopy( type->aggregate.actuals );
    667                 }
    668                 out->qualifiers |= type->qualifiers;
    669                 return out;
    670         }
    671         default:
    672                 return type;
    673         } // switch
    674 }
    675 
    676 
    677481void buildForall(
    678482                const DeclarationNode * firstNode,
     
    690494        for ( auto i = outputList.begin() ;
    691495                        i != outputList.end() ;
    692                         ++i, n = n->next ) {
     496                        ++i, n = (DeclarationNode*)n->get_next() ) {
    693497                // Only the object type class adds additional assertions.
    694498                if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
     
    835639        for ( auto i = outputForall.begin() ;
    836640                        i != outputForall.end() ;
    837                         ++i, n = n->next ) {
     641                        ++i, n = (DeclarationNode*)n->get_next() ) {
    838642                // Only the object type class adds additional assertions.
    839643                if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
     
    14681272        auto members = ret->members.begin();
    14691273        ret->hide = td->enumeration.hiding == EnumHiding::Hide ? ast::EnumDecl::EnumHiding::Hide : ast::EnumDecl::EnumHiding::Visible;
    1470         for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = cur->next, ++members ) {
     1274        for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ), ++members ) {
    14711275                if ( cur->enumInLine ) {
    14721276                        // Do Nothing
     
    16961500        assert( ! function.params );
    16971501        // loop over declaration first as it is easier to spot errors
    1698         for ( DeclarationNode * decl = function.oldDeclList; decl != nullptr; decl = decl->next ) {
     1502        for ( DeclarationNode * decl = function.oldDeclList; decl != nullptr; decl = dynamic_cast< DeclarationNode * >( decl->get_next() ) ) {
    16991503                // scan ALL parameter names for each declaration name to check for duplicates
    1700                 for ( DeclarationNode * param = function.idList; param != nullptr; param = param->next ) {
     1504                for ( DeclarationNode * param = function.idList; param != nullptr; param = dynamic_cast< DeclarationNode * >( param->get_next() ) ) {
    17011505                        if ( *decl->name == *param->name ) {
    17021506                                // type set => parameter name already transformed by a declaration names so there is a duplicate
     
    17201524        //    rtb( a, b, c ) const char * b; {} => int rtn( int a, const char * b, int c ) {}
    17211525
    1722         for ( DeclarationNode * param = function.idList; param != nullptr; param = param->next ) {
     1526        for ( DeclarationNode * param = function.idList; param != nullptr; param = dynamic_cast< DeclarationNode * >( param->get_next() ) ) {
    17231527                if ( ! param->type ) {                                                  // generate type int for empty parameter type
    17241528                        param->type = new TypeData( TypeData::Basic );
  • src/Parser/TypeData.h

    rf6e8c67 rbbf2cb1  
    111111
    112112        const std::string * leafName() const;
    113 
    114         TypeData * getLastBase();
    115         void setLastBase( TypeData * );
    116113};
    117 
    118 TypeData * addQualifiers( TypeData * ltype, TypeData * rtype );
    119 TypeData * addType( TypeData * ltype, TypeData * rtype, std::vector<ast::ptr<ast::Attribute>> & );
    120 TypeData * cloneBaseType( TypeData * type, TypeData * other );
    121 TypeData * makeNewBase( TypeData * type );
    122114
    123115ast::Type * typebuild( const TypeData * );
  • src/Parser/lex.ll

    rf6e8c67 rbbf2cb1  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Sat Feb 24 11:47:24 2024
    13  * Update Count     : 777
     12 * Last Modified On : Tue Oct  3 17:10:57 2023
     13 * Update Count     : 773
    1414 */
    1515
     
    407407";"                             { ASCIIOP_RETURN(); }
    408408"."                             { ASCIIOP_RETURN(); }                                   // also operator
    409 "@@"                    { NAMEDOP_RETURN(ATTR); }                               // CFA, attribute shorthand
    410409"..."                   { NAMEDOP_RETURN(ELLIPSIS); }
    411410
  • src/Parser/parser.yy

    rf6e8c67 rbbf2cb1  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar  4 08:44:25 2024
    13 // Update Count     : 6562
     12// Last Modified On : Fri Feb 23 18:25:46 2024
     13// Update Count     : 6484
    1414//
    1515
     
    126126        DeclarationNode * cl = (new DeclarationNode)->addType( typeSpec ); // typeSpec IS DELETED!!!
    127127
    128         // Start at second variable in declaration list and clone the type specifiers for each variable.
    129         for ( DeclarationNode * cur = declList->next ; cur != nullptr; cur = cur->next ) {
     128        // Start at second variable in declaration list and clone the type specifiers for each variable..
     129        for ( DeclarationNode * cur = dynamic_cast<DeclarationNode *>( declList->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) {
    130130                cl->cloneBaseType( cur, copyattr );                             // cur is modified
    131131        } // for
     
    139139void distExt( DeclarationNode * declaration ) {
    140140        // distribute EXTENSION across all declarations
    141         for ( DeclarationNode *iter = declaration ; iter != nullptr ; iter = iter->next ) {
     141        for ( DeclarationNode *iter = declaration; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) {
    142142                iter->set_extension( true );
    143143        } // for
     
    146146void distInl( DeclarationNode * declaration ) {
    147147        // distribute INLINE across all declarations
    148         for ( DeclarationNode *iter = declaration ; iter != nullptr ; iter = iter->next ) {
     148        for ( DeclarationNode *iter = declaration; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) {
    149149                iter->set_inLine( true );
    150150        } // for
     
    153153void distQual( DeclarationNode * declaration, DeclarationNode * qualifiers ) {
    154154        // distribute qualifiers across all non-variable declarations in a distribution statemement
    155         for ( DeclarationNode * iter = declaration ; iter != nullptr ; iter = iter->next ) {
     155        for ( DeclarationNode * iter = declaration; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) {
    156156                // SKULLDUGGERY: Distributions are parsed inside out, so qualifiers are added to declarations inside out. Since
    157157                // addQualifiers appends to the back of the list, the forall clauses are in the wrong order (right to left). To
     
    389389%token LE GE EQ NE                                                                              // <=   >=      ==      !=
    390390%token ANDAND OROR                                                                              // &&   ||
    391 %token ATTR ELLIPSIS                                                                    // @@   ...
     391%token ELLIPSIS                                                                                 // ...
    392392
    393393%token EXPassign        MULTassign      DIVassign       MODassign       // \=   *=      /=      %=
     
    433433%type<stmt> statement                                   labeled_statement                       compound_statement
    434434%type<stmt> statement_decl                              statement_decl_list                     statement_list_nodecl
    435 %type<stmt> selection_statement
     435%type<stmt> selection_statement                 if_statement
    436436%type<clause> switch_clause_list_opt    switch_clause_list
    437437%type<expr> case_value
     
    500500%type<decl> cfa_identifier_parameter_declarator_tuple cfa_identifier_parameter_ptr
    501501
    502 %type<decl> cfa_parameter_declaration cfa_parameter_list cfa_parameter_list_ellipsis_opt
     502%type<decl> cfa_parameter_declaration cfa_parameter_list cfa_parameter_ellipsis_list_opt
    503503
    504504%type<decl> cfa_typedef_declaration cfa_variable_declaration cfa_variable_specifier
     
    508508%type<decl> KR_parameter_list KR_parameter_list_opt
    509509
    510 %type<decl> parameter_declaration parameter_list parameter_list_ellipsis_opt
     510%type<decl> parameter_declaration parameter_list parameter_type_list_opt
    511511
    512512%type<decl> paren_identifier paren_type
     
    530530%type<decl> type_parameter type_parameter_list type_initializer_opt
    531531
    532 %type<expr> type_parameters_opt type_list array_type_list // array_dimension_list
     532%type<expr> type_parameters_opt type_list array_type_list
    533533
    534534%type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list
     
    12461246        ;
    12471247
    1248 // if, switch, and choose require parenthesis around the conditional because it can be followed by a statement.
    1249 // For example, without parenthesis:
    1250 //
    1251 //    if x + y + z; => "if ( x + y ) + z" or "if ( x ) + y + z"
    1252 //    switch ( S ) { ... } => switch ( S ) { compound literal... } ... or
    1253 
    12541248selection_statement:
    1255         IF '(' conditional_declaration ')' statement            %prec THEN
    1256                 // explicitly deal with the shift/reduce conflict on if/else
    1257                 { $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), nullptr ) ); }
    1258         | IF '(' conditional_declaration ')' statement ELSE statement
    1259                 { $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), maybe_build_compound( yylloc, $7 ) ) ); }
     1249                        // pop causes a S/R conflict without separating the IF statement into a non-terminal even after resolving
     1250                        // the inherent S/R conflict with THEN/ELSE.
     1251        push if_statement pop
     1252                { $$ = $2; }
    12601253        | SWITCH '(' comma_expression ')' case_clause
    12611254                { $$ = new StatementNode( build_switch( yylloc, true, $3, $5 ) ); }
     
    12811274        | CHOOSE '(' comma_expression ')' '{' error '}'         // CFA, invalid syntax rule
    12821275                { SemanticError( yylloc, "syntax error, declarations can only appear before the list of case clauses." ); $$ = nullptr; }
     1276        ;
     1277
     1278if_statement:
     1279        IF '(' conditional_declaration ')' statement            %prec THEN
     1280                // explicitly deal with the shift/reduce conflict on if/else
     1281                { $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), nullptr ) ); }
     1282        | IF '(' conditional_declaration ')' statement ELSE statement
     1283                { $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), maybe_build_compound( yylloc, $7 ) ) ); }
    12831284        ;
    12841285
     
    18961897declaration_list:
    18971898        declaration
    1898         | declaration_list declaration
    1899                 { $$ = $1->set_last( $2 ); }
     1899        | declaration_list declaration          { $$ = $1->appendList( $2 ); }
    19001900        ;
    19011901
     
    19101910                { $$ = $1; }
    19111911        | KR_parameter_list c_declaration ';'
    1912                 { $$ = $1->set_last( $2 ); }
     1912                { $$ = $1->appendList( $2 ); }
    19131913        ;
    19141914
     
    19681968                { $$ = $2->addQualifiers( $1 )->addInitializer( $3 ); }
    19691969        | cfa_variable_declaration pop ',' push identifier_or_type_name initializer_opt
    1970                 { $$ = $1->set_last( $1->cloneType( $5 )->addInitializer( $6 ) ); }
     1970                { $$ = $1->appendList( $1->cloneType( $5 )->addInitializer( $6 ) ); }
    19711971        ;
    19721972
     
    19901990        | declaration_qualifier_list type_qualifier_list cfa_function_specifier
    19911991                { $$ = $3->addQualifiers( $1 )->addQualifiers( $2 ); }
    1992         | cfa_function_declaration ',' identifier_or_type_name '(' push cfa_parameter_list_ellipsis_opt pop ')'
     1992        | cfa_function_declaration ',' identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')'
    19931993                {
    19941994                        // Append the return type at the start (left-hand-side) to each identifier in the list.
    19951995                        DeclarationNode * ret = new DeclarationNode;
    19961996                        ret->type = maybeCopy( $1->type->base );
    1997                         $$ = $1->set_last( DeclarationNode::newFunction( $3, ret, $6, nullptr ) );
     1997                        $$ = $1->appendList( DeclarationNode::newFunction( $3, ret, $6, nullptr ) );
    19981998                }
    19991999        ;
    20002000
    20012001cfa_function_specifier:                                                                 // CFA
    2002         '[' ']' identifier '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
    2003                 { $$ = DeclarationNode::newFunction( $3,  DeclarationNode::newTuple( nullptr ), $6, nullptr )->addQualifiers( $9 ); }
    2004         | '[' ']' TYPEDEFname '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
    2005                 { $$ = DeclarationNode::newFunction( $3,  DeclarationNode::newTuple( nullptr ), $6, nullptr )->addQualifiers( $9 ); }
    2006         // | '[' ']' TYPEGENname '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
    2007         //      { $$ = DeclarationNode::newFunction( $3,  DeclarationNode::newTuple( nullptr ), $6, nullptr )->addQualifiers( $9 ); }
    2008 
     2002//      '[' ']' identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' // S/R conflict
     2003//              {
     2004//                      $$ = DeclarationNode::newFunction( $3, DeclarationNode::newTuple( 0 ), $6, nullptr, true );
     2005//              }
     2006//      '[' ']' identifier '(' push cfa_parameter_ellipsis_list_opt pop ')'
     2007//              {
     2008//                      typedefTable.setNextIdentifier( *$5 );
     2009//                      $$ = DeclarationNode::newFunction( $5, DeclarationNode::newTuple( 0 ), $8, nullptr, true );
     2010//              }
     2011//      | '[' ']' TYPEDEFname '(' push cfa_parameter_ellipsis_list_opt pop ')'
     2012//              {
     2013//                      typedefTable.setNextIdentifier( *$5 );
     2014//                      $$ = DeclarationNode::newFunction( $5, DeclarationNode::newTuple( 0 ), $8, nullptr, true );
     2015//              }
     2016//      | '[' ']' typegen_name
    20092017                // identifier_or_type_name must be broken apart because of the sequence:
    20102018                //
    2011                 //   '[' ']' identifier_or_type_name '(' cfa_parameter_list_ellipsis_opt ')'
     2019                //   '[' ']' identifier_or_type_name '(' cfa_parameter_ellipsis_list_opt ')'
    20122020                //   '[' ']' type_specifier
    20132021                //
    20142022                // type_specifier can resolve to just TYPEDEFname (e.g., typedef int T; int f( T );). Therefore this must be
    20152023                // flattened to allow lookahead to the '(' without having to reduce identifier_or_type_name.
    2016         | cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
     2024        cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
    20172025                // To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator).
    20182026                { $$ = DeclarationNode::newFunction( $2, $1, $5, nullptr )->addQualifiers( $8 ); }
    2019         | cfa_function_return identifier_or_type_name '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
     2027        | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
    20202028                { $$ = DeclarationNode::newFunction( $2, $1, $5, nullptr )->addQualifiers( $8 ); }
    20212029        ;
     
    20242032        '[' push cfa_parameter_list pop ']'
    20252033                { $$ = DeclarationNode::newTuple( $3 ); }
    2026         | '[' push cfa_parameter_list ',' cfa_abstract_parameter_list pop ']'
     2034        | '[' push cfa_parameter_list pop ',' push cfa_abstract_parameter_list pop ']'
    20272035                // To obtain LR(1 ), the last cfa_abstract_parameter_list is added into this flattened rule to lookahead to the ']'.
    2028                 { $$ = DeclarationNode::newTuple( $3->set_last( $5 ) ); }
     2036                { $$ = DeclarationNode::newTuple( $3->appendList( $7 ) ); }
    20292037        ;
    20302038
     
    20402048                        $$ = $2->addTypedef();
    20412049                }
    2042         | cfa_typedef_declaration ',' identifier
    2043                 {
    2044                         typedefTable.addToEnclosingScope( *$3, TYPEDEFname, "cfa_typedef_declaration 3" );
    2045                         $$ = $1->set_last( $1->cloneType( $3 ) );
     2050        | cfa_typedef_declaration pop ',' push identifier
     2051                {
     2052                        typedefTable.addToEnclosingScope( *$5, TYPEDEFname, "cfa_typedef_declaration 3" );
     2053                        $$ = $1->appendList( $1->cloneType( $5 ) );
    20462054                }
    20472055        ;
     
    20612069                {
    20622070                        typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "typedef_declaration 2" );
    2063                         $$ = $1->set_last( $1->cloneBaseType( $3 )->addTypedef() );
     2071                        $$ = $1->appendList( $1->cloneBaseType( $3 )->addTypedef() );
    20642072                }
    20652073        | type_qualifier_list TYPEDEF type_specifier declarator // remaining OBSOLESCENT (see 2 )
     
    21152123
    21162124        | declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt
    2117                 { $$ = $1->set_last( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) ); }
     2125                { $$ = $1->appendList( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) ); }
    21182126        ;
    21192127
     
    25792587                { $$ = nullptr; }
    25802588        | field_declaration_list_opt field_declaration
    2581                 { $$ = $1 ? $1->set_last( $2 ) : $2; }
     2589                { $$ = $1 ? $1->appendList( $2 ) : $2; }
    25822590        ;
    25832591
     
    26272635        | field_declarator
    26282636        | field_declaring_list_opt ',' attribute_list_opt field_declarator
    2629                 { $$ = $1->set_last( $4->addQualifiers( $3 ) ); }
     2637                { $$ = $1->appendList( $4->addQualifiers( $3 ) ); }
    26302638        ;
    26312639
     
    26492657        | field_abstract
    26502658        | field_abstract_list_opt ',' attribute_list_opt field_abstract
    2651                 { $$ = $1->set_last( $4->addQualifiers( $3 ) ); }
     2659                { $$ = $1->appendList( $4->addQualifiers( $3 ) ); }
    26522660        ;
    26532661
     
    26622670                { $$ = $1->addName( $2 ); }
    26632671        | cfa_field_declaring_list ',' identifier_or_type_name
    2664                 { $$ = $1->set_last( $1->cloneType( $3 ) ); }
     2672                { $$ = $1->appendList( $1->cloneType( $3 ) ); }
    26652673        ;
    26662674
     
    26692677        cfa_abstract_declarator_tuple
    26702678        | cfa_field_abstract_list ','
    2671                 { $$ = $1->set_last( $1->cloneType( 0 ) ); }
     2679                { $$ = $1->appendList( $1->cloneType( 0 ) ); }
    26722680        ;
    26732681
     
    26822690                { $$ = $2; }
    26832691        ;
    2684 
    2685 // ***********
    2686 // Enumeration
    2687 // ***********
    26882692
    26892693enum_type:
     
    27152719        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
    27162720                {
    2717                         if ( $3 && ($3->storageClasses.any() || $3->type->qualifiers.val != 0) ) {
     2721                        if ( $3 && ($3->storageClasses.any() || $3->type->qualifiers.val != 0 )) {
    27182722                                SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
    27192723                        }
     
    27652769                { $$ = DeclarationNode::newEnumInLine( *$2->type->symbolic.name ); }
    27662770        | enumerator_list ',' visible_hide_opt identifier_or_type_name enumerator_value_opt
    2767                 { $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); }
     2771                { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); }
    27682772        | enumerator_list ',' INLINE type_name enumerator_value_opt
    2769                 { $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); }
     2773                { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); }
    27702774        ;
    27712775
     
    27852789        ;
    27862790
    2787 // *******************
    2788 // Function parameters
    2789 // *******************
    2790 
    2791 parameter_list_ellipsis_opt:
     2791cfa_parameter_ellipsis_list_opt:                                                // CFA, abstract + real
     2792        // empty
     2793                { $$ = DeclarationNode::newBasicType( DeclarationNode::Void ); }
     2794        | ELLIPSIS
     2795                { $$ = nullptr; }
     2796        | cfa_abstract_parameter_list
     2797        | cfa_parameter_list
     2798        | cfa_parameter_list pop ',' push cfa_abstract_parameter_list
     2799                { $$ = $1->appendList( $5 ); }
     2800        | cfa_abstract_parameter_list pop ',' push ELLIPSIS
     2801                { $$ = $1->addVarArgs(); }
     2802        | cfa_parameter_list pop ',' push ELLIPSIS
     2803                { $$ = $1->addVarArgs(); }
     2804        ;
     2805
     2806cfa_parameter_list:                                                                             // CFA
     2807                // To obtain LR(1) between cfa_parameter_list and cfa_abstract_tuple, the last cfa_abstract_parameter_list is
     2808                // factored out from cfa_parameter_list, flattening the rules to get lookahead to the ']'.
     2809        cfa_parameter_declaration
     2810        | cfa_abstract_parameter_list pop ',' push cfa_parameter_declaration
     2811                { $$ = $1->appendList( $5 ); }
     2812        | cfa_parameter_list pop ',' push cfa_parameter_declaration
     2813                { $$ = $1->appendList( $5 ); }
     2814        | cfa_parameter_list pop ',' push cfa_abstract_parameter_list pop ',' push cfa_parameter_declaration
     2815                { $$ = $1->appendList( $5 )->appendList( $9 ); }
     2816        ;
     2817
     2818cfa_abstract_parameter_list:                                                    // CFA, new & old style abstract
     2819        cfa_abstract_parameter_declaration
     2820        | cfa_abstract_parameter_list pop ',' push cfa_abstract_parameter_declaration
     2821                { $$ = $1->appendList( $5 ); }
     2822        ;
     2823
     2824parameter_type_list_opt:
    27922825        // empty
    27932826                { $$ = nullptr; }
     
    28002833
    28012834parameter_list:                                                                                 // abstract + real
    2802         parameter_declaration
    2803         | abstract_parameter_declaration
     2835        abstract_parameter_declaration
     2836        | parameter_declaration
     2837        | parameter_list ',' abstract_parameter_declaration
     2838                { $$ = $1->appendList( $3 ); }
    28042839        | parameter_list ',' parameter_declaration
    2805                 { $$ = $1->set_last( $3 ); }
    2806         | parameter_list ',' abstract_parameter_declaration
    2807                 { $$ = $1->set_last( $3 ); }
    2808         ;
    2809 
    2810 cfa_parameter_list_ellipsis_opt:                                                // CFA, abstract + real
    2811         // empty
    2812                 { $$ = DeclarationNode::newBasicType( DeclarationNode::Void ); }
    2813         | ELLIPSIS
    2814                 { $$ = nullptr; }
    2815         | cfa_parameter_list
    2816         | cfa_abstract_parameter_list
    2817         | cfa_parameter_list ',' cfa_abstract_parameter_list
    2818                 { $$ = $1->set_last( $3 ); }
    2819         | cfa_parameter_list ',' ELLIPSIS
    2820                 { $$ = $1->addVarArgs(); }
    2821         | cfa_abstract_parameter_list ',' ELLIPSIS
    2822                 { $$ = $1->addVarArgs(); }
    2823         ;
    2824 
    2825 cfa_parameter_list:                                                                             // CFA
    2826                 // To obtain LR(1) between cfa_parameter_list and cfa_abstract_tuple, the last cfa_abstract_parameter_list is
    2827                 // factored out from cfa_parameter_list, flattening the rules to get lookahead to the ']'.
    2828         cfa_parameter_declaration
    2829         | cfa_abstract_parameter_list ',' cfa_parameter_declaration
    2830                 { $$ = $1->set_last( $3 ); }
    2831         | cfa_parameter_list ',' cfa_parameter_declaration
    2832                 { $$ = $1->set_last( $3 ); }
    2833         | cfa_parameter_list ',' cfa_abstract_parameter_list ',' cfa_parameter_declaration
    2834                 { $$ = $1->set_last( $3 )->set_last( $5 ); }
    2835         ;
    2836 
    2837 cfa_abstract_parameter_list:                                                    // CFA, new & old style abstract
    2838         cfa_abstract_parameter_declaration
    2839         | cfa_abstract_parameter_list ',' cfa_abstract_parameter_declaration
    2840                 { $$ = $1->set_last( $3 ); }
     2840                { $$ = $1->appendList( $3 ); }
    28412841        ;
    28422842
    28432843// Provides optional identifier names (abstract_declarator/variable_declarator), no initialization, different semantics
    28442844// for typedef name by using type_parameter_redeclarator instead of typedef_redeclarator, and function prototypes.
    2845 
    2846 parameter_declaration:
    2847                 // No SUE declaration in parameter list.
    2848         declaration_specifier_nobody identifier_parameter_declarator default_initializer_opt
    2849                 { $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
    2850         | declaration_specifier_nobody type_parameter_redeclarator default_initializer_opt
    2851                 { $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
    2852         ;
    2853 
    2854 abstract_parameter_declaration:
    2855         declaration_specifier_nobody default_initializer_opt
    2856                 { $$ = $1->addInitializer( $2 ? new InitializerNode( $2 ) : nullptr ); }
    2857         | declaration_specifier_nobody abstract_parameter_declarator default_initializer_opt
    2858                 { $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
    2859         ;
    28602845
    28612846cfa_parameter_declaration:                                                              // CFA, new & old style parameter declaration
     
    28812866        ;
    28822867
     2868parameter_declaration:
     2869                // No SUE declaration in parameter list.
     2870        declaration_specifier_nobody identifier_parameter_declarator default_initializer_opt
     2871                { $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
     2872        | declaration_specifier_nobody type_parameter_redeclarator default_initializer_opt
     2873                { $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
     2874        ;
     2875
     2876abstract_parameter_declaration:
     2877        declaration_specifier_nobody default_initializer_opt
     2878                { $$ = $1->addInitializer( $2 ? new InitializerNode( $2 ) : nullptr ); }
     2879        | declaration_specifier_nobody abstract_parameter_declarator default_initializer_opt
     2880                { $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
     2881        ;
     2882
    28832883// ISO/IEC 9899:1999 Section 6.9.1(6) : "An identifier declared as a typedef name shall not be redeclared as a
    28842884// parameter." Because the scope of the K&R-style parameter-list sees the typedef first, the following is based only on
     
    28892889                { $$ = DeclarationNode::newName( $1 ); }
    28902890        | identifier_list ',' identifier
    2891                 { $$ = $1->set_last( DeclarationNode::newName( $3 ) ); }
     2891                { $$ = $1->appendList( DeclarationNode::newName( $3 ) ); }
    28922892        ;
    28932893
     
    29902990        type_parameter
    29912991        | type_parameter_list ',' type_parameter
    2992                 { $$ = $1->set_last( $3 ); }
     2992                { $$ = $1->appendList( $3 ); }
    29932993        ;
    29942994
     
    30633063        assertion
    30643064        | assertion_list assertion
    3065                 { $$ = $1->set_last( $2 ); }
     3065                { $$ = $1->appendList( $2 ); }
    30663066        ;
    30673067
     
    30913091                { $$ = $3->addQualifiers( $1 ); }
    30923092        | type_declaring_list ',' type_declarator
    3093                 { $$ = $1->set_last( $3->copySpecifiers( $1 ) ); }
     3093                { $$ = $1->appendList( $3->copySpecifiers( $1 ) ); }
    30943094        ;
    30953095
     
    31343134        trait_declaration
    31353135        | trait_declaration_list pop push trait_declaration
    3136                 { $$ = $1->set_last( $4 ); }
     3136                { $$ = $1->appendList( $4 ); }
    31373137        ;
    31383138
     
    31463146        | cfa_function_specifier
    31473147        | cfa_trait_declaring_list pop ',' push identifier_or_type_name
    3148                 { $$ = $1->set_last( $1->cloneType( $5 ) ); }
     3148                { $$ = $1->appendList( $1->cloneType( $5 ) ); }
    31493149        ;
    31503150
     
    31533153                { $$ = $2->addType( $1 ); }
    31543154        | trait_declaring_list pop ',' push declarator
    3155                 { $$ = $1->set_last( $1->cloneBaseType( $5 ) ); }
     3155                { $$ = $1->appendList( $1->cloneBaseType( $5 ) ); }
    31563156        ;
    31573157
     
    31613161        // empty, input file
    31623162        | external_definition_list
    3163                 { parseTree = parseTree ? parseTree->set_last( $1 ) : $1;       }
     3163                { parseTree = parseTree ? parseTree->appendList( $1 ) : $1;     }
    31643164        ;
    31653165
     
    31683168                { $$ = $2; }
    31693169        | external_definition_list push external_definition pop
    3170                 { $$ = $1 ? $1->set_last( $3 ) : $3; }
     3170                { $$ = $1 ? $1->appendList( $3 ) : $3; }
    31713171        ;
    31723172
     
    33953395        ATTRIBUTE '(' '(' attribute_name_list ')' ')'
    33963396                { $$ = $4; }
    3397         | ATTRIBUTE '(' attribute_name_list ')'                         // CFA
    3398                 { $$ = $3; }
    3399         | ATTR '(' attribute_name_list ')'                                      // CFA
    3400                 { $$ = $3; }
    34013397        ;
    34023398
     
    35033499
    35043500variable_function:
    3505         '(' variable_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3501        '(' variable_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    35063502                { $$ = $2->addParamList( $5 ); }
    3507         | '(' attribute_list variable_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3503        | '(' attribute_list variable_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    35083504                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    35093505        | '(' variable_function ')'                                                     // redundant parenthesis
     
    35263522
    35273523function_no_ptr:
    3528         paren_identifier '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3524        paren_identifier '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    35293525                { $$ = $1->addParamList( $3 ); }
    3530         | '(' function_ptr ')' '(' parameter_list_ellipsis_opt ')'
     3526        | '(' function_ptr ')' '(' parameter_type_list_opt ')'
    35313527                { $$ = $2->addParamList( $5 ); }
    3532         | '(' attribute_list function_ptr ')' '(' parameter_list_ellipsis_opt ')'
     3528        | '(' attribute_list function_ptr ')' '(' parameter_type_list_opt ')'
    35333529                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    35343530        | '(' function_no_ptr ')'                                                       // redundant parenthesis
     
    35803576        paren_identifier '(' identifier_list ')'                        // function_declarator handles empty parameter
    35813577                { $$ = $1->addIdList( $3 ); }
    3582         | '(' KR_function_ptr ')' '(' parameter_list_ellipsis_opt ')'
     3578        | '(' KR_function_ptr ')' '(' parameter_type_list_opt ')'
    35833579                { $$ = $2->addParamList( $5 ); }
    3584         | '(' attribute_list KR_function_ptr ')' '(' parameter_list_ellipsis_opt ')'
     3580        | '(' attribute_list KR_function_ptr ')' '(' parameter_type_list_opt ')'
    35853581                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    35863582        | '(' KR_function_no_ptr ')'                                            // redundant parenthesis
     
    36723668
    36733669variable_type_function:
    3674         '(' variable_type_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3670        '(' variable_type_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    36753671                { $$ = $2->addParamList( $5 ); }
    3676         | '(' attribute_list variable_type_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3672        | '(' attribute_list variable_type_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    36773673                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    36783674        | '(' variable_type_function ')'                                        // redundant parenthesis
     
    36953691
    36963692function_type_no_ptr:
    3697         paren_type '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3693        paren_type '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    36983694                { $$ = $1->addParamList( $3 ); }
    3699         | '(' function_type_ptr ')' '(' parameter_list_ellipsis_opt ')'
     3695        | '(' function_type_ptr ')' '(' parameter_type_list_opt ')'
    37003696                { $$ = $2->addParamList( $5 ); }
    3701         | '(' attribute_list function_type_ptr ')' '(' parameter_list_ellipsis_opt ')'
     3697        | '(' attribute_list function_type_ptr ')' '(' parameter_type_list_opt ')'
    37023698                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    37033699        | '(' function_type_no_ptr ')'                                          // redundant parenthesis
     
    37423738                { $$ = $1->addQualifiers( $2 ); }
    37433739        | '&' MUTEX paren_identifier attribute_list_opt
    3744                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ),
    3745                                                                                                                         OperKinds::AddressOf ) )->addQualifiers( $4 ); }
     3740                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37463741        | identifier_parameter_ptr
    37473742        | identifier_parameter_array attribute_list_opt
     
    37723767
    37733768identifier_parameter_function:
    3774         paren_identifier '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3769        paren_identifier '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    37753770                { $$ = $1->addParamList( $3 ); }
    3776         | '(' identifier_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3771        | '(' identifier_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    37773772                { $$ = $2->addParamList( $5 ); }
    37783773        | '(' identifier_parameter_function ')'                         // redundant parenthesis
     
    37933788                { $$ = $1->addQualifiers( $2 ); }
    37943789        | '&' MUTEX typedef_name attribute_list_opt
    3795                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ),
    3796                                                                                                                         OperKinds::AddressOf ) )->addQualifiers( $4 ); }
     3790                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37973791        | type_parameter_ptr
    37983792        | type_parameter_array attribute_list_opt
     
    38263820
    38273821type_parameter_function:
    3828         typedef_name '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3822        typedef_name '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    38293823                { $$ = $1->addParamList( $3 ); }
    3830         | '(' type_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3824        | '(' type_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    38313825                { $$ = $2->addParamList( $5 ); }
    38323826        ;
     
    38763870
    38773871abstract_function:
    3878         '(' parameter_list_ellipsis_opt ')'                     // empty parameter list OBSOLESCENT (see 3)
     3872        '(' parameter_type_list_opt ')'                 // empty parameter list OBSOLESCENT (see 3)
    38793873                { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
    3880         | '(' abstract_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3874        | '(' abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    38813875                { $$ = $2->addParamList( $5 ); }
    38823876        | '(' abstract_function ')'                                                     // redundant parenthesis
     
    38943888                { $$ = DeclarationNode::newArray( $3, nullptr, false )->addArray( DeclarationNode::newArray( $6, nullptr, false ) ); }
    38953889                // { SemanticError( yylloc, "New array dimension is currently unimplemented." ); $$ = nullptr; }
    3896 
    3897                 // If needed, the following parses and does not use comma_expression, so the array structure can be built.
    3898         // | '[' push assignment_expression pop ',' push array_dimension_list pop ']' // CFA
    3899 
    39003890        | '[' push array_type_list pop ']'                                      // CFA
    39013891                { $$ = DeclarationNode::newArray( $3, nullptr, false ); }
    39023892        | multi_array_dimension
    39033893        ;
    3904 
    3905 // array_dimension_list:
    3906 //      assignment_expression
    3907 //      | array_dimension_list ',' assignment_expression
    3908 //      ;
    39093894
    39103895array_type_list:
     
    40083993
    40093994abstract_parameter_function:
    4010         '(' parameter_list_ellipsis_opt ')'                     // empty parameter list OBSOLESCENT (see 3)
     3995        '(' parameter_type_list_opt ')'                 // empty parameter list OBSOLESCENT (see 3)
    40113996                { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
    4012         | '(' abstract_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3997        | '(' abstract_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    40133998                { $$ = $2->addParamList( $5 ); }
    40143999        | '(' abstract_parameter_function ')'                           // redundant parenthesis
     
    40874072
    40884073variable_abstract_function:
    4089         '(' variable_abstract_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
     4074        '(' variable_abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
    40904075                { $$ = $2->addParamList( $5 ); }
    40914076        | '(' variable_abstract_function ')'                            // redundant parenthesis
     
    41734158//
    41744159//              cfa_abstract_tuple identifier_or_type_name
    4175 //              '[' cfa_parameter_list ']' identifier_or_type_name '(' cfa_parameter_list_ellipsis_opt ')'
     4160//              '[' cfa_parameter_list ']' identifier_or_type_name '(' cfa_parameter_ellipsis_list_opt ')'
    41764161//
    41774162// since a function return type can be syntactically identical to a tuple type:
     
    42394224
    42404225cfa_abstract_function:                                                                  // CFA
    4241         '[' ']' '(' cfa_parameter_list_ellipsis_opt ')'
    4242                 { $$ = DeclarationNode::newFunction( nullptr, DeclarationNode::newTuple( nullptr ), $4, nullptr ); }
    4243         | cfa_abstract_tuple '(' push cfa_parameter_list_ellipsis_opt pop ')'
     4226//      '[' ']' '(' cfa_parameter_ellipsis_list_opt ')'
     4227//              { $$ = DeclarationNode::newFunction( nullptr, DeclarationNode::newTuple( nullptr ), $4, nullptr ); }
     4228        cfa_abstract_tuple '(' push cfa_parameter_ellipsis_list_opt pop ')'
    42444229                { $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); }
    4245         | cfa_function_return '(' push cfa_parameter_list_ellipsis_opt pop ')'
     4230        | cfa_function_return '(' push cfa_parameter_ellipsis_list_opt pop ')'
    42464231                { $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); }
    42474232        ;
  • src/ResolvExpr/Resolver.cc

    rf6e8c67 rbbf2cb1  
    412412
    413413        void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
    414         bool shouldGenCtorInit( const ast::ObjectDecl * ) const;
    415414
    416415        void beginScope() { managedTypes.beginScope(); }
     
    582581}
    583582
    584 bool Resolver::shouldGenCtorInit( ast::ObjectDecl const * decl ) const {
    585         // If we shouldn't try to construct it, then don't.
    586         if ( !InitTweak::tryConstruct( decl ) ) return false;
    587         // Otherwise, if it is a managed type, we may construct it.
    588         if ( managedTypes.isManaged( decl ) ) return true;
    589         // Skip construction if it is trivial at compile-time.
    590         if ( InitTweak::isConstExpr( decl->init ) ) return false;
    591         // Skip construction for local declarations.
    592         return ( !isInFunction() || decl->storage.is_static );
    593 }
    594 
    595583const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) {
    596584        // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
     
    627615                        // this object in visitor pass, thus disabling CtorInit codegen.
    628616                        // this happens on aggregate members and function parameters.
    629                         if ( shouldGenCtorInit( mutDecl ) ) {
     617                        if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) {
    630618                                // constructed objects cannot be designated
    631619                                if ( InitTweak::isDesignated( mutDecl->init ) ) {
Note: See TracChangeset for help on using the changeset viewer.