Changeset f6e8c67


Ignore:
Timestamp:
Mar 6, 2024, 6:06:43 AM (13 months ago)
Author:
JiadaL <j82liang@…>
Branches:
master
Children:
647d633
Parents:
bbf2cb1 (diff), af60383 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Files:
14 edited

Legend:

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

    rbbf2cb1 rf6e8c67  
    22\label{s:RelatedWork}
    33
    4 An 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.
     4In general, an \Newterm{algebraic data type} (ADT) is a composite type, \ie, a type formed by combining other types.
     5Three 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).
     6Enumerated 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.
     7Values of algebraic types are access by subscripting, field qualification, or type (pattern) matching.
     8
     9Enumeration 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}.
    510Among theses languages, there are a large set of overlapping features, but each language has its own unique extensions and restrictions.
    611
    7 
    812\section{Pascal}
    9 
    10 \lstnewenvironment{pascal}[1][]{% necessary
    11 \lstset{
    12 language=pascal,
    13 escapechar=\$,                                                  % LaTeX escape in code
    14 moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
    15 }% lstset
    16 \lstset{#1}% necessary
    17 }{}
     13\lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    1814
    1915Classic Pascal has the \lstinline[language=pascal]{const} declaration binding a name to a constant literal/expression.
     
    2218                 PI = 3.14159;   Plus = '+';   Fred = 'Fred';
    2319\end{pascal}
    24 The enumerator type is inferred from the constant-expression type.
    25 There is no notion of an ordered set, modulo the \lstinline[language=pascal]{set of} type.
     20Here, there is no enumeration because there is no specific type (pseudo enumeration).
     21Hence, there is no notion of a (possibly ordered) set, modulo the \lstinline[language=pascal]{set of} type.
     22The type of each constant name (enumerator) is inferred from the constant-expression type.
    2623
    2724Free Pascal~\cite[\S~3.1.1]{FreePascal} is a modern, object-oriented version of classic Pascal, with a C-style enumeration type.
     
    4239
    4340\section{Ada}
    44 
    45 \lstnewenvironment{ada}[1][]{% necessary
    46 \lstset{
    47 language=[2005]Ada,
    48 escapechar=\$,                                                  % LaTeX escape in code
    49 moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
    50 literate={'}{\ttfamily'\!}1                             % remove '-' literate as comment
    51 }% lstset
    52 \lstset{#1}% necessary
    53 }{}
     41\lstnewenvironment{ada}[1][]{\lstset{language=[2005]Ada,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},literate={'}{\ttfamily'\!}1}\lstset{#1}}{}
    5442
    5543An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
    5644\begin{ada}
    57 type RGB is ( @Red@, @Green@, Blue ); -- 3 literals (enumerators)
     45type RGB is ( Red, Green, Blue ); -- 3 literals (enumerators)
    5846\end{ada}
    59 No other enumerators are assignable to objects of this type.
     47Object initialization and assignment are restricted to the enumerators of this type.
    6048Enumerators 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.
    6149To explicitly set enumerator values, \emph{all} enumerators must be set in \emph{ascending} order, \ie there is no auto-initialization.
     
    6856(0, 10, RED)  (1, 20, GREEN)  (2, 30, BLUE)
    6957\end{ada}
     58Note, 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).
    7059
    7160Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope.
    72 Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same name (a questionable design decision).
    73 The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relation is given implicitly by the sequence of enumerators, which is always ascending.
     61The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of enumerators, which is always ascending.
    7462
    7563Ada enumerators are overloadable.
     
    136124\begin{ada}
    137125type Operator is ( '+', '-', '*', '/' );
    138 Op : Operator;
    139126\end{ada}
    140127which is syntactic sugar for the label and not character literals from the predefined type @Character@.
    141 The purpose is readability using character literals rather than names.
     128The purpose is strictly readability using character literals rather than names.
    142129\begin{ada}
    143 Op := '+';
    144 case Op is                    -- all enumerators must appear
    145         when '+' => ... ;
    146         when '-' => ... ;
    147         when '*' => ... ;
    148         when '/' => ... ;
    149 end case;
     130Op : Operator := '+';
     131if Op = '+' or else Op = '-' then ... ;
     132elsif Op = '*' or else Op = '/' then ... ; end if;
    150133\end{ada}
    151 Arrays of character enumerators can be treated as strings.
     134Interestingly, arrays of character enumerators can be treated as strings.
    152135\begin{ada}
    153136Ops : array( 0..3 ) of Operator;
    154137Ops := @"+-*/"@;            -- string assignment to array elements
    155138Ops := @"+-" & "*/"@;   -- string concatenation and assignment
    156 for Op of Ops loop
    157         Put_Line( Operator'Image( Op ) );
    158 end loop;
    159139\end{ada}
    160140Ada's @Character@ type is defined as a character enumeration across all Latin-1 characters.
    161141
    162 Ada's boolean type is defined as a special enumeration, which can be used in conditions.
     142Ada's boolean type is also a special enumeration, which can be used in conditions.
    163143\begin{ada}
    164144type Boolean is (False, True); -- False / True not keywords
     
    177157Hence, the ordering of the enumerators is crucial to provide the necessary ranges.
    178158
    179 An enumeration type can be used in the Ada \lstinline[language=ada]{case} (switch) and iterating constructs.
     159An enumeration type can be used in the Ada \lstinline[language=ada]{case} (all enumerators must appear or a default) or iterating constructs.
    180160\begin{cquote}
    181161\lstDeleteShortInline@
     
    233213\section{\CC}
    234214\label{s:C++RelatedWork}
    235 
    236 \lstnewenvironment{c++}[1][]{% necessary
    237 \lstset{
    238 language=[GNU]C++,
    239 escapechar=\$,                                                  % LaTeX escape in code
    240 moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
    241 }% lstset
    242 \lstset{#1}% necessary
    243 }{}
     215\lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    244216
    245217\CC is largely backwards compatible with C, so it inherited C's enumerations.
     
    288260enum class E { A, B, C };
    289261E e = @E::@A;                                                   $\C{// qualified enumerator}$
    290 e = B;                                                                  $\C{// B not in scope}$
     262e = B;                                                                  $\C{// error: B not in scope}$
    291263\end{c++}
    292264\CC{20} supports explicit unscoping with a \lstinline[language=c++]{using enum} declaration.
     
    303275enum class srgb @: signed char@ { Red = -1, Green = 0, Blue = 1 };
    304276\end{c++}
    305 There is no implicit conversion from the \lstinline[language=c++]{enum class} type and to its type.
     277There is no implicit conversion from the \lstinline[language=c++]{enum class} type to its declared type.
    306278\begin{c++}
    307279rgb crgb = rgb::Red;
    308 char ch = rgb::Red;   ch = crgb;                $\C{// disallowed}$
     280char ch = rgb::Red;   ch = crgb;                $\C{// error}$
    309281\end{c++}
    310 Finally, there is no mechanism to iterate through an enumeration nor use the enumeration type to declare an array dimension.
     282Finally, enumerations can be used in the @switch@ statement but there is no mechanism to iterate through an enumeration.
     283An enumeration type cannot declare an array dimension but can be used as a subscript.
     284There is no mechanism to subtype or inherit from enumerations.
    311285
    312286
    313287\section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE
    314 
    315 \lstnewenvironment{csharp}[1][]{% necessary
    316 \lstset{
    317 language=[Sharp]C,
    318 escapechar=\$,                                                  % LaTeX escape in code
    319 moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
    320 }% lstset
    321 \lstset{#1}% necessary
    322 }{}
     288\label{s:Csharp}
     289\lstnewenvironment{csharp}[1][]{\lstset{language=[Sharp]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    323290
    324291% https://www.tutorialsteacher.com/codeeditor?cid=cs-mk8Ojx
    325292
    326 \Csharp is a dynamically-typed programming-language with a scoped, integral enumeration-type similar to C/\CC enumeration.
     293\Csharp is a dynamically-typed programming-language with a scoped, integral enumeration-type similar to the C/\CC enumeration.
    327294\begin{csharp}
    328 enum Weekday : byte { Monday, Tuesday, Wednesday, Thursday@ = 10@, Friday, Saturday, Sunday@,@ };
     295enum Weekday : byte { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun@,@ };
    329296\end{csharp}
    330 The default underlying type is @int@, with auto-incrementing, implicit/explicit initialization, terminator comma, and optional integral typing (default @int@)
     297The default underlying type is @int@, with auto-incrementing, implicit/explicit initialization, terminator comma, and optional integral typing (default @int@).
    331298A method cannot be defined in an enumeration type.
    332299As 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.
    333300\begin{csharp}
    334 int day = (int)Weekday.Friday;                  $\C{// day == 10}$
    335 Weekday weekday = (Weekdays)42;                 $\C{// weekday == 42}$
    336 Console.WriteLine( Weekday.Friday );    $\C{// print Friday}$
    337 string mon = Weekday.Monday.ToString();
     301int day = (int)Weekday.Fri;             $\C{// day == 10}$
     302Weekday weekday = (Weekdays)42;         $\C{// weekday == 42, logically invalid}$
     303Console.WriteLine( Weekday.Fri ); $\C{// print Fri}$
     304string mon = Weekday.Mon.ToString(); $\C{// mon == "Mon"}$
    338305\end{csharp}
    339306
    340 The @Enum.GetValues@ pseudo-method retrieves an array of the enumeration constants for looping over an enumeration type or variable.
     307The @Enum.GetValues@ pseudo-method retrieves an array of the enumeration constants for looping over an enumeration type or variable (expensive operation).
    341308\begin{csharp}
    342309foreach ( Weekday constant in @Enum.GetValues@( typeof(Weekday) ) ) {
     
    348315\begin{csharp}
    349316@[Flags]@ public enum Weekday {
    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 }
    355 Weekday meetings = @Weekday.Monday | Weekday.Wednesday@; // 0x5
     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}
     322Weekday meetings = @Weekday.Mon | Weekday.Wed@; // 0x5
    356323\end{csharp}
    357324
    358 \Csharp supports an enumeration class to embed enumeration operations, where the enumerators are objects.
     325\VRef[Figure]{CsharpFreeVersusClass} shows an enumeration with free routines for manipulation, and embedding the enumeration and operations into an enumeration class.
     326The 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
    359336\begin{csharp}
    360 public 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) { }
     337public 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        }
    364356}
    365357\end{csharp}
    366 Find a meaningful example and test it.
     358&
     359\begin{csharp}
     360public 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}
    367388
    368389
    369390\section{Golang}
    370 
    371 \lstnewenvironment{Go}[1][]{% necessary
    372 \lstset{
    373 language=Go,
    374 escapechar=\$,                                                  % LaTeX escape in code
    375 moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
    376 }% lstset
    377 \lstset{#1}% necessary
    378 }{}
    379 
    380 The Golang enumeration is similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
     391\lstnewenvironment{Go}[1][]{\lstset{language=Go,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
     392
     393Golang provides pseudo-enumeration similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
    381394\begin{Go}
    382395const ( R = 0; G; B )                                   $\C{// implicit: 0 0 0}$
     
    401414Auto-incrementing stops after an explicit initialization.
    402415\begin{Go}
    403 const ( Monday = iota; Tuesday; Wednesday; // 0, 1, 2
    404          @Thursday = 10@; Friday; Saturday; Sunday ) // 10, 10, 10, 10
     416const ( Mon = iota; Tue; Wed; // 0, 1, 2
     417         @Thu = 10@; Fri; Sat; Sun ) // 10, 10, 10, 10
    405418\end{Go}
    406419Auto-incrementing can be restarted with an expression containing \emph{one} \lstinline[language=Go]{iota}.
    407420\begin{Go}
    408421const ( V1 = iota; V2; @V3 = 7;@ V4 = @iota@; V5 ) // 0 1 7 3 4
    409 const ( Monday = iota; Tuesday; Wednesday; // 0, 1, 2
    410          @Thursday = 10;@ Friday = @iota - Wednesday + Thursday - 1@; Saturday; Sunday ) // 10, 11, 12, 13
     422const ( Mon = iota; Tue; Wed; // 0, 1, 2
     423         @Thu = 10;@ Fri = @iota - Wed + Thu - 1@; Sat; Sun ) // 10, 11, 12, 13
    411424\end{Go}
    412425Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier.
    413426
     427Basic switch and looping are possible.
     428\begin{cquote}
     429\lstDeleteShortInline@
     430\setlength{\tabcolsep}{15pt}
     431\begin{tabular}{@{}ll@{}}
     432\begin{Go}
     433day := Mon;
     434switch 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
     444for 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}
     454However, the loop prints the values from 0 to 13 because there is no actual enumeration.
     455
    414456
    415457\section{Java}
    416 
    417 \lstnewenvironment{Java}[1][]{% necessary
    418 \lstset{
    419 language=Java,
    420 escapechar=\$,                                                  % LaTeX escape in code
    421 moredelim=**[is][\color{red}]{`}{`},    % red highlighting @...@
    422 }% lstset
    423 \lstset{#1}% necessary
    424 }{}
    425 
    426 Here'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:
     458\lstnewenvironment{Java}[1][]{\lstset{language=Java,morekeywords={enum,assert,strictfp},
     459        escapechar=\$,moredelim=**[is][\color{red}]{!}{!},}\lstset{#1}}{}
     460
     461Every enumeration in Java is an enumeration class.
     462For a basic enumeration
    427463\begin{Java}
    428 public enum PizzaStatus {
    429     ORDERED,
    430     READY,
    431     DELIVERED;
    432 }
     464enum Weekday { Mon, Tue, Wed, Thu, Fri, Sat, Sun };
     465Weekday day = Weekday.Sat;
    433466\end{Java}
    434 Additionally, 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 
    438 Now 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:
     467the scoped enumerators are an ordered list of @final@ methods of type integer, ordered left to right starting at 0, increasing by 1.
     468The value of an enumeration instance is restricted to the enumeration's enumerators.
     469There is an implicit @int@ variable in the enumeration used to store the value of an enumeration instance.
     470The position (ordinal) and label are accessible, where the value is the same as the position.
    439471\begin{Java}
    440 public 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 }
     472System.out.println( day.!ordinal()! + " " + day.!name()! ); // 5 Sat
    455473\end{Java}
    456 
    457 \paragraph{Comparing Enum Types Using "==" Operator}
    458 
    459 Since 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.
    460 Furthermore, the "==" operator provides compile-time and run-time safety.
    461 
    462 First, we'll look at run-time safety in the following snippet, where we'll use the "==" operator to compare statuses.
    463 Either value can be null and we won't get a NullPointerException. Conversely, if we use the equals method, we will get a NullPointerException:
     474There is an inverse function @valueOf@ from string to enumerator.
    464475\begin{Java}
    465 if(testPz.getStatus().equals(Pizza.PizzaStatus.DELIVERED));
    466 if(testPz.getStatus() == Pizza.PizzaStatus.DELIVERED);
     476day = Weekday.valueOf( "Wed" );
    467477\end{Java}
    468 As 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.
    469 This is because the values of the enum and the getStatus method coincidentally are the same;
    470 however, logically the comparison should be false. We avoid this issue by using the "==" operator.
    471 
    472 The compiler will flag the comparison as an incompatibility error:
     478There are no implicit conversions to/from an enumerator and its underlying type.
     479Like \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
    473487\begin{Java}
    474 if(testPz.getStatus().equals(TestColor.GREEN));
    475 if(testPz.getStatus() == TestColor.GREEN);
     488enum Weekday !{!
     489        Mon, Tue, Wed, Thu, Fri, Sat, Sun !}!;
     490
     491static boolean isWeekday( Weekday wd ) {
     492        return wd.ordinal() <= Weekday.Fri.ordinal();
     493}
     494static boolean isWeekend( Weekday wd ) {
     495        return Weekday.Fri.ordinal() < wd.ordinal();
     496}
     497
     498public static void main( String[] args ) {
     499        Weekday day = Weekday.Sat;
     500        System.out.println( isWeekday( day ) );
     501        System.out.println( isWeekend( day ) );
     502}
    476503\end{Java}
    477 
    478 \paragraph{Using Enum Types in Switch Statements}
    479 
    480 We can use enum types in switch statements also:
     504&
    481505\begin{Java}
    482 public int getDeliveryTimeInDays() {
    483     switch (status) {
    484         case ORDERED: return 5;
    485         case READY: return 2;
    486         case DELIVERED: return 0;
    487     }
    488     return 0;
     506enum 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!}!
     516public static void main( String[] args ) {
     517        WeekDay day = WeekDay.Sat;
     518        System.out.println( day.isWeekday() );
     519        System.out.println( day.isWeekend() );
    489520}
    490521\end{Java}
    491 
    492 \paragraph{Fields, Methods and Constructors in Enums}
    493 
    494 We can define constructors, methods, and fields inside enum types, which makes them very powerful.
    495 
    496 Next, let's extend the example above by implementing the transition from one stage of a pizza order to another.
    497 We'll see how we can get rid of the if and switch statements used before:
     522\end{tabular}
     523\lstMakeShortInline@
     524\caption{Java: Free Routine Versus Class Enumeration}
     525\label{f:JavaFreeVersusClass}
     526\end{figure}
     527
     528To 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.
    498529\begin{Java}
    499 public 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 }
     530enum 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};
     535Weekday day = Weekday.Sat;
    541536\end{Java}
    542 The test snippet below demonstrates how this works:
     537If an enumerator initialization is a runtime expression, the expression is executed once at the point the enumeration is declaraed.
     538
     539The position, value, and label are accessible.
    543540\begin{Java}
    544 @Test
    545 public void givenPizaOrder_whenReady_thenDeliverable() {
    546     Pizza testPz = new Pizza();
    547     testPz.setStatus(Pizza.PizzaStatus.READY);
    548     assertTrue(testPz.isDeliverable());
    549 }
     541System.out.println( !day.ordinal()! + " " + !day.day! + " " + !day.name()! );  // 5 6 Sat
    550542\end{Java}
    551 
    552 \paragraph{EnumSet and EnumMap}
    553 
    554 \paragraph{EnumSet}
    555 
    556 The EnumSet is a specialized Set implementation that's meant to be used with Enum types.
    557 
    558 Compared 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.
    559 It 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 
    561 The 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 
    563 Therefore, 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 
    565 In the code snippet below, we can see how to use EnumSet to create a subset of constants:
     543The constructor is private so only initialization or assignment can be used to set an enumeration, which ensures only corresponding enumerator values are allowed.
     544
     545An enumeration can appear in a @switch@ statement, but no ranges.
    566546\begin{Java}
    567 public 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.
     547switch ( 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;
    594554}
    595555\end{Java}
    596 
    597 Executing the following test demonstrates the power of the EnumSet implementation of the Set interface:
     556Like \Csharp, looping over an enumeration is done using method @values@, which returns the array of enumerator values (expensive operation).
    598557\begin{Java}
    599 @Test
    600 public 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 }
     558for ( Weekday iday : Weekday.values() ) {
     559        System.out.print( iday.ordinal() + iday.day + " " +  iday.name() + ",  " );
     560}
     5610 1 Mon,  1 2 Tue,  2 3 Wed,  3 4 Thu,  4 5 Fri,  5 6 Sat,  6 7 Sun, 
    622562\end{Java}
    623563
    624 \paragraph{EnumMap}
    625 
    626 EnumMap is a specialized Map implementation meant to be used with enum constants as keys.
    627 Compared to its counterpart HashMap, it's an efficient and compact implementation that's internally represented as an array:
    628 \begin{Java}
    629 EnumMap<Pizza.PizzaStatus, Pizza> map;
    630 \end{Java}
    631 Let's look at an example of how we can use it in practice:
    632 \begin{Java}
    633 public 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}
    651 Executing the following test demonstrates the power of the EnumMap implementation of the Map interface:
    652 \begin{Java}
    653 @Test
    654 public 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 
    682 Normally, implementing a class using the Singleton pattern is quite non-trivial.
    683 Enums provide a quick and easy way of implementing singletons.
    684 
    685 In addition, since the enum class implements the Serializable interface under the hood, the class is guaranteed to be a singleton by the JVM.
    686 This is unlike the conventional implementation, where we have to ensure that no new instances are created during deserialization.
    687 
    688 In the code snippet below, we see how we can implement a singleton pattern:
    689 \begin{Java}
    690 public 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 
    711 Conventionally, the Strategy pattern is written by having an interface that is implemented by different classes.
    712 
    713 Adding a new strategy means adding a new implementation class.
    714 With enums, we can achieve this with less effort, and adding a new implementation means simply defining another instance with some implementation.
    715 
    716 The code snippet below shows how to implement the Strategy pattern:
    717 \begin{Java}
    718 public 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}
    735 Then we add the following method to the Pizza class:
    736 \begin{Java}
    737 public void deliver() {
    738     if (isDeliverable()) {
    739         PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy()
    740           .deliver(this);
    741         this.setStatus(PizzaStatus.DELIVERED);
    742     }
    743 }
    744 
    745 @Test
    746 public 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 
    754 8. Java 8 and Enums
    755 
    756 We 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}
    758 public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
    759     return input.stream().filter(
    760       (s) -> !deliveredPizzaStatuses.contains(s.getStatus()))
    761         .collect(Collectors.toList());
    762 }
    763 
    764 public 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}
     564As 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.
     565There is also a specialized version of @HashMap@ with enumerator keys, which has performance benefits.
     566
     567Enumeration inheritence is disallowed because an enumeration is @final@.
     568
    772569
    773570
    774571\section{Modula-3}
    775572
     573
     574
    776575\section{Rust}
     576\lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
     577
     578Enumerations
     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}
     600An 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
     602Enumerations are declared with the keyword enum.
     603
     604An example of an enum item and its use:
     605\begin{rust}
     606enum Animal {
     607        Dog,
     608        Cat,
     609}
     610
     611let mut a: Animal = Animal::Dog;
     612a = Animal::Cat;
     613\end{rust}
     614Enum constructors can have either named or unnamed fields:
     615\begin{rust}
     616enum Animal {
     617        Dog(String, f64),
     618        Cat { name: String, weight: f64 },
     619}
     620
     621let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2);
     622a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
     623\end{rust}
     624In this example, Cat is a struct-like enum variant, whereas Dog is simply called an enum variant.
     625
     626An enum where no constructors contain fields are called a field-less enum. For example, this is a fieldless enum:
     627\begin{rust}
     628enum Fieldless {
     629        Tuple(),
     630        Struct{},
     631        Unit,
     632}
     633\end{rust}
     634If a field-less enum only contains unit variants, the enum is called an unit-only enum. For example:
     635\begin{rust}
     636enum Enum {
     637        Foo = 3,
     638        Bar = 2,
     639        Baz = 1,
     640}
     641\end{rust}
     642
     643\subsection{Discriminants}
     644
     645Each enum instance has a discriminant: an integer logically associated to it that is used to determine which variant it holds.
     646
     647Under 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
     653In 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
     672If 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}
     674enum Foo {
     675        Bar,                    // 0
     676        Baz = 123,        // 123
     677        Quux,              // 124
     678}
     679
     680let baz_discriminant = Foo::Baz as u32;
     681assert_eq!(baz_discriminant, 123);
     682\end{rust}
     683
     684\subsection{Restrictions}
     685
     686It is an error when two variants share the same discriminant.
     687\begin{rust}
     688enum SharedDiscriminantError {
     689        SharedA = 1,
     690        SharedB = 1
     691}
     692
     693enum SharedDiscriminantError2 {
     694        Zero,      // 0
     695        One,            // 1
     696        OneToo = 1  // 1 (collision with previous!)
     697}
     698\end{rust}
     699It 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)]
     702enum OverflowingDiscriminantError {
     703        Max = 255,
     704        MaxPlusOne // Would be 256, but that overflows the enum.
     705}
     706
     707#[repr(u8)]
     708enum 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}
     718Via 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
     724If 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}
     726enum Enum {
     727        Foo,
     728        Bar,
     729        Baz,
     730}
     731
     732assert_eq!(0, Enum::Foo as isize);
     733assert_eq!(1, Enum::Bar as isize);
     734assert_eq!(2, Enum::Baz as isize);
     735\end{rust}
     736Field-less enums can be casted if they do not have explicit discriminants, or where only unit variants are explicit.
     737\begin{rust}
     738enum Fieldless {
     739        Tuple(),
     740        Struct{},
     741        Unit,
     742}
     743
     744assert_eq!(0, Fieldless::Tuple() as isize);
     745assert_eq!(1, Fieldless::Struct{} as isize);
     746assert_eq!(2, Fieldless::Unit as isize);
     747\end{rust}
     748\begin{rust}
     749#[repr(u8)]
     750enum FieldlessWithDiscrimants {
     751        First = 10,
     752        Tuple(),
     753        Second = 20,
     754        Struct{},
     755        Unit,
     756}
     757
     758assert_eq!(10, FieldlessWithDiscrimants::First as u8);
     759assert_eq!(11, FieldlessWithDiscrimants::Tuple() as u8);
     760assert_eq!(20, FieldlessWithDiscrimants::Second as u8);
     761assert_eq!(21, FieldlessWithDiscrimants::Struct{} as u8);
     762assert_eq!(22, FieldlessWithDiscrimants::Unit as u8);
     763\end{rust}
     764
     765\subsection{Pointer casting}
     766
     767If the enumeration specifies a primitive representation, then the discriminant may be reliably accessed via unsafe pointer casting:
     768\begin{rust}
     769#[repr(u8)]
     770enum Enum {
     771        Unit,
     772        Tuple(bool),
     773        Struct{a: bool},
     774}
     775
     776impl Enum {
     777        fn discriminant(&self) -> u8 {
     778                unsafe { *(self as *const Self as *const u8) }
     779        }
     780}
     781
     782let unit_like = Enum::Unit;
     783let tuple_like = Enum::Tuple(true);
     784let struct_like = Enum::Struct{a: false};
     785
     786assert_eq!(0, unit_like.discriminant());
     787assert_eq!(1, tuple_like.discriminant());
     788assert_eq!(2, struct_like.discriminant());
     789\end{rust}
     790
     791\subsection{Zero-variant enums}
     792
     793Enums with zero variants are known as zero-variant enums. As they have no valid values, they cannot be instantiated.
     794\begin{rust}
     795enum ZeroVariants {}
     796\end{rust}
     797Zero-variant enums are equivalent to the never type, but they cannot be coerced into other types.
     798\begin{rust}
     799let x: ZeroVariants = panic!();
     800let y: u32 = x; // mismatched type error
     801\end{rust}
     802
     803\subsection{Variant visibility}
     804
     805Enum 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}
     807macro_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.
     820mac_variant! { E }
     821
     822// This is allowed, since it is removed before being validated.
     823#[cfg(FALSE)]
     824enum E {
     825        pub U,
     826        pub(crate) T(u8),
     827        pub(super) T { f: String }
     828}
     829\end{rust}
    777830
    778831
    779832\section{Swift}
    780 
    781 \lstnewenvironment{swift}[1][]{% necessary
    782 \lstset{
    783 language=Swift,
    784 escapechar=\$,                                                  % LaTeX escape in code
    785 moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
    786 }% lstset
    787 \lstset{#1}% necessary
    788 }{}
    789 
    790 Model custom types that define a list of possible values.
     833\lstnewenvironment{swift}[1][]{\lstset{language=Swift,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
     834
     835% https://www.programiz.com/swift/online-compiler
     836
     837A 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}
     839enum 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};
     844var day = Many.Sat; // qualification to resolve type
     845print( day );
     846day = .Wed // no qualification after type resolved
     847print( day );
     848day = .code( "ABC" );
     849print( day );
     850day = .tuple( 1, 2, 3 );
     851print( day );
     852
     853Sat
     854Wed
     855code("ABC")
     856tuple(1, 2, 3)
     857\end{swift}
     858
    791859
    792860An 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.
     
    808876\paragraph{Enumeration Syntax}
    809877
    810 You introduce enumerations with the @enum@ keyword and place their entire definition within a pair of braces:
    811 \begin{swift}
    812 enum SomeEnumeration {
    813         // enumeration definition goes here
    814 }
    815 \end{swift}
    816 Here's an example for the four main points of a compass:
    817 \begin{swift}
    818 enum CompassPoint {
    819         case north
    820         case south
    821         case east
    822         case west
    823 }
    824 \end{swift}
    825 The values defined in an enumeration (such as @north@, @south@, @east@, and @west@) are its enumeration cases.
    826 You use the @case@ keyword to introduce new enumeration cases.
    827878
    828879Note:
     
    11391190
    11401191\section{Python}
     1192\lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
     1193
     1194An @Enum@ is a set of symbolic names bound to unique values.
     1195They are similar to global variables, but they offer a more useful @repr()@, grouping, type-safety, and a few other features.
     1196
     1197They 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}
     1209Or 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}
     1217As you can see, creating an @Enum@ is as simple as writing a class that inherits from @Enum@ itself.
     1218
     1219Note: Case of Enum Members
     1220
     1221Because 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
     1223Depending 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}
     1228As you can see, the @repr()@ of a member shows the enum name, the member name, and the value.
     1229The @str()@ of a member shows only the enum name and member name:
     1230\begin{python}
     1231print(Weekday.THURSDAY)
     1232Weekday.THURSDAY
     1233\end{python}
     1234The type of an enumeration member is the enum it belongs to:
     1235\begin{python}
     1236>>> type(Weekday.MONDAY)
     1237<enum 'Weekday'>
     1238isinstance(Weekday.FRIDAY, Weekday)
     1239True
     1240\end{python}
     1241Enum members have an attribute that contains just their name:
     1242\begin{python}
     1243>>> print(Weekday.TUESDAY.name)
     1244TUESDAY
     1245\end{python}
     1246Likewise, they have an attribute for their value:
     1247\begin{python}
     1248>>> Weekday.WEDNESDAY.value
     12493
     1250\end{python}
     1251Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added.
     1252For example, @datetime.date@ has two methods for returning the weekday: @weekday()@ and @isoweekday()@.
     1253The difference is that one of them counts from 0-6 and the other from 1-7.
     1254Rather 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
     1257def from_date(cls, date):
     1258    return cls(date.isoweekday())
     1259\end{python}
     1260The 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}
     1275Now 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}
     1281Of course, if you're reading this on some other day, you'll see that day instead.
     1282
     1283This 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}
     1295We've changed two things: we're inherited from @Flag@, and the values are all powers of 2.
     1296
     1297Just 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}
     1303But @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}
     1309You can even iterate over a @Flag@ variable:
     1310\begin{python}
     1311>>> for day in weekend:
     1312...    print(day)
     1313Weekday.SATURDAY
     1314Weekday.SUNDAY
     1315\end{python}
     1316Okay, 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}
     1324And 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)
     1331answer SO questions
     1332\end{python}
     1333In 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
     1349Sometimes 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}
     1357If you want to access enum members by name, use item access:
     1358\begin{python}
     1359Color['RED']
     1360<Color.RED: 1>
     1361
     1362Color['GREEN']
     1363<Color.GREEN: 2>
     1364\end{python}
     1365If 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
     13711
     1372\end{python}
     1373
     1374\subsection{Duplicating enum members and values}
     1375
     1376Having two enum members with the same name is invalid:
     1377\begin{python}
     1378>>> class Shape(Enum):
     1379...    SQUARE = 2
     1380...    SQUARE = 3
     1381...
     1382Traceback (most recent call last):
     1383...
     1384TypeError: 'SQUARE' already defined as 2
     1385\end{python}
     1386However, an enum member can have other names associated with it.
     1387Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@.
     1388By-value lookup of the value of @A@ will return the member @A@.
     1389By-name lookup of @A@ will return the member @A@.
     1390By-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
     1406Note: 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
     1410By default, enumerations allow multiple names as aliases for the same value.
     1411When 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...
     1421Traceback (most recent call last):
     1422...
     1423ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
     1424\end{python}
     1425
     1426\subsection{Using automatic values}
     1427
     1428If 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}
     1439The 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}
     1455Note The @_generate_next_value_()@ method must be defined before any members.
     1456
     1457\subsection{Iteration}
     1458
     1459Iterating 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}
     1467Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Weekday.WEEKEND@ aren't shown.
     1468
     1469The special attribute @__members__@ is a read-only ordered mapping of names to members.
     1470It 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}
     1480The @__members__@ attribute can be used for detailed programmatic access to the enumeration members.
     1481For 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}
     1486Note: Aliases for flags include values with multiple flags set, such as 3, and no flags set, i.e. 0.
     1487
     1488\subsection{Comparisons}
     1489
     1490Enumeration members are compared by identity:
     1491\begin{python}
     1492>>> Color.RED is Color.RED
     1493True
     1494>>> Color.RED is Color.BLUE
     1495False
     1496>>> Color.RED is not Color.BLUE
     1497True
     1498\end{python}
     1499Ordered comparisons between enumeration values are not supported.
     1500Enum members are not integers (but see @IntEnum@ below):
     1501\begin{python}
     1502>>> Color.RED < Color.BLUE
     1503Traceback (most recent call last):
     1504  File "<stdin>", line 1, in <module>
     1505TypeError: '<' not supported between instances of 'Color' and 'Color'
     1506\end{python}
     1507Equality comparisons are defined though:
     1508\begin{python}
     1509>>> Color.BLUE == Color.RED
     1510False
     1511>>> Color.BLUE != Color.RED
     1512True
     1513>>> Color.BLUE == Color.BLUE
     1514True
     1515\end{python}
     1516Comparisons 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
     1519False
     1520\end{python}
     1521
     1522Warning: 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
     1526Most of the examples above use integers for enumeration values.
     1527Using integers is short and handy (and provided by default by the Functional API), but not strictly enforced.
     1528In the vast majority of use-cases, one doesn't care what the actual value of an enumeration is.
     1529But if the value is important, enumerations can have arbitrary values.
     1530
     1531Enumerations 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}
     1551Then:
     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}
     1560The 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;
     1561all 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
     1563Note: if your enumeration defines @__new__()@ and/or @__init__()@, any value(s) given to the enum member will be passed into those methods.
     1564See Planet for an example.
     1565
     1566Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
     1567it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
     1568See When to use @__new__()@ vs. @__init__()@ for more details.
     1569
     1570\subsection{Restricted Enum subclassing}
     1571
     1572A new @Enum@ class must have one base enum class, up to one concrete data type, and as many object-based mixin classes as needed.
     1573The order of these base classes is:
     1574\begin{python}
     1575class EnumName([mix-in, ...,] [data-type,] base-enum):
     1576    pass
     1577\end{python}
     1578Also, subclassing an enumeration is allowed only if the enumeration does not define any members.
     1579So this is forbidden:
     1580\begin{python}
     1581>>> class MoreColor(Color):
     1582...     PINK = 17
     1583...
     1584Traceback (most recent call last):
     1585...
     1586TypeError: <enum 'MoreColor'> cannot extend <enum 'Color'>
     1587\end{python}
     1588But 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}
     1599Allowing subclassing of enums that define members would lead to a violation of some important invariants of types and instances.
     1600On 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
     1604When inheriting from a @dataclass@, the @__repr__()@ omits the inherited class' name.
     1605For 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}
     1621Use the @dataclass()@ argument repr=False to use the standard @repr()@.
     1622
     1623Changed in version 3.12: Only the dataclass fields are shown in the value area, not the dataclass' name.
     1624
     1625\subsection{Pickling}
     1626
     1627Enumerations 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))
     1632True
     1633\end{python}
     1634The 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
     1636Note: With pickle protocol version 4 it is possible to easily pickle enums nested in other classes.
     1637
     1638It is possible to modify how enum members are pickled/unpickled by defining @__reduce_ex__()@ in the enumeration class.
     1639The 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}
     1645Note: Using by-name for flags is not recommended, as unnamed aliases will not unpickle.
     1646
     1647\subsection{Functional API}
     1648
     1649The @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}
     1659The semantics of this API resemble @namedtuple@.
     1660The first argument of the call to @Enum@ is the name of the enumeration.
     1661
     1662The second argument is the source of enumeration member names.
     1663It 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.
     1664The last two options enable assigning arbitrary values to enumerations;
     1665the others auto-assign increasing integers starting with 1 (use the @start@ parameter to specify a different starting value).
     1666A new class derived from @Enum@ is returned.
     1667In 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}
     1676The 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
     1678Pickling 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).
     1679The 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}
     1683Warning: 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
     1685The 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.
     1686For 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}
     1690The complete signature is:
     1691\begin{python}
     1692Enum(
     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.
     1707This 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}
     1711or an iterator of names:
     1712\begin{python}
     1713['RED', 'GREEN', 'BLUE']
     1714\end{python}
     1715or an iterator of (name, value) pairs:
     1716\begin{python}
     1717[('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]
     1718\end{python}
     1719or a mapping:
     1720\begin{python}
     1721{'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}
     1722\end{python}
     1723\item
     1724module: 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}
     1732Changed in version 3.5: The start parameter was added.
     1733
     1734\subsection{Derived Enumerations}
     1735
     1736\subsection{IntEnum}
     1737
     1738The first variation of @Enum@ that is provided is also a subclass of @int@.
     1739Members of an @IntEnum@ can be compared to integers;
     1740by 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
     1752False
     1753>>> Shape.CIRCLE == 1
     1754True
     1755>>> Shape.CIRCLE == Request.POST
     1756True
     1757\end{python}
     1758However, 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
     1769False
     1770\end{python}
     1771@IntEnum@ values behave like integers in other ways you'd expect:
     1772\begin{python}
     1773>>> int(Shape.CIRCLE)
     17741
     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
     1783The second variation of @Enum@ that is provided is also a subclass of @str@.
     1784Members of a @StrEnum@ can be compared to strings;
     1785by extension, string enumerations of different types can also be compared to each other.
     1786
     1787New in version 3.11.
     1788
     1789\subsection{IntFlag}
     1790
     1791The next variation of @Enum@ provided, @IntFlag@, is also based on @int@.
     1792The difference being @IntFlag@ members can be combined using the bitwise operators (@&, |, ^, ~@) and the result is still an @IntFlag@ member, if possible.
     1793Like @IntEnum@, @IntFlag@ members are also integers and can be used wherever an int is used.
     1794
     1795Note: Any operation on an IntFlag member besides the bit-wise operations will lose the @IntFlag@ membership.
     1796
     1797Bit-wise operations that result in invalid @IntFlag@ values will lose the @IntFlag@ membership.
     1798See @FlagBoundary@ for details.
     1799
     1800New in version 3.6.
     1801
     1802Changed in version 3.11.
     1803
     1804Sample @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
     18156
     1816>>> RW = Perm.R | Perm.W
     1817>>> Perm.R in RW
     1818True
     1819\end{python}
     1820It 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}
     1835Note: Named combinations are considered aliases. Aliases do not show up during iteration, but can be returned from by-value lookups.
     1836
     1837Changed in version 3.11.
     1838
     1839Another 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)
     1844False
     1845\end{python}
     1846Because @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
     18529
     1853\end{python}
     1854Note: 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
     1857True
     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}
     1864New in version 3.11.
     1865
     1866\subsection{Flag}
     1867
     1868The last variation is @Flag@.
     1869Like @IntFlag@, @Flag@ members can be combined using the bitwise operators (@&, |, ^, ~@).
     1870Unlike @IntFlag@, they cannot be combined with, nor compared against, any other @Flag@ enumeration, nor @int@.
     1871While 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
     1873New in version 3.6.
     1874
     1875Like @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)
     1886False
     1887\end{python}
     1888Individual 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}
     1899Giving 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)
     1910False
     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}
     1918New in version 3.11.
     1919
     1920Note: 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;
     1922for example, when integer constants are replaced with enumerations, or for interoperability with other systems.
     1923
     1924\subsection{Others}
     1925
     1926While @IntEnum@ is part of the enum module, it would be very simple to implement independently:
     1927\begin{python}
     1928class IntEnum(int, Enum):
     1929    pass
     1930\end{python}
     1931This demonstrates how similar derived enumerations can be defined;
     1932for example a @FloatEnum@ that mixes in float instead of @int@.
     1933
     1934Some rules:
     1935\begin{itemize}
     1936\item
     1937When subclassing @Enum@, mix-in types must appear before @Enum@ itself in the sequence of bases, as in the @IntEnum@ example above.
     1938\item
     1939Mix-in types must be subclassable.
     1940For example, @bool@ and @range@ are not subclassable and will throw an error during Enum creation if used as the mix-in type.
     1941\item
     1942While @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.
     1943This restriction does not apply to mix-ins which only add methods and don't specify another type.
     1944\item
     1945When 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
     1947A 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
     1951Formatted string literals, @str.format()@, and format() will use the enum's @__str__()@ method.
     1952\end{itemize}
     1953Note: 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.
     1958Any other modifications may go in either @__new__()@ or @__init__()@, with @__init__()@ being preferred.
     1959
     1960For 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'])
     1978Coordinate.PY
     1979
     1980>>> print(Coordinate(3))
     1981Coordinate.VY
     1982\end{python}
     1983Warning: 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
     1987Supported @__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.
     1992Supported @_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}
     2007Note: For standard @Enum@ classes the next value chosen is the last value seen incremented by one.
     2008
     2009For @Flag@ classes the next value chosen will be the next highest power-of-two, regardless of the last value seen.
     2010
     2011New in version 3.6: @_missing_@, @_order_@, @_generate_@next@_value_@
     2012
     2013New in version 3.7: @_ignore_@
     2014
     2015To help keep Python 2 / Python 3 code in sync an @_order_@ attribute can be provided.
     2016It 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...
     2024Traceback (most recent call last):
     2025...
     2026TypeError: member order does not match _order_:
     2027  ['RED', 'BLUE', 'GREEN']
     2028  ['RED', 'GREEN', 'BLUE']
     2029\end{python}
     2030Note: 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
     2034Private names are not converted to enum members, but remain normal attributes.
     2035
     2036Changed 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@.
     2041In certain situations, such as writing custom enum behavior, being able to access one member directly from another is useful, and is supported;
     2042however, in order to avoid name clashes between member names and attributes/methods from mixed-in classes, upper-case names are strongly recommended.
     2043
     2044Changed in version 3.5.
     2045
     2046\subsection{Creating members that are mixed with other data types}
     2047
     2048When 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...
     2053MyEnum.example.value        # and hex(11) is...
     205417
     2055\end{python}
     2056
     2057\subsection{\lstinline{Boolean} value of \lstinline{Enum} classes and members}
     2058
     2059Enum classes that are mixed with non-@Enum@ types (such as @int@, @str@, etc.) are evaluated according to the mixed-in type's rules;
     2060otherwise, all members evaluate as @True@.
     2061To make your own enum's boolean evaluation depend on the member's value add the following to your class:
     2062\begin{python}
     2063def __bool__(self):
     2064    return bool(self.value)
     2065\end{python}
     2066Plain @Enum@ classes always evaluate as @True@.
     2067
     2068\subsection{\lstinline{Enum} classes with methods}
     2069
     2070If 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
     2081Iterating 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
     2099Using 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}
     2110the following are true:
     2111\begin{itemize}
     2112\item
     2113single-bit flags are canonical
     2114\item
     2115multi-bit and zero-bit flags are aliases
     2116\item
     2117only 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}
     2122negating 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
     2131names 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
     2137multi-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
     2149membership / containment checking: zero-valued flags are always considered to be contained:
     2150\begin{python}
     2151>>> Color.BLACK in Color.WHITE
     2152True
     2153\end{python}
     2154otherwise, 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
     2157True
     2158
     2159>>> Color.GREEN in Color.PURPLE
     2160False
     2161\end{python}
     2162\end{itemize}
     2163There 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
     2175keeps Flag status and extra bits
     2176\item
     2177extra bits do not show up in iteration
     2178\item
     2179extra bits do show up in repr() and str()
     2180\end{itemize}
     2181\end{itemize}
     2182The 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
     2186Enums have a custom metaclass that affects many aspects of both derived @Enum@ classes and their instances (members).
     2187
     2188\subsection{Enum Classes}
     2189
     2190The @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
     2195Flags 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.
     2196So, 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
     2200The 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
     2205Flag members can be iterated over just like the @Flag@ class, and only the canonical members will be returned.
     2206For 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
     2213Inverting 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}
     2218Flag members have a length corresponding to the number of power-of-two values they contain. For example:
     2219\begin{python}
     2220>>> len(Color.PURPLE)
     22212
     2222\end{python}
     2223
     2224\subsection{Enum Cookbook}
     2225
     2226While @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
     2230In 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
     2233use instances of auto for the value
     2234\item
     2235use instances of object as the value
     2236\item
     2237use a descriptive string as the value
     2238\item
     2239use a tuple as the value and a custom @__new__()@ to replace the tuple with an @int@ value
     2240\end{itemize}
     2241Using 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
     2245Using @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
     2258Using @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}
     2268This 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
     2283Using 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
     2296Using 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}
     2313To 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}
     2322Then 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}
     2338Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
     2339it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
     2340
     2341Warning: Do not call @super().__new__()@, as the lookup-only @__new__@ is the one that is found;
     2342instead, use the data type directly -- e.g.:
     2343\begin{python}
     2344obj = int.__new__(cls, value)
     2345\end{python}
     2346
     2347\subsection{OrderedEnum}
     2348
     2349An 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
     2376True
     2377\end{python}
     2378
     2379\subsection{DuplicateFreeEnum}
     2380
     2381Raises 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...
     2398Traceback (most recent call last):
     2399  ...
     2400ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'
     2401\end{python}
     2402Note: This is a useful example for subclassing Enum to add or change other behaviors as well as disallowing aliases.
     2403If the only desired change is disallowing aliases, the @unique()@ decorator can be used instead.
     2404
     2405\subsection{Planet}
     2406
     2407If @__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
     24309.802652743337129
     2431\end{python}
     2432
     2433\subsection{TimePeriod}
     2434
     2435An 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
     2453While 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
    11412455
    11422456\section{Algebraic Data Type}
  • TabularUnified src/Parser/DeclarationNode.cc

    rbbf2cb1 rf6e8c67  
    8282
    8383DeclarationNode::~DeclarationNode() {
     84        delete name;
     85
    8486//      delete variable.name;
    8587        delete variable.assertions;
     
    99101DeclarationNode * DeclarationNode::clone() const {
    100102        DeclarationNode * newnode = new DeclarationNode;
    101         newnode->set_next( maybeCopy( get_next() ) );
     103        newnode->next = maybeCopy( next );
    102104        newnode->name = name ? new string( *name ) : nullptr;
    103105
    104         newnode->builtin = NoBuiltinType;
    105106        newnode->type = maybeCopy( type );
    106107        newnode->inLine = inLine;
     
    170171
    171172void DeclarationNode::printList( std::ostream & os, int indent ) const {
    172         ParseNode::printList( os, indent );
     173        ParseList::printList( os, indent );
    173174        if ( hasEllipsis ) {
    174175                os << string( indent, ' ' )  << "and a variable number of other arguments" << endl;
     
    433434        DeclarationNode * newnode = new DeclarationNode;
    434435        newnode->type = new TypeData( TypeData::Builtin );
    435         newnode->builtin = bt;
    436         newnode->type->builtintype = newnode->builtin;
     436        newnode->type->builtintype = bt;
    437437        return newnode;
    438438} // DeclarationNode::newBuiltinType
     
    554554} // DeclarationNode::copySpecifiers
    555555
    556 static 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 
    567556DeclarationNode * DeclarationNode::addQualifiers( DeclarationNode * q ) {
    568557        if ( ! q ) { return this; }                                                     // empty qualifier
     
    580569        } // if
    581570
    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 
    599571        checkQualifiers( type, q->type );
     572        BuiltinType const builtin = type->builtintype;
    600573        if ( (builtin == Zero || builtin == One) && q->type->qualifiers.any() && error.length() == 0 ) {
    601574                SemanticWarning( yylloc, Warning::BadQualifiersZeroOne, builtinTypeNames[builtin] );
    602575        } // if
    603         addQualifiersToType( q->type, type );
     576        type = ::addQualifiers( q->type, type );
     577        q->type = nullptr;
    604578
    605579        delete q;
     
    607581} // addQualifiers
    608582
    609 static 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 
    686583DeclarationNode * DeclarationNode::addType( DeclarationNode * o, bool copyattr ) {
    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
     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
    721601        delete o;
    722 
    723602        return this;
    724603}
    725604
    726605DeclarationNode * DeclarationNode::addEnumBase( DeclarationNode * o ) {
    727         if ( o && o->type) {
    728                 type->base= o->type;
     606        if ( o && o->type ) {
     607                type->base = o->type;
    729608        } // if
    730609        delete o;
     
    745624        if ( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS ) {
    746625                if ( variable.assertions ) {
    747                         variable.assertions->appendList( assertions );
     626                        variable.assertions->set_last( assertions );
    748627                } else {
    749628                        variable.assertions = assertions;
     
    756635        case TypeData::Symbolic:
    757636                if ( type->symbolic.assertions ) {
    758                         type->symbolic.assertions->appendList( assertions );
     637                        type->symbolic.assertions->set_last( assertions );
    759638                } else {
    760639                        type->symbolic.assertions = assertions;
     
    810689DeclarationNode * DeclarationNode::setBase( TypeData * newType ) {
    811690        if ( type ) {
    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;
     691                type->setLastBase( newType );
    819692        } else {
    820693                type = newType;
     
    857730                assert( p->type->kind == TypeData::Pointer || p->type->kind == TypeData::Reference );
    858731                if ( 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
     732                        p->type->base = makeNewBase( type );
    873733                        type = nullptr;
    874734                } // if
     
    880740}
    881741
    882 static 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 
    891742DeclarationNode * DeclarationNode::addNewArray( DeclarationNode * a ) {
    892743        if ( ! a ) return this;
    893744        assert( a->type->kind == TypeData::Array );
    894         TypeData * lastArray = findLast( a->type );
    895745        if ( 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
     746                a->type->setLastBase( makeNewBase( type ) );
    909747                type = nullptr;
    910748        } // if
     
    960798DeclarationNode * DeclarationNode::cloneBaseType( DeclarationNode * o, bool copyattr ) {
    961799        if ( ! o ) return nullptr;
    962 
    963800        o->copySpecifiers( this, copyattr );
    964801        if ( 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
     802                o->type = ::cloneBaseType( type, o->type );
    996803        } // if
    997804        return o;
     
    1099906        std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList );
    1100907
    1101         for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
     908        for ( const DeclarationNode * cur = firstNode ; cur ; cur = cur->next ) {
    1102909                try {
    1103910                        bool extracted_named = false;
     
    1167974        std::back_insert_iterator<std::vector<ast::ptr<ast::DeclWithType>>> out( outputList );
    1168975
    1169         for ( const DeclarationNode * cur = firstNode; cur; cur = strict_next( cur ) ) {
     976        for ( const DeclarationNode * cur = firstNode; cur; cur = cur->next ) {
    1170977                try {
    1171978                        ast::Decl * decl = cur->build();
     
    12171024        std::back_insert_iterator<std::vector<ast::ptr<ast::Type>>> out( outputList );
    12181025
    1219         for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
     1026        for ( const DeclarationNode * cur = firstNode ; cur ; cur = cur->next ) {
    12201027                try {
    12211028                        * out++ = cur->buildType();
  • TabularUnified src/Parser/DeclarationNode.h

    rbbf2cb1 rf6e8c67  
    1919
    2020struct TypeData;
    21 class InitializerNode;
    22 
    23 struct DeclarationNode : public ParseNode {
     21struct InitializerNode;
     22
     23struct DeclarationNode final : public ParseList<DeclarationNode> {
    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 
    114110        virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
    115111        virtual void printList( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
     
    129125        DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
    130126
    131         DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }
     127        const std::string * name = nullptr;
    132128
    133129        struct Variable_t {
     
    144140        };
    145141        StaticAssert_t assert;
    146 
    147         BuiltinType builtin = NoBuiltinType;
    148142
    149143        TypeData * type = nullptr;
     
    177171}
    178172
    179 template<typename NodeType>
    180 NodeType * 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 
    187173// This generic buildList is here along side its overloads.
    188174template<typename AstType, typename NodeType,
     
    193179        std::back_insert_iterator<Container<ast::ptr<AstType>, Args...>> out( output );
    194180
    195         for ( NodeType * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
     181        for ( NodeType * cur = firstNode ; cur ; cur = cur->next ) {
    196182                try {
    197183                        AstType * node = dynamic_cast<AstType *>( maybeBuild( cur ) );
  • TabularUnified src/Parser/ExpressionNode.h

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

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

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

    rbbf2cb1 rf6e8c67  
    3333
    3434struct DeclarationNode;
    35 class InitializerNode;
    36 class ExpressionNode;
     35struct InitializerNode;
     36struct ExpressionNode;
    3737struct StatementNode;
    3838
     
    4545extern YYLTYPE yylloc;
    4646
    47 class ParseNode {
    48   public:
    49         ParseNode() {};
    50         virtual ~ParseNode() { delete next; delete name; };
     47struct ParseNode {
     48        ParseNode() {}
     49        virtual ~ParseNode() {}
    5150        virtual ParseNode * clone() const = 0;
    5251
    53         ParseNode * get_next() const { return next; }
    54         ParseNode * set_next( ParseNode * newlink ) { next = newlink; return this; }
     52        virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
    5553
    56         ParseNode * get_last() {
    57                 ParseNode * current;
    58                 for ( current = this; current->get_next() != nullptr; current = current->get_next() );
     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>`!
     60template<typename Next>
     61struct 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;
    5969                return current;
    6070        }
    61         ParseNode * set_last( ParseNode * newlast ) {
    62                 if ( newlast != nullptr ) get_last()->set_next( newlast );
    63                 return this;
     71        Next * set_last( Next * newlast ) {
     72                if ( newlast != nullptr ) get_last()->next = newlast;
     73                return static_cast<Next *>( this );
    6474        }
    6575
    66         virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
    6776        virtual void printList( std::ostream & os, int indent = 0 ) const {
    6877                print( os, indent );
     
    7079        }
    7180
    72         static int indent_by;
    73 
    74         ParseNode * next = nullptr;
    75         const std::string * name = nullptr;
    76         CodeLocation location = yylloc;
    77 }; // ParseNode
     81        Next * next = nullptr;
     82};
    7883
    7984// Must harmonize with OperName.
  • TabularUnified src/Parser/StatementNode.cc

    rbbf2cb1 rf6e8c67  
    5454                StatementNode * nextStmt = new StatementNode(
    5555                        new ast::DeclStmt( decl->location, maybeBuild( decl ) ) );
    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 );
     56                next = nextStmt;
     57                if ( decl->next ) {
     58                        next->next = new StatementNode( decl->next );
     59                        decl->next = nullptr;
    6060                } // if
    6161        } else {
    62                 if ( decl->get_next() ) {
    63                         set_next( new StatementNode( dynamic_cast< DeclarationNode * >( decl->get_next() ) ) );
    64                         decl->set_next( 0 );
     62                if ( decl->next ) {
     63                        next = new StatementNode( decl->next );
     64                        decl->next = nullptr;
    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 = (ClauseNode *)curr->get_next() ) {
    90                 ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr);
     89        for ( ClauseNode * curr = prev; curr != nullptr; curr = curr->next ) {
     90                ClauseNode * node = curr;
    9191                assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
    9292                prev = curr;
    9393        } // for
    94         ClauseNode * node = dynamic_cast< ClauseNode * >(prev);
     94        ClauseNode * node = 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 = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
    335         targetExpr->set_next( nullptr );
     334        ExpressionNode * next = targetExpr->next;
     335        targetExpr->next = nullptr;
    336336        buildMoveList( next, clause->target_args );
    337337
  • TabularUnified src/Parser/StatementNode.h

    rbbf2cb1 rf6e8c67  
    1818#include "ParseNode.h"
    1919
    20 struct StatementNode final : public ParseNode {
     20struct StatementNode final : public ParseList<StatementNode> {
    2121        StatementNode() : stmt( nullptr ) {}
    2222        StatementNode( ast::Stmt * stmt ) : stmt( stmt ) {}
     
    3939}; // StatementNode
    4040
    41 struct ClauseNode final : public ParseNode {
     41struct ClauseNode final : public ParseList<ClauseNode> {
    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     }
    4944
    5045        virtual ClauseNode * clone() const final { assert( false ); return nullptr; }
  • TabularUnified src/Parser/TypeData.cc

    rbbf2cb1 rf6e8c67  
    479479
    480480
     481TypeData * TypeData::getLastBase() {
     482        TypeData * cur = this;
     483        while ( cur->base ) cur = cur->base;
     484        return cur;
     485}
     486
     487void TypeData::setLastBase( TypeData * newBase ) {
     488        getLastBase()->base = newBase;
     489}
     490
     491// Takes ownership of src.
     492static 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.
     505TypeData * 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.
     524static 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.
     607TypeData * 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.
     632TypeData * 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
     659TypeData * 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
    481677void buildForall(
    482678                const DeclarationNode * firstNode,
     
    494690        for ( auto i = outputList.begin() ;
    495691                        i != outputList.end() ;
    496                         ++i, n = (DeclarationNode*)n->get_next() ) {
     692                        ++i, n = n->next ) {
    497693                // Only the object type class adds additional assertions.
    498694                if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
     
    639835        for ( auto i = outputForall.begin() ;
    640836                        i != outputForall.end() ;
    641                         ++i, n = (DeclarationNode*)n->get_next() ) {
     837                        ++i, n = n->next ) {
    642838                // Only the object type class adds additional assertions.
    643839                if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
     
    12721468        auto members = ret->members.begin();
    12731469        ret->hide = td->enumeration.hiding == EnumHiding::Hide ? ast::EnumDecl::EnumHiding::Hide : ast::EnumDecl::EnumHiding::Visible;
    1274         for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ), ++members ) {
     1470        for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = cur->next, ++members ) {
    12751471                if ( cur->enumInLine ) {
    12761472                        // Do Nothing
     
    15001696        assert( ! function.params );
    15011697        // loop over declaration first as it is easier to spot errors
    1502         for ( DeclarationNode * decl = function.oldDeclList; decl != nullptr; decl = dynamic_cast< DeclarationNode * >( decl->get_next() ) ) {
     1698        for ( DeclarationNode * decl = function.oldDeclList; decl != nullptr; decl = decl->next ) {
    15031699                // scan ALL parameter names for each declaration name to check for duplicates
    1504                 for ( DeclarationNode * param = function.idList; param != nullptr; param = dynamic_cast< DeclarationNode * >( param->get_next() ) ) {
     1700                for ( DeclarationNode * param = function.idList; param != nullptr; param = param->next ) {
    15051701                        if ( *decl->name == *param->name ) {
    15061702                                // type set => parameter name already transformed by a declaration names so there is a duplicate
     
    15241720        //    rtb( a, b, c ) const char * b; {} => int rtn( int a, const char * b, int c ) {}
    15251721
    1526         for ( DeclarationNode * param = function.idList; param != nullptr; param = dynamic_cast< DeclarationNode * >( param->get_next() ) ) {
     1722        for ( DeclarationNode * param = function.idList; param != nullptr; param = param->next ) {
    15271723                if ( ! param->type ) {                                                  // generate type int for empty parameter type
    15281724                        param->type = new TypeData( TypeData::Basic );
  • TabularUnified src/Parser/TypeData.h

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

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

    rbbf2cb1 rf6e8c67  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Feb 23 18:25:46 2024
    13 // Update Count     : 6484
     12// Last Modified On : Mon Mar  4 08:44:25 2024
     13// Update Count     : 6562
    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 = dynamic_cast<DeclarationNode *>( declList->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) {
     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 ) {
    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 = (DeclarationNode *)iter->get_next() ) {
     141        for ( DeclarationNode *iter = declaration ; iter != nullptr ; iter = iter->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 = (DeclarationNode *)iter->get_next() ) {
     148        for ( DeclarationNode *iter = declaration ; iter != nullptr ; iter = iter->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 = (DeclarationNode *)iter->get_next() ) {
     155        for ( DeclarationNode * iter = declaration ; iter != nullptr ; iter = iter->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 ELLIPSIS                                                                                 // ...
     391%token ATTR 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                 if_statement
     435%type<stmt> selection_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_ellipsis_list_opt
     502%type<decl> cfa_parameter_declaration cfa_parameter_list cfa_parameter_list_ellipsis_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_type_list_opt
     510%type<decl> parameter_declaration parameter_list parameter_list_ellipsis_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
     532%type<expr> type_parameters_opt type_list array_type_list // array_dimension_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
    12481254selection_statement:
    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; }
     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 ) ) ); }
    12531260        | SWITCH '(' comma_expression ')' case_clause
    12541261                { $$ = new StatementNode( build_switch( yylloc, true, $3, $5 ) ); }
     
    12741281        | CHOOSE '(' comma_expression ')' '{' error '}'         // CFA, invalid syntax rule
    12751282                { SemanticError( yylloc, "syntax error, declarations can only appear before the list of case clauses." ); $$ = nullptr; }
    1276         ;
    1277 
    1278 if_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 ) ) ); }
    12841283        ;
    12851284
     
    18971896declaration_list:
    18981897        declaration
    1899         | declaration_list declaration          { $$ = $1->appendList( $2 ); }
     1898        | declaration_list declaration
     1899                { $$ = $1->set_last( $2 ); }
    19001900        ;
    19011901
     
    19101910                { $$ = $1; }
    19111911        | KR_parameter_list c_declaration ';'
    1912                 { $$ = $1->appendList( $2 ); }
     1912                { $$ = $1->set_last( $2 ); }
    19131913        ;
    19141914
     
    19681968                { $$ = $2->addQualifiers( $1 )->addInitializer( $3 ); }
    19691969        | cfa_variable_declaration pop ',' push identifier_or_type_name initializer_opt
    1970                 { $$ = $1->appendList( $1->cloneType( $5 )->addInitializer( $6 ) ); }
     1970                { $$ = $1->set_last( $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_ellipsis_list_opt pop ')'
     1992        | cfa_function_declaration ',' identifier_or_type_name '(' push cfa_parameter_list_ellipsis_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->appendList( DeclarationNode::newFunction( $3, ret, $6, nullptr ) );
     1997                        $$ = $1->set_last( DeclarationNode::newFunction( $3, ret, $6, nullptr ) );
    19981998                }
    19991999        ;
    20002000
    20012001cfa_function_specifier:                                                                 // CFA
    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
     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
    20172009                // identifier_or_type_name must be broken apart because of the sequence:
    20182010                //
    2019                 //   '[' ']' identifier_or_type_name '(' cfa_parameter_ellipsis_list_opt ')'
     2011                //   '[' ']' identifier_or_type_name '(' cfa_parameter_list_ellipsis_opt ')'
    20202012                //   '[' ']' type_specifier
    20212013                //
    20222014                // type_specifier can resolve to just TYPEDEFname (e.g., typedef int T; int f( T );). Therefore this must be
    20232015                // flattened to allow lookahead to the '(' without having to reduce identifier_or_type_name.
    2024         cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
     2016        | cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
    20252017                // To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator).
    20262018                { $$ = DeclarationNode::newFunction( $2, $1, $5, nullptr )->addQualifiers( $8 ); }
    2027         | cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
     2019        | cfa_function_return identifier_or_type_name '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
    20282020                { $$ = DeclarationNode::newFunction( $2, $1, $5, nullptr )->addQualifiers( $8 ); }
    20292021        ;
     
    20322024        '[' push cfa_parameter_list pop ']'
    20332025                { $$ = DeclarationNode::newTuple( $3 ); }
    2034         | '[' push cfa_parameter_list pop ',' push cfa_abstract_parameter_list pop ']'
     2026        | '[' push cfa_parameter_list ',' cfa_abstract_parameter_list pop ']'
    20352027                // To obtain LR(1 ), the last cfa_abstract_parameter_list is added into this flattened rule to lookahead to the ']'.
    2036                 { $$ = DeclarationNode::newTuple( $3->appendList( $7 ) ); }
     2028                { $$ = DeclarationNode::newTuple( $3->set_last( $5 ) ); }
    20372029        ;
    20382030
     
    20482040                        $$ = $2->addTypedef();
    20492041                }
    2050         | cfa_typedef_declaration pop ',' push identifier
    2051                 {
    2052                         typedefTable.addToEnclosingScope( *$5, TYPEDEFname, "cfa_typedef_declaration 3" );
    2053                         $$ = $1->appendList( $1->cloneType( $5 ) );
     2042        | cfa_typedef_declaration ',' identifier
     2043                {
     2044                        typedefTable.addToEnclosingScope( *$3, TYPEDEFname, "cfa_typedef_declaration 3" );
     2045                        $$ = $1->set_last( $1->cloneType( $3 ) );
    20542046                }
    20552047        ;
     
    20692061                {
    20702062                        typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "typedef_declaration 2" );
    2071                         $$ = $1->appendList( $1->cloneBaseType( $3 )->addTypedef() );
     2063                        $$ = $1->set_last( $1->cloneBaseType( $3 )->addTypedef() );
    20722064                }
    20732065        | type_qualifier_list TYPEDEF type_specifier declarator // remaining OBSOLESCENT (see 2 )
     
    21232115
    21242116        | declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt
    2125                 { $$ = $1->appendList( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) ); }
     2117                { $$ = $1->set_last( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) ); }
    21262118        ;
    21272119
     
    25872579                { $$ = nullptr; }
    25882580        | field_declaration_list_opt field_declaration
    2589                 { $$ = $1 ? $1->appendList( $2 ) : $2; }
     2581                { $$ = $1 ? $1->set_last( $2 ) : $2; }
    25902582        ;
    25912583
     
    26352627        | field_declarator
    26362628        | field_declaring_list_opt ',' attribute_list_opt field_declarator
    2637                 { $$ = $1->appendList( $4->addQualifiers( $3 ) ); }
     2629                { $$ = $1->set_last( $4->addQualifiers( $3 ) ); }
    26382630        ;
    26392631
     
    26572649        | field_abstract
    26582650        | field_abstract_list_opt ',' attribute_list_opt field_abstract
    2659                 { $$ = $1->appendList( $4->addQualifiers( $3 ) ); }
     2651                { $$ = $1->set_last( $4->addQualifiers( $3 ) ); }
    26602652        ;
    26612653
     
    26702662                { $$ = $1->addName( $2 ); }
    26712663        | cfa_field_declaring_list ',' identifier_or_type_name
    2672                 { $$ = $1->appendList( $1->cloneType( $3 ) ); }
     2664                { $$ = $1->set_last( $1->cloneType( $3 ) ); }
    26732665        ;
    26742666
     
    26772669        cfa_abstract_declarator_tuple
    26782670        | cfa_field_abstract_list ','
    2679                 { $$ = $1->appendList( $1->cloneType( 0 ) ); }
     2671                { $$ = $1->set_last( $1->cloneType( 0 ) ); }
    26802672        ;
    26812673
     
    26902682                { $$ = $2; }
    26912683        ;
     2684
     2685// ***********
     2686// Enumeration
     2687// ***********
    26922688
    26932689enum_type:
     
    27192715        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
    27202716                {
    2721                         if ( $3 && ($3->storageClasses.any() || $3->type->qualifiers.val != 0 )) {
     2717                        if ( $3 && ($3->storageClasses.any() || $3->type->qualifiers.val != 0) ) {
    27222718                                SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
    27232719                        }
     
    27692765                { $$ = DeclarationNode::newEnumInLine( *$2->type->symbolic.name ); }
    27702766        | enumerator_list ',' visible_hide_opt identifier_or_type_name enumerator_value_opt
    2771                 { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); }
     2767                { $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); }
    27722768        | enumerator_list ',' INLINE type_name enumerator_value_opt
    2773                 { $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); }
     2769                { $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); }
    27742770        ;
    27752771
     
    27892785        ;
    27902786
    2791 cfa_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 
    2806 cfa_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 
    2818 cfa_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 
    2824 parameter_type_list_opt:
     2787// *******************
     2788// Function parameters
     2789// *******************
     2790
     2791parameter_list_ellipsis_opt:
    28252792        // empty
    28262793                { $$ = nullptr; }
     
    28332800
    28342801parameter_list:                                                                                 // abstract + real
    2835         abstract_parameter_declaration
    2836         | parameter_declaration
     2802        parameter_declaration
     2803        | abstract_parameter_declaration
     2804        | parameter_list ',' parameter_declaration
     2805                { $$ = $1->set_last( $3 ); }
    28372806        | parameter_list ',' abstract_parameter_declaration
    2838                 { $$ = $1->appendList( $3 ); }
    2839         | parameter_list ',' parameter_declaration
    2840                 { $$ = $1->appendList( $3 ); }
     2807                { $$ = $1->set_last( $3 ); }
     2808        ;
     2809
     2810cfa_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
     2825cfa_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
     2837cfa_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 ); }
    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
     2846parameter_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
     2854abstract_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        ;
    28452860
    28462861cfa_parameter_declaration:                                                              // CFA, new & old style parameter declaration
     
    28662881        ;
    28672882
    2868 parameter_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 
    2876 abstract_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->appendList( DeclarationNode::newName( $3 ) ); }
     2891                { $$ = $1->set_last( DeclarationNode::newName( $3 ) ); }
    28922892        ;
    28932893
     
    29902990        type_parameter
    29912991        | type_parameter_list ',' type_parameter
    2992                 { $$ = $1->appendList( $3 ); }
     2992                { $$ = $1->set_last( $3 ); }
    29932993        ;
    29942994
     
    30633063        assertion
    30643064        | assertion_list assertion
    3065                 { $$ = $1->appendList( $2 ); }
     3065                { $$ = $1->set_last( $2 ); }
    30663066        ;
    30673067
     
    30913091                { $$ = $3->addQualifiers( $1 ); }
    30923092        | type_declaring_list ',' type_declarator
    3093                 { $$ = $1->appendList( $3->copySpecifiers( $1 ) ); }
     3093                { $$ = $1->set_last( $3->copySpecifiers( $1 ) ); }
    30943094        ;
    30953095
     
    31343134        trait_declaration
    31353135        | trait_declaration_list pop push trait_declaration
    3136                 { $$ = $1->appendList( $4 ); }
     3136                { $$ = $1->set_last( $4 ); }
    31373137        ;
    31383138
     
    31463146        | cfa_function_specifier
    31473147        | cfa_trait_declaring_list pop ',' push identifier_or_type_name
    3148                 { $$ = $1->appendList( $1->cloneType( $5 ) ); }
     3148                { $$ = $1->set_last( $1->cloneType( $5 ) ); }
    31493149        ;
    31503150
     
    31533153                { $$ = $2->addType( $1 ); }
    31543154        | trait_declaring_list pop ',' push declarator
    3155                 { $$ = $1->appendList( $1->cloneBaseType( $5 ) ); }
     3155                { $$ = $1->set_last( $1->cloneBaseType( $5 ) ); }
    31563156        ;
    31573157
     
    31613161        // empty, input file
    31623162        | external_definition_list
    3163                 { parseTree = parseTree ? parseTree->appendList( $1 ) : $1;     }
     3163                { parseTree = parseTree ? parseTree->set_last( $1 ) : $1;       }
    31643164        ;
    31653165
     
    31683168                { $$ = $2; }
    31693169        | external_definition_list push external_definition pop
    3170                 { $$ = $1 ? $1->appendList( $3 ) : $3; }
     3170                { $$ = $1 ? $1->set_last( $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; }
    33973401        ;
    33983402
     
    34993503
    35003504variable_function:
    3501         '(' variable_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3505        '(' variable_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    35023506                { $$ = $2->addParamList( $5 ); }
    3503         | '(' attribute_list variable_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3507        | '(' attribute_list variable_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    35043508                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    35053509        | '(' variable_function ')'                                                     // redundant parenthesis
     
    35223526
    35233527function_no_ptr:
    3524         paren_identifier '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3528        paren_identifier '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    35253529                { $$ = $1->addParamList( $3 ); }
    3526         | '(' function_ptr ')' '(' parameter_type_list_opt ')'
     3530        | '(' function_ptr ')' '(' parameter_list_ellipsis_opt ')'
    35273531                { $$ = $2->addParamList( $5 ); }
    3528         | '(' attribute_list function_ptr ')' '(' parameter_type_list_opt ')'
     3532        | '(' attribute_list function_ptr ')' '(' parameter_list_ellipsis_opt ')'
    35293533                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    35303534        | '(' function_no_ptr ')'                                                       // redundant parenthesis
     
    35763580        paren_identifier '(' identifier_list ')'                        // function_declarator handles empty parameter
    35773581                { $$ = $1->addIdList( $3 ); }
    3578         | '(' KR_function_ptr ')' '(' parameter_type_list_opt ')'
     3582        | '(' KR_function_ptr ')' '(' parameter_list_ellipsis_opt ')'
    35793583                { $$ = $2->addParamList( $5 ); }
    3580         | '(' attribute_list KR_function_ptr ')' '(' parameter_type_list_opt ')'
     3584        | '(' attribute_list KR_function_ptr ')' '(' parameter_list_ellipsis_opt ')'
    35813585                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    35823586        | '(' KR_function_no_ptr ')'                                            // redundant parenthesis
     
    36683672
    36693673variable_type_function:
    3670         '(' variable_type_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3674        '(' variable_type_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    36713675                { $$ = $2->addParamList( $5 ); }
    3672         | '(' attribute_list variable_type_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3676        | '(' attribute_list variable_type_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    36733677                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    36743678        | '(' variable_type_function ')'                                        // redundant parenthesis
     
    36913695
    36923696function_type_no_ptr:
    3693         paren_type '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3697        paren_type '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    36943698                { $$ = $1->addParamList( $3 ); }
    3695         | '(' function_type_ptr ')' '(' parameter_type_list_opt ')'
     3699        | '(' function_type_ptr ')' '(' parameter_list_ellipsis_opt ')'
    36963700                { $$ = $2->addParamList( $5 ); }
    3697         | '(' attribute_list function_type_ptr ')' '(' parameter_type_list_opt ')'
     3701        | '(' attribute_list function_type_ptr ')' '(' parameter_list_ellipsis_opt ')'
    36983702                { $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
    36993703        | '(' function_type_no_ptr ')'                                          // redundant parenthesis
     
    37383742                { $$ = $1->addQualifiers( $2 ); }
    37393743        | '&' MUTEX paren_identifier attribute_list_opt
    3740                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
     3744                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ),
     3745                                                                                                                        OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37413746        | identifier_parameter_ptr
    37423747        | identifier_parameter_array attribute_list_opt
     
    37673772
    37683773identifier_parameter_function:
    3769         paren_identifier '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3774        paren_identifier '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    37703775                { $$ = $1->addParamList( $3 ); }
    3771         | '(' identifier_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3776        | '(' identifier_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    37723777                { $$ = $2->addParamList( $5 ); }
    37733778        | '(' identifier_parameter_function ')'                         // redundant parenthesis
     
    37883793                { $$ = $1->addQualifiers( $2 ); }
    37893794        | '&' MUTEX typedef_name attribute_list_opt
    3790                 { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
     3795                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ),
     3796                                                                                                                        OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    37913797        | type_parameter_ptr
    37923798        | type_parameter_array attribute_list_opt
     
    38203826
    38213827type_parameter_function:
    3822         typedef_name '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3828        typedef_name '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    38233829                { $$ = $1->addParamList( $3 ); }
    3824         | '(' type_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3830        | '(' type_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    38253831                { $$ = $2->addParamList( $5 ); }
    38263832        ;
     
    38703876
    38713877abstract_function:
    3872         '(' parameter_type_list_opt ')'                 // empty parameter list OBSOLESCENT (see 3)
     3878        '(' parameter_list_ellipsis_opt ')'                     // empty parameter list OBSOLESCENT (see 3)
    38733879                { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
    3874         | '(' abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     3880        | '(' abstract_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    38753881                { $$ = $2->addParamList( $5 ); }
    38763882        | '(' abstract_function ')'                                                     // redundant parenthesis
     
    38883894                { $$ = DeclarationNode::newArray( $3, nullptr, false )->addArray( DeclarationNode::newArray( $6, nullptr, false ) ); }
    38893895                // { 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
    38903900        | '[' push array_type_list pop ']'                                      // CFA
    38913901                { $$ = DeclarationNode::newArray( $3, nullptr, false ); }
    38923902        | multi_array_dimension
    38933903        ;
     3904
     3905// array_dimension_list:
     3906//      assignment_expression
     3907//      | array_dimension_list ',' assignment_expression
     3908//      ;
    38943909
    38953910array_type_list:
     
    39934008
    39944009abstract_parameter_function:
    3995         '(' parameter_type_list_opt ')'                 // empty parameter list OBSOLESCENT (see 3)
     4010        '(' parameter_list_ellipsis_opt ')'                     // empty parameter list OBSOLESCENT (see 3)
    39964011                { $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
    3997         | '(' abstract_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     4012        | '(' abstract_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    39984013                { $$ = $2->addParamList( $5 ); }
    39994014        | '(' abstract_parameter_function ')'                           // redundant parenthesis
     
    40724087
    40734088variable_abstract_function:
    4074         '(' variable_abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
     4089        '(' variable_abstract_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
    40754090                { $$ = $2->addParamList( $5 ); }
    40764091        | '(' variable_abstract_function ')'                            // redundant parenthesis
     
    41584173//
    41594174//              cfa_abstract_tuple identifier_or_type_name
    4160 //              '[' cfa_parameter_list ']' identifier_or_type_name '(' cfa_parameter_ellipsis_list_opt ')'
     4175//              '[' cfa_parameter_list ']' identifier_or_type_name '(' cfa_parameter_list_ellipsis_opt ')'
    41614176//
    41624177// since a function return type can be syntactically identical to a tuple type:
     
    42244239
    42254240cfa_abstract_function:                                                                  // CFA
    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 ')'
     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 ')'
    42294244                { $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); }
    4230         | cfa_function_return '(' push cfa_parameter_ellipsis_list_opt pop ')'
     4245        | cfa_function_return '(' push cfa_parameter_list_ellipsis_opt pop ')'
    42314246                { $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); }
    42324247        ;
  • TabularUnified src/ResolvExpr/Resolver.cc

    rbbf2cb1 rf6e8c67  
    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;
    414415
    415416        void beginScope() { managedTypes.beginScope(); }
     
    581582}
    582583
     584bool 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
    583595const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) {
    584596        // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
     
    615627                        // this object in visitor pass, thus disabling CtorInit codegen.
    616628                        // this happens on aggregate members and function parameters.
    617                         if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) {
     629                        if ( shouldGenCtorInit( mutDecl ) ) {
    618630                                // constructed objects cannot be designated
    619631                                if ( InitTweak::isDesignated( mutDecl->init ) ) {
Note: See TracChangeset for help on using the changeset viewer.