Index: doc/theses/jiada_liang_MMath/relatedwork.tex
===================================================================
--- doc/theses/jiada_liang_MMath/relatedwork.tex	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ doc/theses/jiada_liang_MMath/relatedwork.tex	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -2,18 +2,14 @@
 \label{s:RelatedWork}
 
-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.
+In general, an \Newterm{algebraic data type} (ADT) is a composite type, \ie, a type formed by combining other types.
+Three common classes of algebraic types are \Newterm{array type}, \ie homogeneous types, \Newterm{product type}, \ie heterogeneous tuples and records (structures), and \Newterm{sum type}, \ie tagged product-types (unions).
+Enumerated types are a special case of product/sum types with non-mutable fields, \ie initialized (constructed) once at the type's declaration, possible restricted to compile-time initialization.
+Values of algebraic types are access by subscripting, field qualification, or type (pattern) matching.
+
+Enumeration types exist in many popular programming languages, both past and present, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, Haskell~\cite{Haskell} \CC, Go~\cite{Go}, Java~\cite{Java}, Modula-3~\cite{Modula-3}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}.
 Among theses languages, there are a large set of overlapping features, but each language has its own unique extensions and restrictions.
 
-
 \section{Pascal}
-
-\lstnewenvironment{pascal}[1][]{% necessary
-\lstset{
-language=pascal,
-escapechar=\$,							% LaTeX escape in code
-moredelim=**[is][\color{red}]{@}{@},	% red highlighting @...@
-}% lstset
-\lstset{#1}% necessary
-}{}
+\lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
 
 Classic Pascal has the \lstinline[language=pascal]{const} declaration binding a name to a constant literal/expression.
@@ -22,6 +18,7 @@
 		 PI = 3.14159;   Plus = '+';   Fred = 'Fred';
 \end{pascal}
-The enumerator type is inferred from the constant-expression type.
-There is no notion of an ordered set, modulo the \lstinline[language=pascal]{set of} type.
+Here, there is no enumeration because there is no specific type (pseudo enumeration).
+Hence, there is no notion of a (possibly ordered) set, modulo the \lstinline[language=pascal]{set of} type.
+The type of each constant name (enumerator) is inferred from the constant-expression type.
 
 Free Pascal~\cite[\S~3.1.1]{FreePascal} is a modern, object-oriented version of classic Pascal, with a C-style enumeration type.
@@ -42,20 +39,11 @@
 
 \section{Ada}
-
-\lstnewenvironment{ada}[1][]{% necessary
-\lstset{
-language=[2005]Ada,
-escapechar=\$,							% LaTeX escape in code
-moredelim=**[is][\color{red}]{@}{@},	% red highlighting @...@
-literate={'}{\ttfamily'\!}1				% remove '-' literate as comment
-}% lstset
-\lstset{#1}% necessary
-}{}
+\lstnewenvironment{ada}[1][]{\lstset{language=[2005]Ada,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},literate={'}{\ttfamily'\!}1}\lstset{#1}}{}
 
 An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
 \begin{ada}
-type RGB is ( @Red@, @Green@, Blue ); -- 3 literals (enumerators)
+type RGB is ( Red, Green, Blue ); -- 3 literals (enumerators)
 \end{ada}
-No other enumerators are assignable to objects of this type.
+Object initialization and assignment are restricted to the enumerators of this type.
 Enumerators 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.
 To explicitly set enumerator values, \emph{all} enumerators must be set in \emph{ascending} order, \ie there is no auto-initialization.
@@ -68,8 +56,8 @@
 (0, 10, RED)  (1, 20, GREEN)  (2, 30, BLUE) 
 \end{ada}
+Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same, \eg @Red@ and @RED@ (a questionable design decision).
 
 Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope.
-Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same name (a questionable design decision).
-The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relation is given implicitly by the sequence of enumerators, which is always ascending.
+The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of enumerators, which is always ascending.
 
 Ada enumerators are overloadable.
@@ -136,29 +124,21 @@
 \begin{ada}
 type Operator is ( '+', '-', '*', '/' );
-Op : Operator;
 \end{ada}
 which is syntactic sugar for the label and not character literals from the predefined type @Character@.
-The purpose is readability using character literals rather than names.
+The purpose is strictly readability using character literals rather than names.
 \begin{ada}
-Op := '+';
-case Op is                    -- all enumerators must appear
-	when '+' => ... ;
-	when '-' => ... ;
-	when '*' => ... ;
-	when '/' => ... ;
-end case;
+Op : Operator := '+';
+if Op = '+' or else Op = '-' then ... ;
+elsif Op = '*' or else Op = '/' then ... ; end if;
 \end{ada}
-Arrays of character enumerators can be treated as strings.
+Interestingly, arrays of character enumerators can be treated as strings.
 \begin{ada}
 Ops : array( 0..3 ) of Operator;
 Ops := @"+-*/"@;            -- string assignment to array elements
 Ops := @"+-" & "*/"@;   -- string concatenation and assignment
-for Op of Ops loop
-	Put_Line( Operator'Image( Op ) );
-end loop;
 \end{ada}
 Ada's @Character@ type is defined as a character enumeration across all Latin-1 characters.
 
-Ada's boolean type is defined as a special enumeration, which can be used in conditions.
+Ada's boolean type is also a special enumeration, which can be used in conditions.
 \begin{ada}
 type Boolean is (False, True); -- False / True not keywords
@@ -177,5 +157,5 @@
 Hence, the ordering of the enumerators is crucial to provide the necessary ranges.
 
-An enumeration type can be used in the Ada \lstinline[language=ada]{case} (switch) and iterating constructs.
+An enumeration type can be used in the Ada \lstinline[language=ada]{case} (all enumerators must appear or a default) or iterating constructs.
 \begin{cquote}
 \lstDeleteShortInline@
@@ -233,13 +213,5 @@
 \section{\CC}
 \label{s:C++RelatedWork}
-
-\lstnewenvironment{c++}[1][]{% necessary
-\lstset{
-language=[GNU]C++,
-escapechar=\$,							% LaTeX escape in code
-moredelim=**[is][\color{red}]{@}{@},	% red highlighting @...@
-}% lstset
-\lstset{#1}% necessary
-}{}
+\lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
 
 \CC is largely backwards compatible with C, so it inherited C's enumerations.
@@ -288,5 +260,5 @@
 enum class E { A, B, C };
 E e = @E::@A;	 						$\C{// qualified enumerator}$
-e = B;	 								$\C{// B not in scope}$
+e = B;	 								$\C{// error: B not in scope}$
 \end{c++}
 \CC{20} supports explicit unscoping with a \lstinline[language=c++]{using enum} declaration.
@@ -303,40 +275,35 @@
 enum class srgb @: signed char@ { Red = -1, Green = 0, Blue = 1 };
 \end{c++}
-There is no implicit conversion from the \lstinline[language=c++]{enum class} type and to its type.
+There is no implicit conversion from the \lstinline[language=c++]{enum class} type to its declared type.
 \begin{c++}
 rgb crgb = rgb::Red;
-char ch = rgb::Red;   ch = crgb;		$\C{// disallowed}$
+char ch = rgb::Red;   ch = crgb;		$\C{// error}$
 \end{c++}
-Finally, there is no mechanism to iterate through an enumeration nor use the enumeration type to declare an array dimension.
+Finally, enumerations can be used in the @switch@ statement but there is no mechanism to iterate through an enumeration.
+An enumeration type cannot declare an array dimension but can be used as a subscript.
+There is no mechanism to subtype or inherit from enumerations.
 
 
 \section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE
-
-\lstnewenvironment{csharp}[1][]{% necessary
-\lstset{
-language=[Sharp]C,
-escapechar=\$,							% LaTeX escape in code
-moredelim=**[is][\color{red}]{@}{@},	% red highlighting @...@
-}% lstset
-\lstset{#1}% necessary
-}{}
+\label{s:Csharp}
+\lstnewenvironment{csharp}[1][]{\lstset{language=[Sharp]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
 
 % https://www.tutorialsteacher.com/codeeditor?cid=cs-mk8Ojx
 
-\Csharp is a dynamically-typed programming-language with a scoped, integral enumeration-type similar to C/\CC enumeration.
+\Csharp is a dynamically-typed programming-language with a scoped, integral enumeration-type similar to the C/\CC enumeration.
 \begin{csharp}
-enum Weekday : byte { Monday, Tuesday, Wednesday, Thursday@ = 10@, Friday, Saturday, Sunday@,@ };
+enum Weekday : byte { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun@,@ };
 \end{csharp}
-The default underlying type is @int@, with auto-incrementing, implicit/explicit initialization, terminator comma, and optional integral typing (default @int@)
+The default underlying type is @int@, with auto-incrementing, implicit/explicit initialization, terminator comma, and optional integral typing (default @int@).
 A method cannot be defined in an enumeration type.
 As 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.
 \begin{csharp}
-int day = (int)Weekday.Friday;			$\C{// day == 10}$
-Weekday weekday = (Weekdays)42;			$\C{// weekday == 42}$
-Console.WriteLine( Weekday.Friday );	$\C{// print Friday}$
-string mon = Weekday.Monday.ToString();
+int day = (int)Weekday.Fri;		$\C{// day == 10}$
+Weekday weekday = (Weekdays)42;		$\C{// weekday == 42, logically invalid}$
+Console.WriteLine( Weekday.Fri ); $\C{// print Fri}$
+string mon = Weekday.Mon.ToString(); $\C{// mon == "Mon"}$
 \end{csharp}
 
-The @Enum.GetValues@ pseudo-method retrieves an array of the enumeration constants for looping over an enumeration type or variable.
+The @Enum.GetValues@ pseudo-method retrieves an array of the enumeration constants for looping over an enumeration type or variable (expensive operation).
 \begin{csharp}
 foreach ( Weekday constant in @Enum.GetValues@( typeof(Weekday) ) ) {
@@ -348,35 +315,81 @@
 \begin{csharp}
 @[Flags]@ public enum Weekday {
-	None = 0x0, Monday = 0x1, Tuesday = 0x2, Wednesday = 0x4,
-	Thursday = 0x8, Friday = 0x10, Saturday = 0x20, Sunday = 0x40,
-	Weekend = @Saturday | Sunday@,
-	Weekdays = @Monday | Tuesday | Wednesday | Thursday | Friday@
-}
-Weekday meetings = @Weekday.Monday | Weekday.Wednesday@; // 0x5
+	None = 0x0, Mon = 0x1, Tue = 0x2, Wed = 0x4,
+	Thu = 0x8, Fri = 0x10, Sat = 0x20, Sun = 0x40,
+	Weekend = @Sat | Sun@,
+	Weekdays = @Mon | Tue | Wed | Thu | Fri@
+}
+Weekday meetings = @Weekday.Mon | Weekday.Wed@; // 0x5
 \end{csharp}
 
-\Csharp supports an enumeration class to embed enumeration operations, where the enumerators are objects.
+\VRef[Figure]{CsharpFreeVersusClass} shows an enumeration with free routines for manipulation, and embedding the enumeration and operations into an enumeration class.
+The key observation is that an enumeration class is just a structuring mechanism without any additional semantics.
+
+% https://learn.microsoft.com/en-us/dotnet/api/system.enum?view=net-8.0
+
+\begin{figure}
+\centering
+\lstDeleteShortInline@
+\begin{tabular}{@{}l|l@{}}
+\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
+\hline
 \begin{csharp}
-public class PaymentType : Enumeration {
-    public static readonly PaymentType DebitCard = new PaymentType(0);
-    public static readonly PaymentType CreditCard = new PaymentType(1);
-    private PaymentType(int value, [CallerMemberName] string name = null) : base(value, name) { }
+public class Program {
+
+	enum Weekday {
+		Mon, Tue, Wed, Thu, Fri, Sat, Sun };
+
+	static bool isWeekday( Weekday wd ) {
+		return wd <= Weekday.Fri;
+	}
+	static bool isWeekend( Weekday wd ) {
+		return Weekday.Sat <= wd;
+	}
+
+
+	public static void Main() {
+		Weekday day = Weekday.Sat;
+
+		Console.WriteLine( isWeekday( day ) );
+		Console.WriteLine( isWeekend( day ) );
+	}
 }
 \end{csharp}
-Find a meaningful example and test it.
+&
+\begin{csharp}
+public class Program {
+	public @class@ WeekDay : Enumeration {
+		public enum Day {
+				Mon, Tue, Wed, Thu, Fri, Sat, Sun };
+		public enum Day2 : Day {
+				XXX, YYY };
+		Day day;
+		public bool isWeekday() {
+			return day <= Day.Fri;
+		}
+		public bool isWeekend() {
+			return day > Day.Fri;
+		}
+		public WeekDay( Day d ) { day = d; }
+	}
+	public static void Main() {
+		WeekDay cday = new
+				WeekDay( WeekDay.Day.Sat );
+		Console.WriteLine( cday.isWeekday() );
+		Console.WriteLine( cday.isWeekend() );
+	}
+}
+\end{csharp}
+\end{tabular}
+\lstMakeShortInline@
+\caption{\Csharp: Free Routine Versus Class Enumeration}
+\label{CsharpFreeVersusClass}
+\end{figure}
 
 
 \section{Golang}
-
-\lstnewenvironment{Go}[1][]{% necessary
-\lstset{
-language=Go,
-escapechar=\$,							% LaTeX escape in code
-moredelim=**[is][\color{red}]{@}{@},	% red highlighting @...@
-}% lstset
-\lstset{#1}% necessary
-}{}
-
-The Golang enumeration is similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
+\lstnewenvironment{Go}[1][]{\lstset{language=Go,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+
+Golang provides pseudo-enumeration similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
 \begin{Go}
 const ( R = 0; G; B )					$\C{// implicit: 0 0 0}$
@@ -401,392 +414,447 @@
 Auto-incrementing stops after an explicit initialization.
 \begin{Go}
-const ( Monday = iota; Tuesday; Wednesday; // 0, 1, 2
-	 @Thursday = 10@; Friday; Saturday; Sunday ) // 10, 10, 10, 10
+const ( Mon = iota; Tue; Wed; // 0, 1, 2
+	 @Thu = 10@; Fri; Sat; Sun ) // 10, 10, 10, 10
 \end{Go}
 Auto-incrementing can be restarted with an expression containing \emph{one} \lstinline[language=Go]{iota}.
 \begin{Go}
 const ( V1 = iota; V2; @V3 = 7;@ V4 = @iota@; V5 ) // 0 1 7 3 4
-const ( Monday = iota; Tuesday; Wednesday; // 0, 1, 2
-	 @Thursday = 10;@ Friday = @iota - Wednesday + Thursday - 1@; Saturday; Sunday ) // 10, 11, 12, 13
+const ( Mon = iota; Tue; Wed; // 0, 1, 2
+	 @Thu = 10;@ Fri = @iota - Wed + Thu - 1@; Sat; Sun ) // 10, 11, 12, 13
 \end{Go}
 Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier.
 
+Basic switch and looping are possible.
+\begin{cquote}
+\lstDeleteShortInline@
+\setlength{\tabcolsep}{15pt}
+\begin{tabular}{@{}ll@{}}
+\begin{Go}
+day := Mon;
+switch day {
+  case Mon, Tue, Wed, Thu, Fri:
+	fmt.Println( "weekday" );
+  case Sat, Sun:
+	fmt.Println( "weekend" );
+}
+\end{Go}
+&
+\begin{Go}
+
+for i := Mon; i <= Sun; i += 1 {
+	fmt.Println( i )
+}
+
+
+
+\end{Go}
+\end{tabular}
+\lstMakeShortInline@
+\end{cquote}
+However, the loop prints the values from 0 to 13 because there is no actual enumeration.
+
 
 \section{Java}
-
-\lstnewenvironment{Java}[1][]{% necessary
-\lstset{
-language=Java,
-escapechar=\$,							% LaTeX escape in code
-moredelim=**[is][\color{red}]{`}{`},	% red highlighting @...@
-}% lstset
-\lstset{#1}% necessary
-}{}
-
-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:
+\lstnewenvironment{Java}[1][]{\lstset{language=Java,morekeywords={enum,assert,strictfp},
+	escapechar=\$,moredelim=**[is][\color{red}]{!}{!},}\lstset{#1}}{}
+
+Every enumeration in Java is an enumeration class.
+For a basic enumeration
 \begin{Java}
-public enum PizzaStatus {
-    ORDERED,
-    READY, 
-    DELIVERED; 
-}
+enum Weekday { Mon, Tue, Wed, Thu, Fri, Sat, Sun };
+Weekday day = Weekday.Sat;
 \end{Java}
-Additionally, enums come with many useful methods that we would otherwise need to write if we were using traditional public static final constants.
-
-\paragraph{Custom Enum Methods}
-
-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:
+the scoped enumerators are an ordered list of @final@ methods of type integer, ordered left to right starting at 0, increasing by 1.
+The value of an enumeration instance is restricted to the enumeration's enumerators.
+There is an implicit @int@ variable in the enumeration used to store the value of an enumeration instance.
+The position (ordinal) and label are accessible, where the value is the same as the position.
 \begin{Java}
-public class Pizza {
-    private PizzaStatus status;
-    public enum PizzaStatus {
-        ORDERED,
-        READY,
-        DELIVERED;
-    }
-    public boolean isDeliverable() {
-        if (getStatus() == PizzaStatus.READY) {
-            return true;
-        }
-        return false;
-    }
-    // Methods that set and get the status variable.
-}
+System.out.println( day.!ordinal()! + " " + day.!name()! ); // 5 Sat
 \end{Java}
-
-\paragraph{Comparing Enum Types Using "==" Operator}
-
-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.
-Furthermore, the "==" operator provides compile-time and run-time safety.
-
-First, we'll look at run-time safety in the following snippet, where we'll use the "==" operator to compare statuses.
-Either value can be null and we won't get a NullPointerException. Conversely, if we use the equals method, we will get a NullPointerException:
+There is an inverse function @valueOf@ from string to enumerator.
 \begin{Java}
-if(testPz.getStatus().equals(Pizza.PizzaStatus.DELIVERED)); 
-if(testPz.getStatus() == Pizza.PizzaStatus.DELIVERED); 
+day = Weekday.valueOf( "Wed" );
 \end{Java}
-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.
-This is because the values of the enum and the getStatus method coincidentally are the same;
-however, logically the comparison should be false. We avoid this issue by using the "==" operator.
-
-The compiler will flag the comparison as an incompatibility error:
+There are no implicit conversions to/from an enumerator and its underlying type.
+Like \Csharp, \VRef[Figure]{f:JavaFreeVersusClass} shows the same example for an enumeration with free routines for manipulation, and embedding the enumeration and operations into an enumeration class.
+
+\begin{figure}
+\centering
+\lstDeleteShortInline@
+\begin{tabular}{@{}l|l@{}}
+\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
+\hline
 \begin{Java}
-if(testPz.getStatus().equals(TestColor.GREEN));
-if(testPz.getStatus() == TestColor.GREEN);
+enum Weekday !{!
+	Mon, Tue, Wed, Thu, Fri, Sat, Sun !}!;
+
+static boolean isWeekday( Weekday wd ) {
+	return wd.ordinal() <= Weekday.Fri.ordinal();
+}
+static boolean isWeekend( Weekday wd ) {
+	return Weekday.Fri.ordinal() < wd.ordinal();
+}
+
+public static void main( String[] args ) {
+	Weekday day = Weekday.Sat;
+	System.out.println( isWeekday( day ) );
+	System.out.println( isWeekend( day ) );
+}
 \end{Java}
-
-\paragraph{Using Enum Types in Switch Statements}
-
-We can use enum types in switch statements also:
+&
 \begin{Java}
-public int getDeliveryTimeInDays() {
-    switch (status) {
-        case ORDERED: return 5;
-        case READY: return 2;
-        case DELIVERED: return 0;
-    }
-    return 0;
+enum Weekday !{!
+	Mon, Tue, Wed, Thu, Fri, Sat, Sun;
+
+	public boolean isWeekday() {
+		return ordinal() <= Weekday.Fri.ordinal();
+	}
+	public boolean isWeekend() {
+		return Weekday.Fri.ordinal() < ordinal();
+	}
+!}!
+public static void main( String[] args ) {
+	WeekDay day = WeekDay.Sat;
+	System.out.println( day.isWeekday() );
+	System.out.println( day.isWeekend() );
 }
 \end{Java}
-
-\paragraph{Fields, Methods and Constructors in Enums}
-
-We can define constructors, methods, and fields inside enum types, which makes them very powerful.
-
-Next, let's extend the example above by implementing the transition from one stage of a pizza order to another.
-We'll see how we can get rid of the if and switch statements used before:
+\end{tabular}
+\lstMakeShortInline@
+\caption{Java: Free Routine Versus Class Enumeration}
+\label{f:JavaFreeVersusClass}
+\end{figure}
+
+To explicitly assign enumerator values and/or use a non-@int@ enumeration type (any Java type may be used), the enumeration must specify an explicit type in the enumeration class and a constructor.
 \begin{Java}
-public class Pizza {
-    private PizzaStatus status;
-    public enum PizzaStatus {
-        ORDERED (5){
-            @Override
-            public boolean isOrdered() {
-                return true;
-            }
-        },
-        READY (2){
-            @Override
-            public boolean isReady() {
-                return true;
-            }
-        },
-        DELIVERED (0){
-            @Override
-            public boolean isDelivered() {
-                return true;
-            }
-        };
-
-        private int timeToDelivery;
-        public boolean isOrdered() {return false;}
-        public boolean isReady() {return false;}
-        public boolean isDelivered(){return false;}
-        public int getTimeToDelivery() {
-            return timeToDelivery;
-        }
-        PizzaStatus (int timeToDelivery) {
-            this.timeToDelivery = timeToDelivery;
-        }
-    }
-    public boolean isDeliverable() {
-        return this.status.isReady();
-    }
-    public void printTimeToDeliver() {
-        System.out.println("Time to delivery is " + 
-          this.getStatus().getTimeToDelivery());
-    }
-    // Methods that set and get the status variable.
-}
+enum Weekday {
+	Mon!(1)!, Tue!(2)!, Wed!(3)!, Thu!(4)!, Fri!(5)!, Sat!(6)!, Sun!(7)!; // must appear first
+	private !long! day;					$\C{// underlying enumeration type}$
+	private Weekday( !long! d ) { day = d; } $\C{// used to initialize enumerators}$
+};
+Weekday day = Weekday.Sat;
 \end{Java}
-The test snippet below demonstrates how this works:
+If an enumerator initialization is a runtime expression, the expression is executed once at the point the enumeration is declaraed.
+
+The position, value, and label are accessible.
 \begin{Java}
-@Test
-public void givenPizaOrder_whenReady_thenDeliverable() {
-    Pizza testPz = new Pizza();
-    testPz.setStatus(Pizza.PizzaStatus.READY);
-    assertTrue(testPz.isDeliverable());
-}
+System.out.println( !day.ordinal()! + " " + !day.day! + " " + !day.name()! );  // 5 6 Sat
 \end{Java}
-
-\paragraph{EnumSet and EnumMap}
-
-\paragraph{EnumSet}
-
-The EnumSet is a specialized Set implementation that's meant to be used with Enum types.
-
-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.
-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.
-
-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.
-
-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.
-
-In the code snippet below, we can see how to use EnumSet to create a subset of constants:
+The constructor is private so only initialization or assignment can be used to set an enumeration, which ensures only corresponding enumerator values are allowed.
+
+An enumeration can appear in a @switch@ statement, but no ranges.
 \begin{Java}
-public class Pizza {
-    private static EnumSet<PizzaStatus> undeliveredPizzaStatuses =
-      EnumSet.of(PizzaStatus.ORDERED, PizzaStatus.READY);
-    private PizzaStatus status;
-    public enum PizzaStatus {
-        ...
-    }
-    public boolean isDeliverable() {
-        return this.status.isReady();
-    }
-    public void printTimeToDeliver() {
-        System.out.println("Time to delivery is " + 
-          this.getStatus().getTimeToDelivery() + " days");
-    }
-    public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
-        return input.stream().filter(
-          (s) -> undeliveredPizzaStatuses.contains(s.getStatus()))
-            .collect(Collectors.toList());
-    }
-    public void deliver() { 
-        if (isDeliverable()) { 
-            PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy()
-              .deliver(this); 
-            this.setStatus(PizzaStatus.DELIVERED); 
-        } 
-    }
-    // Methods that set and get the status variable.
+switch ( day ) {
+  case Mon: case Tue: case Wed: case Thu: case Fri:
+	System.out.println( "weekday" );
+	break;
+  case Sat: case Sun:
+	System.out.println( "weekend" );
+	break;
 }
 \end{Java}
-
-Executing the following test demonstrates the power of the EnumSet implementation of the Set interface:
+Like \Csharp, looping over an enumeration is done using method @values@, which returns the array of enumerator values (expensive operation).
 \begin{Java}
-@Test
-public void givenPizaOrders_whenRetrievingUnDeliveredPzs_thenCorrectlyRetrieved() {
-    List<Pizza> pzList = new ArrayList<>();
-    Pizza pz1 = new Pizza();
-    pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
-
-    Pizza pz2 = new Pizza();
-    pz2.setStatus(Pizza.PizzaStatus.ORDERED);
-
-    Pizza pz3 = new Pizza();
-    pz3.setStatus(Pizza.PizzaStatus.ORDERED);
-
-    Pizza pz4 = new Pizza();
-    pz4.setStatus(Pizza.PizzaStatus.READY);
-
-    pzList.add(pz1);
-    pzList.add(pz2);
-    pzList.add(pz3);
-    pzList.add(pz4);
-
-    List<Pizza> undeliveredPzs = Pizza.getAllUndeliveredPizzas(pzList); 
-    assertTrue(undeliveredPzs.size() == 3); 
-}
+for ( Weekday iday : Weekday.values() ) {
+	System.out.print( iday.ordinal() + iday.day + " " +  iday.name() + ",  " );
+}
+0 1 Mon,  1 2 Tue,  2 3 Wed,  3 4 Thu,  4 5 Fri,  5 6 Sat,  6 7 Sun,  
 \end{Java}
 
-\paragraph{EnumMap}
-
-EnumMap is a specialized Map implementation meant to be used with enum constants as keys.
-Compared to its counterpart HashMap, it's an efficient and compact implementation that's internally represented as an array:
-\begin{Java}
-EnumMap<Pizza.PizzaStatus, Pizza> map;
-\end{Java}
-Let's look at an example of how we can use it in practice:
-\begin{Java}
-public static EnumMap<PizzaStatus, List<Pizza>> 
-  groupPizzaByStatus(List<Pizza> pizzaList) {
-    EnumMap<PizzaStatus, List<Pizza>> pzByStatus = 
-      new EnumMap<PizzaStatus, List<Pizza>>(PizzaStatus.class);
-    
-    for (Pizza pz : pizzaList) {
-        PizzaStatus status = pz.getStatus();
-        if (pzByStatus.containsKey(status)) {
-            pzByStatus.get(status).add(pz);
-        } else {
-            List<Pizza> newPzList = new ArrayList<Pizza>();
-            newPzList.add(pz);
-            pzByStatus.put(status, newPzList);
-        }
-    }
-    return pzByStatus;
-}
-\end{Java}
-Executing the following test demonstrates the power of the EnumMap implementation of the Map interface:
-\begin{Java}
-@Test
-public void givenPizaOrders_whenGroupByStatusCalled_thenCorrectlyGrouped() {
-    List<Pizza> pzList = new ArrayList<>();
-    Pizza pz1 = new Pizza();
-    pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
-
-    Pizza pz2 = new Pizza();
-    pz2.setStatus(Pizza.PizzaStatus.ORDERED);
-
-    Pizza pz3 = new Pizza();
-    pz3.setStatus(Pizza.PizzaStatus.ORDERED);
-
-    Pizza pz4 = new Pizza();
-    pz4.setStatus(Pizza.PizzaStatus.READY);
-
-    pzList.add(pz1);
-    pzList.add(pz2);
-    pzList.add(pz3);
-    pzList.add(pz4);
-
-    EnumMap<Pizza.PizzaStatus,List<Pizza>> map = Pizza.groupPizzaByStatus(pzList);
-    assertTrue(map.get(Pizza.PizzaStatus.DELIVERED).size() == 1);
-    assertTrue(map.get(Pizza.PizzaStatus.ORDERED).size() == 2);
-    assertTrue(map.get(Pizza.PizzaStatus.READY).size() == 1);
-}
-\end{Java}
-
-\paragraph{Singleton Pattern}
-
-Normally, implementing a class using the Singleton pattern is quite non-trivial.
-Enums provide a quick and easy way of implementing singletons.
-
-In addition, since the enum class implements the Serializable interface under the hood, the class is guaranteed to be a singleton by the JVM.
-This is unlike the conventional implementation, where we have to ensure that no new instances are created during deserialization.
-
-In the code snippet below, we see how we can implement a singleton pattern:
-\begin{Java}
-public enum PizzaDeliverySystemConfiguration {
-    INSTANCE;
-    PizzaDeliverySystemConfiguration() {
-        // Initialization configuration which involves
-        // overriding defaults like delivery strategy
-    }
-
-    private PizzaDeliveryStrategy deliveryStrategy = PizzaDeliveryStrategy.NORMAL;
-
-    public static PizzaDeliverySystemConfiguration getInstance() {
-        return INSTANCE;
-    }
-
-    public PizzaDeliveryStrategy getDeliveryStrategy() {
-        return deliveryStrategy;
-    }
-}
-\end{Java}
-
-\paragraph{Strategy Pattern}
-
-Conventionally, the Strategy pattern is written by having an interface that is implemented by different classes.
-
-Adding a new strategy means adding a new implementation class.
-With enums, we can achieve this with less effort, and adding a new implementation means simply defining another instance with some implementation.
-
-The code snippet below shows how to implement the Strategy pattern:
-\begin{Java}
-public enum PizzaDeliveryStrategy {
-    EXPRESS {
-        @Override
-        public void deliver(Pizza pz) {
-            System.out.println("Pizza will be delivered in express mode");
-        }
-    },
-    NORMAL {
-        @Override
-        public void deliver(Pizza pz) {
-            System.out.println("Pizza will be delivered in normal mode");
-        }
-    };
-
-    public abstract void deliver(Pizza pz);
-}
-\end{Java}
-Then we add the following method to the Pizza class:
-\begin{Java}
-public void deliver() {
-    if (isDeliverable()) {
-        PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy()
-          .deliver(this);
-        this.setStatus(PizzaStatus.DELIVERED);
-    }
-}
-
-@Test
-public void givenPizaOrder_whenDelivered_thenPizzaGetsDeliveredAndStatusChanges() {
-    Pizza pz = new Pizza();
-    pz.setStatus(Pizza.PizzaStatus.READY);
-    pz.deliver();
-    assertTrue(pz.getStatus() == Pizza.PizzaStatus.DELIVERED);
-}
-\end{Java}
-
-8. Java 8 and Enums
-
-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:
-\begin{Java}
-public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
-    return input.stream().filter(
-      (s) -> !deliveredPizzaStatuses.contains(s.getStatus()))
-        .collect(Collectors.toList());
-}
-
-public static EnumMap<PizzaStatus, List<Pizza>> 
-  groupPizzaByStatus(List<Pizza> pzList) {
-    EnumMap<PizzaStatus, List<Pizza>> map = pzList.stream().collect(
-      Collectors.groupingBy(Pizza::getStatus,
-      () -> new EnumMap<>(PizzaStatus.class), Collectors.toList()));
-    return map;
-}
-\end{Java}
+As well, Java provides an @EnumSet@ where the underlying type is an efficient set of bits, one per enumeration \see{\Csharp \lstinline{Flags}, \VRef{s:Csharp}}, providing (logical) operations on groups of enumerators.
+There is also a specialized version of @HashMap@ with enumerator keys, which has performance benefits.
+
+Enumeration inheritence is disallowed because an enumeration is @final@.
+
 
 
 \section{Modula-3}
 
+
+
 \section{Rust}
+\lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+
+Enumerations
+\begin{rust}
+	Syntax
+	Enumeration :
+	   enum IDENTIFIER  GenericParams? WhereClause? { EnumItems? }
+
+	EnumItems :
+	   EnumItem ( , EnumItem )* ,?
+
+	EnumItem :
+	   OuterAttribute* Visibility?
+	   IDENTIFIER ( EnumItemTuple | EnumItemStruct )? EnumItemDiscriminant?
+
+	EnumItemTuple :
+	   ( TupleFields? )
+
+	EnumItemStruct :
+	   { StructFields? }
+
+	EnumItemDiscriminant :
+	   = Expression
+\end{rust}
+An enumeration, also referred to as an enum, is a simultaneous definition of a nominal enumerated type as well as a set of constructors, that can be used to create or pattern-match values of the corresponding enumerated type.
+
+Enumerations are declared with the keyword enum.
+
+An example of an enum item and its use:
+\begin{rust}
+enum Animal {
+	Dog,
+	Cat,
+}
+
+let mut a: Animal = Animal::Dog;
+a = Animal::Cat;
+\end{rust}
+Enum constructors can have either named or unnamed fields:
+\begin{rust}
+enum Animal {
+	Dog(String, f64),
+	Cat { name: String, weight: f64 },
+}
+
+let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2);
+a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
+\end{rust}
+In this example, Cat is a struct-like enum variant, whereas Dog is simply called an enum variant.
+
+An enum where no constructors contain fields are called a field-less enum. For example, this is a fieldless enum:
+\begin{rust}
+enum Fieldless {
+	Tuple(),
+	Struct{},
+	Unit,
+}
+\end{rust}
+If a field-less enum only contains unit variants, the enum is called an unit-only enum. For example:
+\begin{rust}
+enum Enum {
+	Foo = 3,
+	Bar = 2,
+	Baz = 1,
+}
+\end{rust}
+
+\subsection{Discriminants}
+
+Each enum instance has a discriminant: an integer logically associated to it that is used to determine which variant it holds.
+
+Under the default representation, the discriminant is interpreted as an isize value. However, the compiler is allowed to use a smaller type (or another means of distinguishing variants) in its actual memory layout.
+
+\subsection{Assigning discriminant values}
+
+\subsection{Explicit discriminants}
+
+In two circumstances, the discriminant of a variant may be explicitly set by following the variant name with = and a constant expression:
+
+	if the enumeration is "unit-only".
+
+	if a primitive representation is used. For example:
+\begin{rust}
+	#[repr(u8)]
+	enum Enum {
+		Unit = 3,
+		Tuple(u16),
+		Struct {
+			a: u8,
+			b: u16,
+		} = 1,
+	}
+\end{rust}
+
+\subsection{Implicit discriminants}
+
+If a discriminant for a variant is not specified, then it is set to one higher than the discriminant of the previous variant in the declaration. If the discriminant of the first variant in the declaration is unspecified, then it is set to zero.
+\begin{rust}
+enum Foo {
+	Bar,			// 0
+	Baz = 123,	  // 123
+	Quux,		   // 124
+}
+
+let baz_discriminant = Foo::Baz as u32;
+assert_eq!(baz_discriminant, 123);
+\end{rust}
+
+\subsection{Restrictions}
+
+It is an error when two variants share the same discriminant.
+\begin{rust}
+enum SharedDiscriminantError {
+	SharedA = 1,
+	SharedB = 1
+}
+
+enum SharedDiscriminantError2 {
+	Zero,	   // 0
+	One,		// 1
+	OneToo = 1  // 1 (collision with previous!)
+}
+\end{rust}
+It is also an error to have an unspecified discriminant where the previous discriminant is the maximum value for the size of the discriminant.
+\begin{rust}
+#[repr(u8)]
+enum OverflowingDiscriminantError {
+	Max = 255,
+	MaxPlusOne // Would be 256, but that overflows the enum.
+}
+
+#[repr(u8)]
+enum OverflowingDiscriminantError2 {
+	MaxMinusOne = 254, // 254
+	Max,			   // 255
+	MaxPlusOne		 // Would be 256, but that overflows the enum.
+}
+\end{rust}
+
+\subsection{Accessing discriminant}
+
+\begin{rust}
+Via mem::discriminant
+\end{rust}
+@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.
+
+\subsection{Casting}
+
+If an enumeration is unit-only (with no tuple and struct variants), then its discriminant can be directly accessed with a numeric cast; e.g.:
+\begin{rust}
+enum Enum {
+	Foo,
+	Bar,
+	Baz,
+}
+
+assert_eq!(0, Enum::Foo as isize);
+assert_eq!(1, Enum::Bar as isize);
+assert_eq!(2, Enum::Baz as isize);
+\end{rust}
+Field-less enums can be casted if they do not have explicit discriminants, or where only unit variants are explicit.
+\begin{rust}
+enum Fieldless {
+	Tuple(),
+	Struct{},
+	Unit,
+}
+
+assert_eq!(0, Fieldless::Tuple() as isize);
+assert_eq!(1, Fieldless::Struct{} as isize);
+assert_eq!(2, Fieldless::Unit as isize);
+\end{rust}
+\begin{rust}
+#[repr(u8)]
+enum FieldlessWithDiscrimants {
+	First = 10,
+	Tuple(),
+	Second = 20,
+	Struct{},
+	Unit,
+}
+
+assert_eq!(10, FieldlessWithDiscrimants::First as u8);
+assert_eq!(11, FieldlessWithDiscrimants::Tuple() as u8);
+assert_eq!(20, FieldlessWithDiscrimants::Second as u8);
+assert_eq!(21, FieldlessWithDiscrimants::Struct{} as u8);
+assert_eq!(22, FieldlessWithDiscrimants::Unit as u8);
+\end{rust}
+
+\subsection{Pointer casting}
+
+If the enumeration specifies a primitive representation, then the discriminant may be reliably accessed via unsafe pointer casting:
+\begin{rust}
+#[repr(u8)]
+enum Enum {
+	Unit,
+	Tuple(bool),
+	Struct{a: bool},
+}
+
+impl Enum {
+	fn discriminant(&self) -> u8 {
+		unsafe { *(self as *const Self as *const u8) }
+	}
+}
+
+let unit_like = Enum::Unit;
+let tuple_like = Enum::Tuple(true);
+let struct_like = Enum::Struct{a: false};
+
+assert_eq!(0, unit_like.discriminant());
+assert_eq!(1, tuple_like.discriminant());
+assert_eq!(2, struct_like.discriminant());
+\end{rust}
+
+\subsection{Zero-variant enums}
+
+Enums with zero variants are known as zero-variant enums. As they have no valid values, they cannot be instantiated.
+\begin{rust}
+enum ZeroVariants {}
+\end{rust}
+Zero-variant enums are equivalent to the never type, but they cannot be coerced into other types.
+\begin{rust}
+let x: ZeroVariants = panic!();
+let y: u32 = x; // mismatched type error
+\end{rust}
+
+\subsection{Variant visibility}
+
+Enum variants syntactically allow a Visibility annotation, but this is rejected when the enum is validated. This allows items to be parsed with a unified syntax across different contexts where they are used.
+\begin{rust}
+macro_rules! mac_variant {
+	($vis:vis $name:ident) => {
+		enum $name {
+			$vis Unit,
+
+			$vis Tuple(u8, u16),
+
+			$vis Struct { f: u8 },
+		}
+	}
+}
+
+// Empty `vis` is allowed.
+mac_variant! { E }
+
+// This is allowed, since it is removed before being validated.
+#[cfg(FALSE)]
+enum E {
+	pub U,
+	pub(crate) T(u8),
+	pub(super) T { f: String }
+}
+\end{rust}
 
 
 \section{Swift}
-
-\lstnewenvironment{swift}[1][]{% necessary
-\lstset{
-language=Swift,
-escapechar=\$,							% LaTeX escape in code
-moredelim=**[is][\color{red}]{@}{@},	% red highlighting @...@
-}% lstset
-\lstset{#1}% necessary
-}{}
-
-Model custom types that define a list of possible values.
+\lstnewenvironment{swift}[1][]{\lstset{language=Swift,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+
+% https://www.programiz.com/swift/online-compiler
+
+A Swift enumeration provides a heterogenous set of enumerators, like a tagged @union@, where the field name is the enumerator and its list of type parameters form its type.
+\begin{swift}
+enum Many {
+	case Mon, Tue, Wed, Thu, Fri, Sat, Sun // basic enumerator
+	case code( String ) // string enumerator
+	case tuple( Int, Int, Int ) // tuple enumerator
+};
+var day = Many.Sat; // qualification to resolve type
+print( day );
+day = .Wed // no qualification after type resolved
+print( day );
+day = .code( "ABC" );
+print( day );
+day = .tuple( 1, 2, 3 );
+print( day );
+
+Sat
+Wed
+code("ABC")
+tuple(1, 2, 3)
+\end{swift}
+
 
 An 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.
@@ -808,21 +876,4 @@
 \paragraph{Enumeration Syntax}
 
-You introduce enumerations with the @enum@ keyword and place their entire definition within a pair of braces:
-\begin{swift}
-enum SomeEnumeration {
-	// enumeration definition goes here
-}
-\end{swift}
-Here's an example for the four main points of a compass:
-\begin{swift}
-enum CompassPoint {
-	case north
-	case south
-	case east
-	case west
-}
-\end{swift}
-The values defined in an enumeration (such as @north@, @south@, @east@, and @west@) are its enumeration cases.
-You use the @case@ keyword to introduce new enumeration cases.
 
 Note:
@@ -1139,4 +1190,1267 @@
 
 \section{Python}
+\lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
+
+An @Enum@ is a set of symbolic names bound to unique values.
+They are similar to global variables, but they offer a more useful @repr()@, grouping, type-safety, and a few other features.
+
+They are most useful when you have a variable that can take one of a limited selection of values. For example, the days of the week:
+\begin{python}
+>>> from enum import Enum
+>>> class Weekday(Enum):
+...    MONDAY = 1
+...    TUESDAY = 2
+...    WEDNESDAY = 3
+...    THURSDAY = 4
+...    FRIDAY = 5
+...    SATURDAY = 6
+...    SUNDAY = 7
+\end{python}
+Or perhaps the RGB primary colors:
+\begin{python}
+>>> from enum import Enum
+>>> class Color(Enum):
+...    RED = 1
+...    GREEN = 2
+...    BLUE = 3
+\end{python}
+As you can see, creating an @Enum@ is as simple as writing a class that inherits from @Enum@ itself.
+
+Note: Case of Enum Members
+
+Because Enums are used to represent constants, and to help avoid issues with name clashes between mixin-class methods/attributes and enum names, we strongly recommend using @UPPER_CASE@ names for members, and will be using that style in our examples.
+
+Depending on the nature of the enum a member's value may or may not be important, but either way that value can be used to get the corresponding member:
+\begin{python}
+>>> Weekday(3)
+<Weekday.WEDNESDAY: 3>
+\end{python}
+As you can see, the @repr()@ of a member shows the enum name, the member name, and the value.
+The @str()@ of a member shows only the enum name and member name:
+\begin{python}
+print(Weekday.THURSDAY)
+Weekday.THURSDAY
+\end{python}
+The type of an enumeration member is the enum it belongs to:
+\begin{python}
+>>> type(Weekday.MONDAY)
+<enum 'Weekday'>
+isinstance(Weekday.FRIDAY, Weekday)
+True
+\end{python}
+Enum members have an attribute that contains just their name:
+\begin{python}
+>>> print(Weekday.TUESDAY.name)
+TUESDAY
+\end{python}
+Likewise, they have an attribute for their value:
+\begin{python}
+>>> Weekday.WEDNESDAY.value
+3
+\end{python}
+Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added.
+For example, @datetime.date@ has two methods for returning the weekday: @weekday()@ and @isoweekday()@.
+The difference is that one of them counts from 0-6 and the other from 1-7.
+Rather than keep track of that ourselves we can add a method to the @Weekday@ enum to extract the day from the date instance and return the matching enum member:
+\begin{python}
+$@$classmethod
+def from_date(cls, date):
+    return cls(date.isoweekday())
+\end{python}
+The complete Weekday enum now looks like this:
+\begin{python}
+>>> class Weekday(Enum):
+...    MONDAY = 1
+...    TUESDAY = 2
+...    WEDNESDAY = 3
+...    THURSDAY = 4
+...    FRIDAY = 5
+...    SATURDAY = 6
+...    SUNDAY = 7
+...    #
+...    $@$classmethod
+...    def from_date(cls, date):
+...        return cls(date.isoweekday())
+\end{python}
+Now we can find out what today is! Observe:
+\begin{python}
+>>> from datetime import date
+>>> Weekday.from_date(date.today())     
+<Weekday.TUESDAY: 2>
+\end{python}
+Of course, if you're reading this on some other day, you'll see that day instead.
+
+This Weekday enum is great if our variable only needs one day, but what if we need several? Maybe we're writing a function to plot chores during a week, and don't want to use a @list@ -- we could use a different type of @Enum@:
+\begin{python}
+>>> from enum import Flag
+>>> class Weekday(Flag):
+...    MONDAY = 1
+...    TUESDAY = 2
+...    WEDNESDAY = 4
+...    THURSDAY = 8
+...    FRIDAY = 16
+...    SATURDAY = 32
+...    SUNDAY = 64
+\end{python}
+We've changed two things: we're inherited from @Flag@, and the values are all powers of 2.
+
+Just like the original @Weekday@ enum above, we can have a single selection:
+\begin{python}
+>>> first_week_day = Weekday.MONDAY
+>>> first_week_day
+<Weekday.MONDAY: 1>
+\end{python}
+But @Flag@ also allows us to combine several members into a single variable:
+\begin{python}
+>>> weekend = Weekday.SATURDAY | Weekday.SUNDAY
+>>> weekend
+<Weekday.SATURDAY|SUNDAY: 96>
+\end{python}
+You can even iterate over a @Flag@ variable:
+\begin{python}
+>>> for day in weekend:
+...    print(day)
+Weekday.SATURDAY
+Weekday.SUNDAY
+\end{python}
+Okay, let's get some chores set up:
+\begin{python}
+>>> chores_for_ethan = {
+...    'feed the cat': Weekday.MONDAY | Weekday.WEDNESDAY | Weekday.FRIDAY,
+...    'do the dishes': Weekday.TUESDAY | Weekday.THURSDAY,
+...    'answer SO questions': Weekday.SATURDAY,
+...    }
+\end{python}
+And a function to display the chores for a given day:
+\begin{python}
+>>> def show_chores(chores, day):
+...    for chore, days in chores.items():
+...        if day in days:
+...            print(chore)
+>>> show_chores(chores_for_ethan, Weekday.SATURDAY)
+answer SO questions
+\end{python}
+In cases where the actual values of the members do not matter, you can save yourself some work and use @auto()@ for the values:
+\begin{python}
+>>> from enum import auto
+>>> class Weekday(Flag):
+...    MONDAY = auto()
+...    TUESDAY = auto()
+...    WEDNESDAY = auto()
+...    THURSDAY = auto()
+...    FRIDAY = auto()
+...    SATURDAY = auto()
+...    SUNDAY = auto()
+...    WEEKEND = SATURDAY | SUNDAY
+\end{python}
+
+\subsection{Programmatic access to enumeration members and their attributes}
+
+Sometimes it's useful to access members in enumerations programmatically (i.e. situations where @Color.RED@ won't do because the exact color is not known at program-writing time).
+@Enum@ allows such access:
+\begin{python}
+>>> Color(1)
+<Color.RED: 1>
+>>> Color(3)
+<Color.BLUE: 3>
+\end{python}
+If you want to access enum members by name, use item access:
+\begin{python}
+Color['RED']
+<Color.RED: 1>
+
+Color['GREEN']
+<Color.GREEN: 2>
+\end{python}
+If you have an enum member and need its name or value:
+\begin{python}
+>>> member = Color.RED
+>>> member.name
+'RED'
+>>> member.value
+1
+\end{python}
+
+\subsection{Duplicating enum members and values}
+
+Having two enum members with the same name is invalid:
+\begin{python}
+>>> class Shape(Enum):
+...    SQUARE = 2
+...    SQUARE = 3
+...
+Traceback (most recent call last):
+...
+TypeError: 'SQUARE' already defined as 2
+\end{python}
+However, an enum member can have other names associated with it.
+Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@.
+By-value lookup of the value of @A@ will return the member @A@.
+By-name lookup of @A@ will return the member @A@.
+By-name lookup of @B@ will also return the member @A@:
+\begin{python}
+>>> class Shape(Enum):
+...    SQUARE = 2
+...    DIAMOND = 1
+...    CIRCLE = 3
+...    ALIAS_FOR_SQUARE = 2
+...
+>>> Shape.SQUARE
+<Shape.SQUARE: 2>
+>>> Shape.ALIAS_FOR_SQUARE
+<Shape.SQUARE: 2>
+>>> Shape(2)
+<Shape.SQUARE: 2>
+\end{python}
+
+Note: Attempting to create a member with the same name as an already defined attribute (another member, a method, etc.) or attempting to create an attribute with the same name as a member is not allowed.
+
+\subsection{Ensuring unique enumeration values}
+
+By default, enumerations allow multiple names as aliases for the same value.
+When this behavior isn't desired, you can use the @unique()@ decorator:
+\begin{python}
+>>> from enum import Enum, unique
+>>> $@$unique
+... class Mistake(Enum):
+...     ONE = 1
+...     TWO = 2
+...     THREE = 3
+...     FOUR = 3
+... 
+Traceback (most recent call last):
+...
+ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
+\end{python}
+
+\subsection{Using automatic values}
+
+If the exact value is unimportant you can use @auto@:
+\begin{python}
+>>> from enum import Enum, auto
+>>> class Color(Enum):
+...     RED = auto()
+...     BLUE = auto()
+...     GREEN = auto()
+... 
+>>> [member.value for member in Color]
+[1, 2, 3]
+\end{python}
+The values are chosen by \_generate\_next\_value\_(), which can be overridden:
+\begin{python}
+>>> class AutoName(Enum):
+...     $@$staticmethod
+...     def _generate_next_value_(name, start, count, last_values):
+...         return name
+... 
+>>> class Ordinal(AutoName):
+...     NORTH = auto()
+...     SOUTH = auto()
+...     EAST = auto()
+...     WEST = auto()
+... 
+>>> [member.value for member in Ordinal]
+['NORTH', 'SOUTH', 'EAST', 'WEST']
+\end{python}
+Note The @_generate_next_value_()@ method must be defined before any members.
+
+\subsection{Iteration}
+
+Iterating over the members of an enum does not provide the aliases:
+\begin{python}
+>>> list(Shape)
+[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
+>>> list(Weekday)
+[<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>,
+<Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]
+\end{python}
+Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Weekday.WEEKEND@ aren't shown.
+
+The special attribute @__members__@ is a read-only ordered mapping of names to members.
+It includes all names defined in the enumeration, including the aliases:
+\begin{python}
+>>> for name, member in Shape.__members__.items():
+...     name, member
+... 
+('SQUARE', <Shape.SQUARE: 2>)
+('DIAMOND', <Shape.DIAMOND: 1>)
+('CIRCLE', <Shape.CIRCLE: 3>)
+('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)
+\end{python}
+The @__members__@ attribute can be used for detailed programmatic access to the enumeration members.
+For example, finding all the aliases:
+\begin{python}
+>>> [name for name, member in Shape.__members__.items() if member.name != name]
+['ALIAS_FOR_SQUARE']
+\end{python}
+Note: Aliases for flags include values with multiple flags set, such as 3, and no flags set, i.e. 0.
+
+\subsection{Comparisons}
+
+Enumeration members are compared by identity:
+\begin{python}
+>>> Color.RED is Color.RED
+True
+>>> Color.RED is Color.BLUE
+False
+>>> Color.RED is not Color.BLUE
+True
+\end{python}
+Ordered comparisons between enumeration values are not supported.
+Enum members are not integers (but see @IntEnum@ below):
+\begin{python}
+>>> Color.RED < Color.BLUE
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+TypeError: '<' not supported between instances of 'Color' and 'Color'
+\end{python}
+Equality comparisons are defined though:
+\begin{python}
+>>> Color.BLUE == Color.RED
+False
+>>> Color.BLUE != Color.RED
+True
+>>> Color.BLUE == Color.BLUE
+True
+\end{python}
+Comparisons against non-enumeration values will always compare not equal (again, @IntEnum@ was explicitly designed to behave differently, see below):
+\begin{python}
+>>> Color.BLUE == 2
+False
+\end{python}
+
+Warning: It is possible to reload modules -- if a reloaded module contains enums, they will be recreated, and the new members may not compare identical/equal to the original members.
+
+\subsection{Allowed members and attributes of enumerations}
+
+Most of the examples above use integers for enumeration values.
+Using integers is short and handy (and provided by default by the Functional API), but not strictly enforced.
+In the vast majority of use-cases, one doesn't care what the actual value of an enumeration is.
+But if the value is important, enumerations can have arbitrary values.
+
+Enumerations are Python classes, and can have methods and special methods as usual. If we have this enumeration:
+\begin{python}
+>>> class Mood(Enum):
+...     FUNKY = 1
+...     HAPPY = 3
+... 
+...     def describe(self):
+...         # self is the member here
+...         return self.name, self.value
+... 
+...     def __str__(self):
+...         return 'my custom str! {0}'.format(self.value)
+... 
+...     $@$classmethod
+... 
+...     def favorite_mood(cls):
+...         # cls here is the enumeration
+...         return cls.HAPPY
+...
+\end{python}
+Then:
+\begin{python}
+>>> Mood.favorite_mood()
+<Mood.HAPPY: 3>
+>>> Mood.HAPPY.describe()
+('HAPPY', 3)
+>>> str(Mood.FUNKY)
+'my custom str! 1'
+\end{python}
+The rules for what is allowed are as follows: names that start and end with a single underscore are reserved by enum and cannot be used;
+all other attributes defined within an enumeration will become members of this enumeration, with the exception of special methods (@__str__()@, @__add__()@, etc.), descriptors (methods are also descriptors), and variable names listed in @_ignore_@.
+
+Note: if your enumeration defines @__new__()@ and/or @__init__()@, any value(s) given to the enum member will be passed into those methods.
+See Planet for an example.
+
+Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
+it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
+See When to use @__new__()@ vs. @__init__()@ for more details.
+
+\subsection{Restricted Enum subclassing}
+
+A new @Enum@ class must have one base enum class, up to one concrete data type, and as many object-based mixin classes as needed.
+The order of these base classes is:
+\begin{python}
+class EnumName([mix-in, ...,] [data-type,] base-enum):
+    pass
+\end{python}
+Also, subclassing an enumeration is allowed only if the enumeration does not define any members.
+So this is forbidden:
+\begin{python}
+>>> class MoreColor(Color):
+...     PINK = 17
+... 
+Traceback (most recent call last):
+...
+TypeError: <enum 'MoreColor'> cannot extend <enum 'Color'>
+\end{python}
+But this is allowed:
+\begin{python}
+>>> class Foo(Enum):
+...     def some_behavior(self):
+...         pass
+... 
+>>> class Bar(Foo):
+...     HAPPY = 1
+...     SAD = 2
+... 
+\end{python}
+Allowing subclassing of enums that define members would lead to a violation of some important invariants of types and instances.
+On the other hand, it makes sense to allow sharing some common behavior between a group of enumerations. (See OrderedEnum for an example.)
+
+\subsection{Dataclass support}
+
+When inheriting from a @dataclass@, the @__repr__()@ omits the inherited class' name.
+For example:
+\begin{python}
+>>> from dataclasses import dataclass, field
+>>> $@$dataclass
+... class CreatureDataMixin:
+...     size: str
+...     legs: int
+...     tail: bool = field(repr=False, default=True)
+... 
+>>> class Creature(CreatureDataMixin, Enum):
+...     BEETLE = 'small', 6
+...     DOG = 'medium', 4
+... 
+>>> Creature.DOG
+<Creature.DOG: size='medium', legs=4>
+\end{python}
+Use the @dataclass()@ argument repr=False to use the standard @repr()@.
+
+Changed in version 3.12: Only the dataclass fields are shown in the value area, not the dataclass' name.
+
+\subsection{Pickling}
+
+Enumerations can be pickled and unpickled:
+\begin{python}
+>>> from test.test_enum import Fruit
+>>> from pickle import dumps, loads
+>>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
+True
+\end{python}
+The usual restrictions for pickling apply: picklable enums must be defined in the top level of a module, since unpickling requires them to be importable from that module.
+
+Note: With pickle protocol version 4 it is possible to easily pickle enums nested in other classes.
+
+It is possible to modify how enum members are pickled/unpickled by defining @__reduce_ex__()@ in the enumeration class.
+The default method is by-value, but enums with complicated values may want to use by-name:
+\begin{python}
+>>> import enum
+>>> class MyEnum(enum.Enum):
+...     __reduce_ex__ = enum.pickle_by_enum_name
+\end{python}
+Note: Using by-name for flags is not recommended, as unnamed aliases will not unpickle.
+
+\subsection{Functional API}
+
+The @Enum@ class is callable, providing the following functional API:
+\begin{python}
+>>> Animal = Enum('Animal', 'ANT BEE CAT DOG')
+>>> Animal
+<enum 'Animal'>
+>>> Animal.ANT
+<Animal.ANT: 1>
+>>> list(Animal)
+[<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]
+\end{python}
+The semantics of this API resemble @namedtuple@.
+The first argument of the call to @Enum@ is the name of the enumeration.
+
+The second argument is the source of enumeration member names.
+It can be a whitespace-separated string of names, a sequence of names, a sequence of 2-tuples with key/value pairs, or a mapping (e.g. dictionary) of names to values.
+The last two options enable assigning arbitrary values to enumerations;
+the others auto-assign increasing integers starting with 1 (use the @start@ parameter to specify a different starting value).
+A new class derived from @Enum@ is returned.
+In other words, the above assignment to Animal is equivalent to:
+\begin{python}
+>>> class Animal(Enum):
+...     ANT = 1
+...     BEE = 2
+...     CAT = 3
+...     DOG = 4
+... 
+\end{python}
+The reason for defaulting to 1 as the starting number and not 0 is that 0 is @False@ in a boolean sense, but by default enum members all evaluate to @True@.
+
+Pickling enums created with the functional API can be tricky as frame stack implementation details are used to try and figure out which module the enumeration is being created in (e.g. it will fail if you use a utility function in a separate module, and also may not work on IronPython or Jython).
+The solution is to specify the module name explicitly as follows:
+\begin{python}
+>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)
+\end{python}
+Warning: If module is not supplied, and @Enum@ cannot determine what it is, the new @Enum@ members will not be unpicklable; to keep errors closer to the source, pickling will be disabled.
+
+The new pickle protocol 4 also, in some circumstances, relies on @__qualname__@ being set to the location where pickle will be able to find the class.
+For example, if the class was made available in class SomeData in the global scope:
+\begin{python}
+>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')
+\end{python}
+The complete signature is:
+\begin{python}
+Enum(
+    value='NewEnumName',
+    names=<...>,
+    *,
+    module='...',
+    qualname='...',
+    type=<mixed-in class>,
+    start=1,
+    )
+\end{python}
+\begin{itemize}
+\item
+@value@: What the new enum class will record as its name.
+\item
+@names@: The enum members.
+This can be a whitespace- or comma-separated string (values will start at 1 unless otherwise specified):
+\begin{python}
+'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'
+\end{python}
+or an iterator of names:
+\begin{python}
+['RED', 'GREEN', 'BLUE']
+\end{python}
+or an iterator of (name, value) pairs:
+\begin{python}
+[('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]
+\end{python}
+or a mapping:
+\begin{python}
+{'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}
+\end{python}
+\item
+module: name of module where new enum class can be found.
+\item
+@qualname@: where in module new enum class can be found.
+\item
+@type@: type to mix in to new enum class.
+\item
+@start@: number to start counting at if only names are passed in.
+\end{itemize}
+Changed in version 3.5: The start parameter was added.
+
+\subsection{Derived Enumerations}
+
+\subsection{IntEnum}
+
+The first variation of @Enum@ that is provided is also a subclass of @int@.
+Members of an @IntEnum@ can be compared to integers;
+by extension, integer enumerations of different types can also be compared to each other:
+\begin{python}
+>>> from enum import IntEnum
+>>> class Shape(IntEnum):
+...     CIRCLE = 1
+...     SQUARE = 2
+... 
+>>> class Request(IntEnum):
+...     POST = 1
+...     GET = 2
+... 
+>>> Shape == 1
+False
+>>> Shape.CIRCLE == 1
+True
+>>> Shape.CIRCLE == Request.POST
+True
+\end{python}
+However, they still can't be compared to standard @Enum@ enumerations:
+\begin{python}
+>>> class Shape(IntEnum):
+...     CIRCLE = 1
+...     SQUARE = 2
+... 
+>>> class Color(Enum):
+...     RED = 1
+...     GREEN = 2
+... 
+>>> Shape.CIRCLE == Color.RED
+False
+\end{python}
+@IntEnum@ values behave like integers in other ways you'd expect:
+\begin{python}
+>>> int(Shape.CIRCLE)
+1
+>>> ['a', 'b', 'c'][Shape.CIRCLE]
+'b'
+>>> [i for i in range(Shape.SQUARE)]
+[0, 1]
+\end{python}
+
+\subsection{StrEnum}
+
+The second variation of @Enum@ that is provided is also a subclass of @str@.
+Members of a @StrEnum@ can be compared to strings;
+by extension, string enumerations of different types can also be compared to each other.
+
+New in version 3.11.
+
+\subsection{IntFlag}
+
+The next variation of @Enum@ provided, @IntFlag@, is also based on @int@.
+The difference being @IntFlag@ members can be combined using the bitwise operators (@&, |, ^, ~@) and the result is still an @IntFlag@ member, if possible.
+Like @IntEnum@, @IntFlag@ members are also integers and can be used wherever an int is used.
+
+Note: Any operation on an IntFlag member besides the bit-wise operations will lose the @IntFlag@ membership.
+
+Bit-wise operations that result in invalid @IntFlag@ values will lose the @IntFlag@ membership.
+See @FlagBoundary@ for details.
+
+New in version 3.6.
+
+Changed in version 3.11.
+
+Sample @IntFlag@ class:
+\begin{python}
+>>> from enum import IntFlag
+>>> class Perm(IntFlag):
+...     R = 4
+...     W = 2
+...     X = 1
+... 
+>>> Perm.R | Perm.W
+<Perm.R|W: 6>
+>>> Perm.R + Perm.W
+6
+>>> RW = Perm.R | Perm.W
+>>> Perm.R in RW
+True
+\end{python}
+It is also possible to name the combinations:
+\begin{python}
+>>> class Perm(IntFlag):
+...     R = 4
+...     W = 2
+...     X = 1
+...     RWX = 7
+... 
+>>> Perm.RWX
+<Perm.RWX: 7>
+>>> ~Perm.RWX
+<Perm: 0>
+>>> Perm(7)
+<Perm.RWX: 7>
+\end{python}
+Note: Named combinations are considered aliases. Aliases do not show up during iteration, but can be returned from by-value lookups.
+
+Changed in version 3.11.
+
+Another important difference between @IntFlag@ and @Enum@ is that if no flags are set (the value is 0), its boolean evaluation is @False@:
+\begin{python}
+>>> Perm.R & Perm.X
+<Perm: 0>
+>>> bool(Perm.R & Perm.X)
+False
+\end{python}
+Because @IntFlag@ members are also subclasses of int they can be combined with them (but may lose @IntFlag@ membership:
+\begin{python}
+>>> Perm.X | 4
+<Perm.R|X: 5>
+
+>>> Perm.X + 8
+9
+\end{python}
+Note: The negation operator, @~@, always returns an @IntFlag@ member with a positive value:
+\begin{python}
+>>> (~Perm.X).value == (Perm.R|Perm.W).value == 6
+True
+\end{python}
+@IntFlag@ members can also be iterated over:
+\begin{python}
+>>> list(RW)
+[<Perm.R: 4>, <Perm.W: 2>]
+\end{python}
+New in version 3.11.
+
+\subsection{Flag}
+
+The last variation is @Flag@.
+Like @IntFlag@, @Flag@ members can be combined using the bitwise operators (@&, |, ^, ~@).
+Unlike @IntFlag@, they cannot be combined with, nor compared against, any other @Flag@ enumeration, nor @int@.
+While it is possible to specify the values directly it is recommended to use @auto@ as the value and let @Flag@ select an appropriate value.
+
+New in version 3.6.
+
+Like @IntFlag@, if a combination of @Flag@ members results in no flags being set, the boolean evaluation is @False@:
+\begin{python}
+>>> from enum import Flag, auto
+>>> class Color(Flag):
+...     RED = auto()
+...     BLUE = auto()
+...     GREEN = auto()
+... 
+>>> Color.RED & Color.GREEN
+<Color: 0>
+>>> bool(Color.RED & Color.GREEN)
+False
+\end{python}
+Individual flags should have values that are powers of two (1, 2, 4, 8, ...), while combinations of flags will not:
+\begin{python}
+>>> class Color(Flag):
+...     RED = auto()
+...     BLUE = auto()
+...     GREEN = auto()
+...     WHITE = RED | BLUE | GREEN
+... 
+>>> Color.WHITE
+<Color.WHITE: 7>
+\end{python}
+Giving a name to the ``no flags set'' condition does not change its boolean value:
+\begin{python}
+>>> class Color(Flag):
+...     BLACK = 0
+...     RED = auto()
+...     BLUE = auto()
+...     GREEN = auto()
+... 
+>>> Color.BLACK
+<Color.BLACK: 0>
+>>> bool(Color.BLACK)
+False
+\end{python}
+@Flag@ members can also be iterated over:
+\begin{python}
+>>> purple = Color.RED | Color.BLUE
+>>> list(purple)
+[<Color.RED: 1>, <Color.BLUE: 2>]
+\end{python}
+New in version 3.11.
+
+Note: For the majority of new code, @Enum@ and @Flag@ are strongly recommended, since @IntEnum@ and @IntFlag@ break some semantic promises of an enumeration (by being comparable to integers, and thus by transitivity to other unrelated enumerations).
+@IntEnum@ and @IntFlag@ should be used only in cases where @Enum@ and @Flag@ will not do;
+for example, when integer constants are replaced with enumerations, or for interoperability with other systems.
+
+\subsection{Others}
+
+While @IntEnum@ is part of the enum module, it would be very simple to implement independently:
+\begin{python}
+class IntEnum(int, Enum):
+    pass
+\end{python}
+This demonstrates how similar derived enumerations can be defined;
+for example a @FloatEnum@ that mixes in float instead of @int@.
+
+Some rules:
+\begin{itemize}
+\item
+When subclassing @Enum@, mix-in types must appear before @Enum@ itself in the sequence of bases, as in the @IntEnum@ example above.
+\item
+Mix-in types must be subclassable.
+For example, @bool@ and @range@ are not subclassable and will throw an error during Enum creation if used as the mix-in type.
+\item
+While @Enum@ can have members of any type, once you mix in an additional type, all the members must have values of that type, e.g. @int@ above.
+This restriction does not apply to mix-ins which only add methods and don't specify another type.
+\item
+When another data type is mixed in, the value attribute is not the same as the enum member itself, although it is equivalent and will compare equal.
+\item
+A data type is a mixin that defines @__new__()@, or a @dataclass@
+\item
+\%-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.
+\item
+Formatted string literals, @str.format()@, and format() will use the enum's @__str__()@ method.
+\end{itemize}
+Note: Because @IntEnum@, @IntFlag@, and @StrEnum@ are designed to be drop-in replacements for existing constants, their @__str__()@ method has been reset to their data types' @__str__()@ method.
+
+\subsection{When to use \lstinline{__new__()} vs. \lstinline{__init__()}}
+
+@__new__()@ must be used whenever you want to customize the actual value of the @Enum@ member.
+Any other modifications may go in either @__new__()@ or @__init__()@, with @__init__()@ being preferred.
+
+For example, if you want to pass several items to the constructor, but only want one of them to be the value:
+\begin{python}
+>>> class Coordinate(bytes, Enum):
+...     """
+...     Coordinate with binary codes that can be indexed by the int code.
+...     """
+...     def __new__(cls, value, label, unit):
+...         obj = bytes.__new__(cls, [value])
+...         obj._value_ = value
+...         obj.label = label
+...         obj.unit = unit
+...         return obj
+...     PX = (0, 'P.X', 'km')
+...     PY = (1, 'P.Y', 'km')
+...     VX = (2, 'V.X', 'km/s')
+...     VY = (3, 'V.Y', 'km/s')
+
+>>> print(Coordinate['PY'])
+Coordinate.PY
+
+>>> print(Coordinate(3))
+Coordinate.VY
+\end{python}
+Warning: Do not call @super().__new__()@, as the lookup-only @__new__@ is the one that is found; instead, use the data type directly.
+
+\subsection{Finer Points}
+
+Supported @__dunder__@ names
+
+@__members__@ is a read-only ordered mapping of member\_name:member items. It is only available on the class.
+
+@__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.
+Supported @_sunder_@ names
+\begin{itemize}
+\item
+@_name_@ -- name of the member
+\item
+@_value_@ -- value of the member; can be set / modified in @__new__@
+\item
+@_missing_@ -- a lookup function used when a value is not found; may be overridden
+\item
+@_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
+\item
+@_order_@ -- used in Python 2/3 code to ensure member order is consistent (class attribute, removed during class creation)
+\item
+@_generate_@next@_value_@ -- used by the Functional API and by @auto@ to get an appropriate value for an enum member; may be overridden
+\end{itemize}
+Note: For standard @Enum@ classes the next value chosen is the last value seen incremented by one.
+
+For @Flag@ classes the next value chosen will be the next highest power-of-two, regardless of the last value seen.
+
+New in version 3.6: @_missing_@, @_order_@, @_generate_@next@_value_@
+
+New in version 3.7: @_ignore_@
+
+To help keep Python 2 / Python 3 code in sync an @_order_@ attribute can be provided.
+It will be checked against the actual order of the enumeration and raise an error if the two do not match:
+\begin{python}
+>>> class Color(Enum):
+...     _order_ = 'RED GREEN BLUE'
+...     RED = 1
+...     BLUE = 3
+...     GREEN = 2
+... 
+Traceback (most recent call last):
+...
+TypeError: member order does not match _order_:
+  ['RED', 'BLUE', 'GREEN']
+  ['RED', 'GREEN', 'BLUE']
+\end{python}
+Note: In Python 2 code the @_order_@ attribute is necessary as definition order is lost before it can be recorded.
+
+\subsection{\lstinline{_Private__names}}
+
+Private names are not converted to enum members, but remain normal attributes.
+
+Changed in version 3.11.
+
+\subsection{\lstinline{Enum} member type}
+
+@Enum@ members are instances of their enum class, and are normally accessed as @EnumClass.member@.
+In certain situations, such as writing custom enum behavior, being able to access one member directly from another is useful, and is supported;
+however, in order to avoid name clashes between member names and attributes/methods from mixed-in classes, upper-case names are strongly recommended.
+
+Changed in version 3.5.
+
+\subsection{Creating members that are mixed with other data types}
+
+When subclassing other data types, such as @int@ or @str@, with an @Enum@, all values after the = @are@ passed to that data type's constructor. For example:
+\begin{python}
+>>> class MyEnum(IntEnum):      # help(int) -> int(x, base=10) -> integer
+...     example = '11', 16      # so x='11' and base=16
+... 
+MyEnum.example.value        # and hex(11) is...
+17
+\end{python}
+
+\subsection{\lstinline{Boolean} value of \lstinline{Enum} classes and members}
+
+Enum classes that are mixed with non-@Enum@ types (such as @int@, @str@, etc.) are evaluated according to the mixed-in type's rules;
+otherwise, all members evaluate as @True@.
+To make your own enum's boolean evaluation depend on the member's value add the following to your class:
+\begin{python}
+def __bool__(self):
+    return bool(self.value)
+\end{python}
+Plain @Enum@ classes always evaluate as @True@.
+
+\subsection{\lstinline{Enum} classes with methods}
+
+If you give your enum subclass extra methods, like the Planet class below, those methods will show up in a dir() of the member, but not of the class:
+\begin{python}
+>>> dir(Planet)                         
+['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS',
+ '__class__', '__doc__', '__members__', '__module__']
+>>> dir(Planet.EARTH)                   
+['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value']
+\end{python}
+
+\subsection{Combining members of \lstinline{Flag}}
+
+Iterating over a combination of @Flag@ members will only return the members that are comprised of a single bit:
+\begin{python}
+>>> class Color(Flag):
+...     RED = auto()
+...     GREEN = auto()
+...     BLUE = auto()
+...     MAGENTA = RED | BLUE
+...     YELLOW = RED | GREEN
+...     CYAN = GREEN | BLUE
+... 
+>>> Color(3)  # named combination
+<Color.YELLOW: 3>
+>>> Color(7)      # not named combination
+<Color.RED|GREEN|BLUE: 7>
+\end{python}
+
+\subsection{\lstinline{Flag} and \lstinline{IntFlag} minutia}
+
+Using the following snippet for our examples:
+\begin{python}
+>>> class Color(IntFlag):
+...     BLACK = 0
+...     RED = 1
+...     GREEN = 2
+...     BLUE = 4
+...     PURPLE = RED | BLUE
+...     WHITE = RED | GREEN | BLUE
+... 
+\end{python}
+the following are true:
+\begin{itemize}
+\item
+single-bit flags are canonical
+\item
+multi-bit and zero-bit flags are aliases
+\item
+only canonical flags are returned during iteration:
+\begin{python}
+>>> list(Color.WHITE)
+[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
+\end{python}
+negating a flag or flag set returns a new flag/flag set with the corresponding positive integer value:
+\begin{python}
+>>> Color.BLUE
+<Color.BLUE: 4>
+
+>>> ~Color.BLUE
+<Color.RED|GREEN: 3>
+\end{python}
+\item
+names of pseudo-flags are constructed from their members' names:
+\begin{python}
+>>> (Color.RED | Color.GREEN).name
+'RED|GREEN'
+\end{python}
+\item
+multi-bit flags, aka aliases, can be returned from operations:
+\begin{python}
+>>> Color.RED | Color.BLUE
+<Color.PURPLE: 5>
+
+>>> Color(7)  # or Color(-1)
+<Color.WHITE: 7>
+
+>>> Color(0)
+<Color.BLACK: 0>
+\end{python}
+\item
+membership / containment checking: zero-valued flags are always considered to be contained:
+\begin{python}
+>>> Color.BLACK in Color.WHITE
+True
+\end{python}
+otherwise, only if all bits of one flag are in the other flag will True be returned:
+\begin{python}
+>>> Color.PURPLE in Color.WHITE
+True
+
+>>> Color.GREEN in Color.PURPLE
+False
+\end{python}
+\end{itemize}
+There is a new boundary mechanism that controls how out-of-range / invalid bits are handled: @STRICT@, @CONFORM@, @EJECT@, and @KEEP@:
+\begin{itemize}
+\item
+@STRICT@ --> raises an exception when presented with invalid values
+\item
+@CONFORM@ --> discards any invalid bits
+\item
+@EJECT@ --> lose Flag status and become a normal int with the given value
+\item
+@KEEP@ --> keep the extra bits
+\begin{itemize}
+\item
+keeps Flag status and extra bits
+\item
+extra bits do not show up in iteration
+\item
+extra bits do show up in repr() and str()
+\end{itemize}
+\end{itemize}
+The default for @Flag@ is @STRICT@, the default for @IntFlag@ is @EJECT@, and the default for @_convert_@ is @KEEP@ (see @ssl.Options@ for an example of when @KEEP@ is needed).
+
+\section{How are Enums and Flags different?}
+
+Enums have a custom metaclass that affects many aspects of both derived @Enum@ classes and their instances (members).
+
+\subsection{Enum Classes}
+
+The @EnumType@ metaclass is responsible for providing the @__contains__()@, @__dir__()@, @__iter__()@ and other methods that allow one to do things with an @Enum@ class that fail on a typical class, such as @list(Color)@ or @some_enum_var@ in @Color@.
+@EnumType@ is responsible for ensuring that various other methods on the final @Enum@ class are correct (such as @__new__()@, @__getnewargs__()@, @__str__()@ and @__repr__()@).
+
+\subsection{Flag Classes}
+
+Flags have an expanded view of aliasing: to be canonical, the value of a flag needs to be a power-of-two value, and not a duplicate name.
+So, in addition to the @Enum@ definition of alias, a flag with no value (a.k.a. 0) or with more than one power-of-two value (e.g. 3) is considered an alias.
+
+\subsection{Enum Members (aka instances)}
+
+The most interesting thing about enum members is that they are singletons.
+@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.
+
+\subsection{Flag Members}
+
+Flag members can be iterated over just like the @Flag@ class, and only the canonical members will be returned.
+For example:
+\begin{python}
+>>> list(Color)
+[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
+\end{python}
+(Note that BLACK, PURPLE, and WHITE do not show up.)
+
+Inverting a flag member returns the corresponding positive value, rather than a negative value -- for example:
+\begin{python}
+>>> ~Color.RED
+<Color.GREEN|BLUE: 6>
+\end{python}
+Flag members have a length corresponding to the number of power-of-two values they contain. For example:
+\begin{python}
+>>> len(Color.PURPLE)
+2
+\end{python}
+
+\subsection{Enum Cookbook}
+
+While @Enum@, @IntEnum@, @StrEnum@, @Flag@, and @IntFlag@ are expected to cover the majority of use-cases, they cannot cover them all. Here are recipes for some different types of enumerations that can be used directly, or as examples for creating one's own.
+
+\subsection{Omitting values}
+
+In many use-cases, one doesn't care what the actual value of an enumeration is. There are several ways to define this type of simple enumeration:
+\begin{itemize}
+\item
+use instances of auto for the value
+\item
+use instances of object as the value
+\item
+use a descriptive string as the value
+\item
+use a tuple as the value and a custom @__new__()@ to replace the tuple with an @int@ value
+\end{itemize}
+Using any of these methods signifies to the user that these values are not important, and also enables one to add, remove, or reorder members without having to renumber the remaining members.
+
+\subsection{Using \lstinline{auto}}
+
+Using @auto@ would look like:
+\begin{python}
+>>> class Color(Enum):
+...     RED = auto()
+...     BLUE = auto()
+...     GREEN = auto()
+... 
+>>> Color.GREEN
+<Color.GREEN: 3>
+\end{python}
+
+\subsection{Using \lstinline{object}}
+
+Using @object@ would look like:
+\begin{python}
+>>> class Color(Enum):
+...     RED = object()
+...     GREEN = object()
+...     BLUE = object()
+... 
+>>> Color.GREEN                         
+<Color.GREEN: <object object at 0x...>>
+\end{python}
+This is also a good example of why you might want to write your own @__repr__()@:
+\begin{python}
+>>> class Color(Enum):
+...     RED = object()
+...     GREEN = object()
+...     BLUE = object()
+...     def __repr__(self):
+...         return "<%s.%s>" % (self.__class__.__name__, self._name_)
+... 
+>>> Color.GREEN
+<Color.GREEN>
+\end{python}
+
+\subsection{Using a descriptive string}
+
+Using a string as the value would look like:
+\begin{python}
+>>> class Color(Enum):
+...     RED = 'stop'
+...     GREEN = 'go'
+...     BLUE = 'too fast!'
+... 
+>>> Color.GREEN
+<Color.GREEN: 'go'>
+\end{python}
+
+\subsection{Using a custom \lstinline{__new__()}}
+
+Using an auto-numbering @__new__()@ would look like:
+\begin{python}
+>>> class AutoNumber(Enum):
+...     def __new__(cls):
+...         value = len(cls.__members__) + 1
+...         obj = object.__new__(cls)
+...         obj._value_ = value
+...         return obj
+... 
+>>> class Color(AutoNumber):
+...     RED = ()
+...     GREEN = ()
+...     BLUE = ()
+... 
+>>> Color.GREEN
+<Color.GREEN: 2>
+\end{python}
+To make a more general purpose @AutoNumber@, add @*args@ to the signature:
+\begin{python}
+>>> class AutoNumber(Enum):
+...     def __new__(cls, *args):      # this is the only change from above
+...         value = len(cls.__members__) + 1
+...         obj = object.__new__(cls)
+...         obj._value_ = value
+...         return obj
+\end{python}
+Then when you inherit from @AutoNumber@ you can write your own @__init__@ to handle any extra arguments:
+\begin{python}
+>>> class Swatch(AutoNumber):
+...     def __init__(self, pantone='unknown'):
+...         self.pantone = pantone
+...     AUBURN = '3497'
+...     SEA_GREEN = '1246'
+...     BLEACHED_CORAL = () # New color, no Pantone code yet!
+... 
+>>> Swatch.SEA_GREEN
+<Swatch.SEA_GREEN: 2>
+>>> Swatch.SEA_GREEN.pantone
+'1246'
+>>> Swatch.BLEACHED_CORAL.pantone
+'unknown'
+\end{python}
+Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
+it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
+
+Warning: Do not call @super().__new__()@, as the lookup-only @__new__@ is the one that is found;
+instead, use the data type directly -- e.g.:
+\begin{python}
+obj = int.__new__(cls, value)
+\end{python}
+
+\subsection{OrderedEnum}
+
+An ordered enumeration that is not based on @IntEnum@ and so maintains the normal @Enum@ invariants (such as not being comparable to other enumerations):
+\begin{python}
+>>> class OrderedEnum(Enum):
+...     def __ge__(self, other):
+...         if self.__class__ is other.__class__:
+...             return self.value >= other.value
+...         return NotImplemented
+...     def __gt__(self, other):
+...         if self.__class__ is other.__class__:
+...             return self.value > other.value
+...         return NotImplemented
+...     def __le__(self, other):
+...         if self.__class__ is other.__class__:
+...             return self.value <= other.value
+...         return NotImplemented
+...     def __lt__(self, other):
+...         if self.__class__ is other.__class__:
+...             return self.value < other.value
+...         return NotImplemented
+... 
+>>> class Grade(OrderedEnum):
+...     A = 5
+...     B = 4
+...     C = 3
+...     D = 2
+...     F = 1
+>>> Grade.C < Grade.A
+True
+\end{python}
+
+\subsection{DuplicateFreeEnum}
+
+Raises an error if a duplicate member value is found instead of creating an alias:
+\begin{python}
+>>> class DuplicateFreeEnum(Enum):
+...     def __init__(self, *args):
+...         cls = self.__class__
+...         if any(self.value == e.value for e in cls):
+...             a = self.name
+...             e = cls(self.value).name
+...             raise ValueError(
+...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"
+...                 % (a, e))
+>>> class Color(DuplicateFreeEnum):
+...     RED = 1
+...     GREEN = 2
+...     BLUE = 3
+...     GRENE = 2
+... 
+Traceback (most recent call last):
+  ...
+ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'
+\end{python}
+Note: This is a useful example for subclassing Enum to add or change other behaviors as well as disallowing aliases.
+If the only desired change is disallowing aliases, the @unique()@ decorator can be used instead.
+
+\subsection{Planet}
+
+If @__new__()@ or @__init__()@ is defined, the value of the enum member will be passed to those methods:
+\begin{python}
+>>> class Planet(Enum):
+...     MERCURY = (3.303e+23, 2.4397e6)
+...     VENUS   = (4.869e+24, 6.0518e6)
+...     EARTH   = (5.976e+24, 6.37814e6)
+...     MARS    = (6.421e+23, 3.3972e6)
+...     JUPITER = (1.9e+27,   7.1492e7)
+...     SATURN  = (5.688e+26, 6.0268e7)
+...     URANUS  = (8.686e+25, 2.5559e7)
+...     NEPTUNE = (1.024e+26, 2.4746e7)
+...     def __init__(self, mass, radius):
+...         self.mass = mass       # in kilograms
+...         self.radius = radius   # in meters
+...     $\@$property
+...     def surface_gravity(self):
+...         # universal gravitational constant  (m3 kg-1 s-2)
+...         G = 6.67300E-11
+...         return G * self.mass / (self.radius * self.radius)
+... 
+>>> Planet.EARTH.value
+(5.976e+24, 6378140.0)
+>>> Planet.EARTH.surface_gravity
+9.802652743337129
+\end{python}
+
+\subsection{TimePeriod}
+
+An example to show the @_ignore_@ attribute in use:
+\begin{python}
+>>> from datetime import timedelta
+>>> class Period(timedelta, Enum):
+...     "different lengths of time"
+...     _ignore_ = 'Period i'
+...     Period = vars()
+...     for i in range(367):
+...         Period['day_%d' % i] = i
+... 
+>>> list(Period)[:2]
+[<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
+>>> list(Period)[-2:]
+[<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]
+\end{python}
+
+\subsection{Subclassing EnumType}
+
+While most enum needs can be met by customizing @Enum@ subclasses, either with class decorators or custom functions, @EnumType@ can be subclassed to provide a different Enum experience.
+
 
 \section{Algebraic Data Type}
Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/DeclarationNode.cc	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -82,4 +82,6 @@
 
 DeclarationNode::~DeclarationNode() {
+	delete name;
+
 //	delete variable.name;
 	delete variable.assertions;
@@ -99,8 +101,7 @@
 DeclarationNode * DeclarationNode::clone() const {
 	DeclarationNode * newnode = new DeclarationNode;
-	newnode->set_next( maybeCopy( get_next() ) );
+	newnode->next = maybeCopy( next );
 	newnode->name = name ? new string( *name ) : nullptr;
 
-	newnode->builtin = NoBuiltinType;
 	newnode->type = maybeCopy( type );
 	newnode->inLine = inLine;
@@ -170,5 +171,5 @@
 
 void DeclarationNode::printList( std::ostream & os, int indent ) const {
-	ParseNode::printList( os, indent );
+	ParseList::printList( os, indent );
 	if ( hasEllipsis ) {
 		os << string( indent, ' ' )  << "and a variable number of other arguments" << endl;
@@ -433,6 +434,5 @@
 	DeclarationNode * newnode = new DeclarationNode;
 	newnode->type = new TypeData( TypeData::Builtin );
-	newnode->builtin = bt;
-	newnode->type->builtintype = newnode->builtin;
+	newnode->type->builtintype = bt;
 	return newnode;
 } // DeclarationNode::newBuiltinType
@@ -554,15 +554,4 @@
 } // DeclarationNode::copySpecifiers
 
-static void addQualifiersToType( TypeData *& src, TypeData * dst ) {
-	if ( dst->base ) {
-		addQualifiersToType( src, dst->base );
-	} else if ( dst->kind == TypeData::Function ) {
-		dst->base = src;
-		src = nullptr;
-	} else {
-		dst->qualifiers |= src->qualifiers;
-	} // if
-} // addQualifiersToType
-
 DeclarationNode * DeclarationNode::addQualifiers( DeclarationNode * q ) {
 	if ( ! q ) { return this; }							// empty qualifier
@@ -580,26 +569,11 @@
 	} // if
 
-	if ( q->type->forall ) {							// forall qualifier ?
-		if ( type->forall ) {							// polymorphic routine ?
-			type->forall->appendList( q->type->forall ); // augment forall qualifier
-		} else {
-			if ( type->kind == TypeData::Aggregate ) {	// struct/union ?
-				if ( type->aggregate.params ) {			// polymorphic ?
-					type->aggregate.params->appendList( q->type->forall ); // augment forall qualifier
-				} else {								// not polymorphic
-					type->aggregate.params = q->type->forall; // set forall qualifier
-				} // if
-			} else {									// not polymorphic
-				type->forall = q->type->forall;			// make polymorphic routine
-			} // if
-		} // if
-		q->type->forall = nullptr;						// forall qualifier moved
-	} // if
-
 	checkQualifiers( type, q->type );
+	BuiltinType const builtin = type->builtintype;
 	if ( (builtin == Zero || builtin == One) && q->type->qualifiers.any() && error.length() == 0 ) {
 		SemanticWarning( yylloc, Warning::BadQualifiersZeroOne, builtinTypeNames[builtin] );
 	} // if
-	addQualifiersToType( q->type, type );
+	type = ::addQualifiers( q->type, type );
+	q->type = nullptr;
 
 	delete q;
@@ -607,124 +581,29 @@
 } // addQualifiers
 
-static void addTypeToType( TypeData *& src, TypeData *& dst ) {
-	if ( src->forall && dst->kind == TypeData::Function ) {
-		if ( dst->forall ) {
-			dst->forall->appendList( src->forall );
-		} else {
-			dst->forall = src->forall;
-		} // if
-		src->forall = nullptr;
-	} // if
-	if ( dst->base ) {
-		addTypeToType( src, dst->base );
-	} else {
-		switch ( dst->kind ) {
-		case TypeData::Unknown:
-			src->qualifiers |= dst->qualifiers;
-			dst = src;
-			src = nullptr;
-			break;
-		case TypeData::Basic:
-			dst->qualifiers |= src->qualifiers;
-			if ( src->kind != TypeData::Unknown ) {
-				assert( src->kind == TypeData::Basic );
-
-				if ( dst->basictype == DeclarationNode::NoBasicType ) {
-					dst->basictype = src->basictype;
-				} else if ( src->basictype != DeclarationNode::NoBasicType )
-					SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
-								   DeclarationNode::basicTypeNames[ dst->basictype ],
-								   DeclarationNode::basicTypeNames[ src->basictype ] );
-				if ( dst->complextype == DeclarationNode::NoComplexType ) {
-					dst->complextype = src->complextype;
-				} else if ( src->complextype != DeclarationNode::NoComplexType )
-					SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
-								   DeclarationNode::complexTypeNames[ src->complextype ],
-								   DeclarationNode::complexTypeNames[ src->complextype ] );
-				if ( dst->signedness == DeclarationNode::NoSignedness ) {
-					dst->signedness = src->signedness;
-				} else if ( src->signedness != DeclarationNode::NoSignedness )
-					SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
-								   DeclarationNode::signednessNames[ dst->signedness ],
-								   DeclarationNode::signednessNames[ src->signedness ] );
-				if ( dst->length == DeclarationNode::NoLength ) {
-					dst->length = src->length;
-				} else if ( dst->length == DeclarationNode::Long && src->length == DeclarationNode::Long ) {
-					dst->length = DeclarationNode::LongLong;
-				} else if ( src->length != DeclarationNode::NoLength )
-					SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
-								   DeclarationNode::lengthNames[ dst->length ],
-								   DeclarationNode::lengthNames[ src->length ] );
-			} // if
-			break;
-		default:
-			switch ( src->kind ) {
-			case TypeData::Aggregate:
-			case TypeData::Enum:
-				dst->base = new TypeData( TypeData::AggregateInst );
-				dst->base->aggInst.aggregate = src;
-				if ( src->kind == TypeData::Aggregate ) {
-					dst->base->aggInst.params = maybeCopy( src->aggregate.actuals );
-				} // if
-				dst->base->qualifiers |= src->qualifiers;
-				src = nullptr;
-				break;
-			default:
-				if ( dst->forall ) {
-					dst->forall->appendList( src->forall );
-				} else {
-					dst->forall = src->forall;
-				} // if
-				src->forall = nullptr;
-				dst->base = src;
-				src = nullptr;
-			} // switch
-		} // switch
-	} // if
-}
-
 DeclarationNode * DeclarationNode::addType( DeclarationNode * o, bool copyattr ) {
-	if ( o ) {
-		checkSpecifiers( o );
-		copySpecifiers( o, copyattr );
-		if ( o->type ) {
-			if ( ! type ) {
-				if ( o->type->kind == TypeData::Aggregate || o->type->kind == TypeData::Enum ) {
-					// Hide type information aggregate instances.
-					type = new TypeData( TypeData::AggregateInst );
-					type->aggInst.aggregate = o->type;	// change ownership
-					type->aggInst.aggregate->aggregate.attributes.swap( o->attributes ); // change ownership					
-					if ( o->type->kind == TypeData::Aggregate ) {
-						type->aggInst.hoistType = o->type->aggregate.body;
-						type->aggInst.params = maybeCopy( o->type->aggregate.actuals );
-					} else {
-						type->aggInst.hoistType = o->type->enumeration.body;
-					} // if
-					type->qualifiers |= o->type->qualifiers;
-				} else {
-					type = o->type;
-				} // if
-				o->type = nullptr;						// change ownership
-			} else {
-				addTypeToType( o->type, type );
-			} // if
-		} // if
-		if ( o->bitfieldWidth ) {
-			bitfieldWidth = o->bitfieldWidth;
-		} // if
-
-		// there may be typedefs chained onto the type
-		if ( o->get_next() ) {
-			set_last( o->get_next()->clone() );
-		} // if
-	} // if
+	if ( !o ) return this;
+
+	checkSpecifiers( o );
+	copySpecifiers( o, copyattr );
+	if ( o->type ) {
+		type = ::addType( o->type, type, o->attributes );
+		o->type = nullptr;
+	} // if
+	if ( o->bitfieldWidth ) {
+		bitfieldWidth = o->bitfieldWidth;
+	} // if
+
+	// there may be typedefs chained onto the type
+	if ( o->next ) {
+		set_last( o->next->clone() );
+	} // if
+
 	delete o;
-
 	return this;
 }
 
 DeclarationNode * DeclarationNode::addEnumBase( DeclarationNode * o ) {
-	if ( o && o->type)  {
-		type->base= o->type;
+	if ( o && o->type ) {
+		type->base = o->type;
 	} // if
 	delete o;
@@ -745,5 +624,5 @@
 	if ( variable.tyClass != ast::TypeDecl::NUMBER_OF_KINDS ) {
 		if ( variable.assertions ) {
-			variable.assertions->appendList( assertions );
+			variable.assertions->set_last( assertions );
 		} else {
 			variable.assertions = assertions;
@@ -756,5 +635,5 @@
 	case TypeData::Symbolic:
 		if ( type->symbolic.assertions ) {
-			type->symbolic.assertions->appendList( assertions );
+			type->symbolic.assertions->set_last( assertions );
 		} else {
 			type->symbolic.assertions = assertions;
@@ -810,11 +689,5 @@
 DeclarationNode * DeclarationNode::setBase( TypeData * newType ) {
 	if ( type ) {
-		TypeData * prevBase = type;
-		TypeData * curBase = type->base;
-		while ( curBase != nullptr ) {
-			prevBase = curBase;
-			curBase = curBase->base;
-		} // while
-		prevBase->base = newType;
+		type->setLastBase( newType );
 	} else {
 		type = newType;
@@ -857,18 +730,5 @@
 		assert( p->type->kind == TypeData::Pointer || p->type->kind == TypeData::Reference );
 		if ( type ) {
-			switch ( type->kind ) {
-			case TypeData::Aggregate:
-			case TypeData::Enum:
-				p->type->base = new TypeData( TypeData::AggregateInst );
-				p->type->base->aggInst.aggregate = type;
-				if ( type->kind == TypeData::Aggregate ) {
-					p->type->base->aggInst.params = maybeCopy( type->aggregate.actuals );
-				} // if
-				p->type->base->qualifiers |= type->qualifiers;
-				break;
-
-			default:
-				p->type->base = type;
-			} // switch
+			p->type->base = makeNewBase( type );
 			type = nullptr;
 		} // if
@@ -880,31 +740,9 @@
 }
 
-static TypeData * findLast( TypeData * a ) {
-	assert( a );
-	TypeData * cur = a;
-	while ( cur->base ) {
-		cur = cur->base;
-	} // while
-	return cur;
-}
-
 DeclarationNode * DeclarationNode::addNewArray( DeclarationNode * a ) {
 	if ( ! a ) return this;
 	assert( a->type->kind == TypeData::Array );
-	TypeData * lastArray = findLast( a->type );
 	if ( type ) {
-		switch ( type->kind ) {
-		case TypeData::Aggregate:
-		case TypeData::Enum:
-			lastArray->base = new TypeData( TypeData::AggregateInst );
-			lastArray->base->aggInst.aggregate = type;
-			if ( type->kind == TypeData::Aggregate ) {
-				lastArray->base->aggInst.params = maybeCopy( type->aggregate.actuals );
-			} // if
-			lastArray->base->qualifiers |= type->qualifiers;
-			break;
-		default:
-			lastArray->base = type;
-		} // switch
+		a->type->setLastBase( makeNewBase( type ) );
 		type = nullptr;
 	} // if
@@ -960,38 +798,7 @@
 DeclarationNode * DeclarationNode::cloneBaseType( DeclarationNode * o, bool copyattr ) {
 	if ( ! o ) return nullptr;
-
 	o->copySpecifiers( this, copyattr );
 	if ( type ) {
-		TypeData * srcType = type;
-
-		// search for the base type by scanning off pointers and array designators
-		while ( srcType->base ) {
-			srcType = srcType->base;
-		} // while
-
-		TypeData * newType = srcType->clone();
-		if ( newType->kind == TypeData::AggregateInst ) {
-			// don't duplicate members
-			if ( newType->aggInst.aggregate->kind == TypeData::Enum ) {
-				delete newType->aggInst.aggregate->enumeration.constants;
-				newType->aggInst.aggregate->enumeration.constants = nullptr;
-				newType->aggInst.aggregate->enumeration.body = false;
-			} else {
-				assert( newType->aggInst.aggregate->kind == TypeData::Aggregate );
-				delete newType->aggInst.aggregate->aggregate.fields;
-				newType->aggInst.aggregate->aggregate.fields = nullptr;
-				newType->aggInst.aggregate->aggregate.body = false;
-			} // if
-			// don't hoist twice
-			newType->aggInst.hoistType = false;
-		} // if
-
-		newType->forall = maybeCopy( type->forall );
-		if ( ! o->type ) {
-			o->type = newType;
-		} else {
-			addTypeToType( newType, o->type );
-			delete newType;
-		} // if
+		o->type = ::cloneBaseType( type, o->type );
 	} // if
 	return o;
@@ -1099,5 +906,5 @@
 	std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList );
 
-	for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
+	for ( const DeclarationNode * cur = firstNode ; cur ; cur = cur->next ) {
 		try {
 			bool extracted_named = false;
@@ -1167,5 +974,5 @@
 	std::back_insert_iterator<std::vector<ast::ptr<ast::DeclWithType>>> out( outputList );
 
-	for ( const DeclarationNode * cur = firstNode; cur; cur = strict_next( cur ) ) {
+	for ( const DeclarationNode * cur = firstNode; cur; cur = cur->next ) {
 		try {
 			ast::Decl * decl = cur->build();
@@ -1217,5 +1024,5 @@
 	std::back_insert_iterator<std::vector<ast::ptr<ast::Type>>> out( outputList );
 
-	for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
+	for ( const DeclarationNode * cur = firstNode ; cur ; cur = cur->next ) {
 		try {
 			* out++ = cur->buildType();
Index: src/Parser/DeclarationNode.h
===================================================================
--- src/Parser/DeclarationNode.h	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/DeclarationNode.h	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -19,7 +19,7 @@
 
 struct TypeData;
-class InitializerNode;
-
-struct DeclarationNode : public ParseNode {
+struct InitializerNode;
+
+struct DeclarationNode final : public ParseList<DeclarationNode> {
 	// These enumerations must harmonize with their names in DeclarationNode.cc.
 	enum BasicType {
@@ -108,8 +108,4 @@
 	DeclarationNode * cloneBaseType( DeclarationNode * newdecl, bool = true );
 
-	DeclarationNode * appendList( DeclarationNode * node ) {
-		return (DeclarationNode *)set_last( node );
-	}
-
 	virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
 	virtual void printList( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
@@ -129,5 +125,5 @@
 	DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
 
-	DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }
+	const std::string * name = nullptr;
 
 	struct Variable_t {
@@ -144,6 +140,4 @@
 	};
 	StaticAssert_t assert;
-
-	BuiltinType builtin = NoBuiltinType;
 
 	TypeData * type = nullptr;
@@ -177,12 +171,4 @@
 }
 
-template<typename NodeType>
-NodeType * strict_next( NodeType * node ) {
-	ParseNode * next = node->get_next();
-	if ( nullptr == next ) return nullptr;
-	if ( NodeType * ret = dynamic_cast<NodeType *>( next ) ) return ret;
-	SemanticError( next->location, "internal error, non-homogeneous nodes founds in buildList processing." );
-}
-
 // This generic buildList is here along side its overloads.
 template<typename AstType, typename NodeType,
@@ -193,5 +179,5 @@
 	std::back_insert_iterator<Container<ast::ptr<AstType>, Args...>> out( output );
 
-	for ( NodeType * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
+	for ( NodeType * cur = firstNode ; cur ; cur = cur->next ) {
 		try {
 			AstType * node = dynamic_cast<AstType *>( maybeBuild( cur ) );
Index: src/Parser/ExpressionNode.h
===================================================================
--- src/Parser/ExpressionNode.h	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/ExpressionNode.h	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -18,14 +18,14 @@
 #include "ParseNode.h"
 
-class InitializerNode;
+struct InitializerNode;
 
-class ExpressionNode final : public ParseNode {
-public:
+struct ExpressionNode final : public ParseList<ExpressionNode> {
 	ExpressionNode( ast::Expr * expr = nullptr ) : expr( expr ) {}
 	virtual ~ExpressionNode() {}
 	virtual ExpressionNode * clone() const override {
 		if ( nullptr == expr ) return nullptr;
-		return static_cast<ExpressionNode*>(
-			(new ExpressionNode( ast::shallowCopy( expr.get() ) ))->set_next( maybeCopy( get_next() ) ));
+		ExpressionNode * node = new ExpressionNode( ast::shallowCopy( expr.get() ) );
+		node->next = maybeCopy( next );
+		return node;
 	}
 
Index: src/Parser/InitializerNode.cc
===================================================================
--- src/Parser/InitializerNode.cc	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/InitializerNode.cc	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -36,5 +36,5 @@
 		: expr( _expr ), aggregate( aggrp ), designator( des ), kids( nullptr ), maybeConstructed( true ), isDelete( false ) {
 	if ( aggrp )
-		kids = dynamic_cast< InitializerNode * >( get_next() );
+		kids = next;
 
 	if ( kids )
@@ -48,8 +48,8 @@
 
 	if ( aggrp )
-		kids = dynamic_cast< InitializerNode * >( get_next() );
+		kids = next;
 
 	if ( kids )
-		set_next( nullptr );
+		next = nullptr;
 } // InitializerNode::InitializerNode
 
@@ -73,5 +73,5 @@
 			while ( curdes != nullptr) {
 				curdes->printOneLine(os);
-				curdes = (ExpressionNode *)(curdes->get_next());
+				curdes = curdes->next;
 				if ( curdes ) os << ", ";
 			} // while
@@ -87,5 +87,5 @@
 
 	InitializerNode *moreInit;
-	if ( (moreInit = dynamic_cast< InitializerNode * >( get_next() ) ) ) {
+	if ( ( moreInit = next ) ) {
 		moreInit->printOneLine( os );
 	} // if
@@ -98,5 +98,5 @@
 		std::vector<ast::ptr<ast::Designation>> designlist;
 		InitializerNode * child = next_init();
-		for ( ; child != nullptr ; child = dynamic_cast< InitializerNode * >( child->get_next() ) ) {
+		for ( ; child != nullptr ; child = child->next ) {
 			std::deque<ast::ptr<ast::Expr>> desList;
 			buildList( child->designator, desList );
Index: src/Parser/InitializerNode.h
===================================================================
--- src/Parser/InitializerNode.h	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/InitializerNode.h	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -18,6 +18,5 @@
 #include "ParseNode.h"
 
-class InitializerNode : public ParseNode {
-public:
+struct InitializerNode final : public ParseList<InitializerNode> {
 	InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr );
 	InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr );
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/ParseNode.h	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -33,6 +33,6 @@
 
 struct DeclarationNode;
-class InitializerNode;
-class ExpressionNode;
+struct InitializerNode;
+struct ExpressionNode;
 struct StatementNode;
 
@@ -45,24 +45,33 @@
 extern YYLTYPE yylloc;
 
-class ParseNode {
-  public:
-	ParseNode() {};
-	virtual ~ParseNode() { delete next; delete name; };
+struct ParseNode {
+	ParseNode() {}
+	virtual ~ParseNode() {}
 	virtual ParseNode * clone() const = 0;
 
-	ParseNode * get_next() const { return next; }
-	ParseNode * set_next( ParseNode * newlink ) { next = newlink; return this; }
+	virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
 
-	ParseNode * get_last() {
-		ParseNode * current;
-		for ( current = this; current->get_next() != nullptr; current = current->get_next() );
+	static int indent_by;
+
+	CodeLocation location = yylloc;
+}; // ParseNode
+
+/// Only ever use in the form `struct NAME final : public ParseList<NAME>`!
+template<typename Next>
+struct ParseList : public ParseNode {
+	ParseList() {}
+	virtual ~ParseList() { delete next; };
+	virtual ParseList<Next> * clone() const = 0;
+
+	Next * get_last() {
+		Next * current = static_cast<Next *>( this );
+		while ( current->next != nullptr ) current = current->next;
 		return current;
 	}
-	ParseNode * set_last( ParseNode * newlast ) {
-		if ( newlast != nullptr ) get_last()->set_next( newlast );
-		return this;
+	Next * set_last( Next * newlast ) {
+		if ( newlast != nullptr ) get_last()->next = newlast;
+		return static_cast<Next *>( this );
 	}
 
-	virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
 	virtual void printList( std::ostream & os, int indent = 0 ) const {
 		print( os, indent );
@@ -70,10 +79,6 @@
 	}
 
-	static int indent_by;
-
-	ParseNode * next = nullptr;
-	const std::string * name = nullptr;
-	CodeLocation location = yylloc;
-}; // ParseNode
+	Next * next = nullptr;
+};
 
 // Must harmonize with OperName.
Index: src/Parser/StatementNode.cc
===================================================================
--- src/Parser/StatementNode.cc	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/StatementNode.cc	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -54,13 +54,13 @@
 		StatementNode * nextStmt = new StatementNode(
 			new ast::DeclStmt( decl->location, maybeBuild( decl ) ) );
-		set_next( nextStmt );
-		if ( decl->get_next() ) {
-			get_next()->set_next( new StatementNode( dynamic_cast< DeclarationNode * >(decl->get_next()) ) );
-			decl->set_next( 0 );
+		next = nextStmt;
+		if ( decl->next ) {
+			next->next = new StatementNode( decl->next );
+			decl->next = nullptr;
 		} // if
 	} else {
-		if ( decl->get_next() ) {
-			set_next( new StatementNode( dynamic_cast< DeclarationNode * >( decl->get_next() ) ) );
-			decl->set_next( 0 );
+		if ( decl->next ) {
+			next = new StatementNode( decl->next );
+			decl->next = nullptr;
 		} // if
 		agg = decl;
@@ -87,10 +87,10 @@
 	ClauseNode * prev = this;
 	// find end of list and maintain previous pointer
-	for ( ClauseNode * curr = prev; curr != nullptr; curr = (ClauseNode *)curr->get_next() ) {
-		ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr);
+	for ( ClauseNode * curr = prev; curr != nullptr; curr = curr->next ) {
+		ClauseNode * node = curr;
 		assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
 		prev = curr;
 	} // for
-	ClauseNode * node = dynamic_cast< ClauseNode * >(prev);
+	ClauseNode * node = prev;
 	// convert from StatementNode list to Statement list
 	std::vector<ast::ptr<ast::Stmt>> stmts;
@@ -332,6 +332,6 @@
 	clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
 
-	ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
-	targetExpr->set_next( nullptr );
+	ExpressionNode * next = targetExpr->next;
+	targetExpr->next = nullptr;
 	buildMoveList( next, clause->target_args );
 
Index: src/Parser/StatementNode.h
===================================================================
--- src/Parser/StatementNode.h	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/StatementNode.h	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -18,5 +18,5 @@
 #include "ParseNode.h"
 
-struct StatementNode final : public ParseNode {
+struct StatementNode final : public ParseList<StatementNode> {
 	StatementNode() : stmt( nullptr ) {}
 	StatementNode( ast::Stmt * stmt ) : stmt( stmt ) {}
@@ -39,12 +39,7 @@
 }; // StatementNode
 
-struct ClauseNode final : public ParseNode {
+struct ClauseNode final : public ParseList<ClauseNode> {
 	ClauseNode( ast::StmtClause * clause ) : clause( clause ) {}
 	virtual ~ClauseNode() {}
-
-	ClauseNode * set_last( ParseNode * newlast ) {
-		ParseNode::set_last( newlast );
-        return this;
-    }
 
 	virtual ClauseNode * clone() const final { assert( false ); return nullptr; }
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/TypeData.cc	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -479,4 +479,200 @@
 
 
+TypeData * TypeData::getLastBase() {
+	TypeData * cur = this;
+	while ( cur->base ) cur = cur->base;
+	return cur;
+}
+
+void TypeData::setLastBase( TypeData * newBase ) {
+	getLastBase()->base = newBase;
+}
+
+// Takes ownership of src.
+static void addQualifiersToType( TypeData * dst, TypeData * src ) {
+	if ( dst->base ) {
+		addQualifiersToType( dst->base, src );
+	} else if ( dst->kind == TypeData::Function ) {
+		dst->base = src;
+		src = nullptr;
+    } else {
+		dst->qualifiers |= src->qualifiers;
+		delete src;
+	} // if
+}
+
+// Takes ownership of all arguments, gives ownership of return value.
+TypeData * addQualifiers( TypeData * ltype, TypeData * rtype ) {
+	if ( ltype->forall ) {
+		if ( rtype->forall ) {
+			rtype->forall->set_last( ltype->forall );
+		} else if ( TypeData::Aggregate != rtype->kind ) {
+			rtype->forall = ltype->forall;
+		} else if ( rtype->aggregate.params ) {
+			rtype->aggregate.params->set_last( ltype->forall );
+		} else {
+			rtype->aggregate.params = ltype->forall;
+		}
+		ltype->forall = nullptr;
+	}
+
+	addQualifiersToType( rtype, ltype );
+	return rtype;
+}
+
+// Helper for addType and cloneBaseType.
+static void addTypeToType( TypeData *& dst, TypeData *& src ) {
+	if ( src->forall && dst->kind == TypeData::Function ) {
+		if ( dst->forall ) {
+			dst->forall->set_last( src->forall );
+		} else {
+			dst->forall = src->forall;
+		} // if
+		src->forall = nullptr;
+	} // if
+	if ( dst->base ) {
+		addTypeToType( dst->base, src );
+		return;
+	}
+	switch ( dst->kind ) {
+	case TypeData::Unknown:
+		src->qualifiers |= dst->qualifiers;
+		// LEAKS dst?
+		dst = src;
+		src = nullptr;
+		break;
+	case TypeData::Basic:
+		dst->qualifiers |= src->qualifiers;
+		if ( src->kind != TypeData::Unknown ) {
+			assert( src->kind == TypeData::Basic );
+
+			if ( dst->basictype == DeclarationNode::NoBasicType ) {
+				dst->basictype = src->basictype;
+			} else if ( src->basictype != DeclarationNode::NoBasicType ) {
+				SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
+					DeclarationNode::basicTypeNames[ dst->basictype ],
+					DeclarationNode::basicTypeNames[ src->basictype ] );
+			}
+			if ( dst->complextype == DeclarationNode::NoComplexType ) {
+				dst->complextype = src->complextype;
+			} else if ( src->complextype != DeclarationNode::NoComplexType ) {
+				SemanticError( yylloc, "multiple declaration types \"%s\" and \"%s\".",
+					DeclarationNode::complexTypeNames[ src->complextype ],
+					DeclarationNode::complexTypeNames[ src->complextype ] );
+			}
+			if ( dst->signedness == DeclarationNode::NoSignedness ) {
+				dst->signedness = src->signedness;
+			} else if ( src->signedness != DeclarationNode::NoSignedness ) {
+				SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
+					DeclarationNode::signednessNames[ dst->signedness ],
+					DeclarationNode::signednessNames[ src->signedness ] );
+			}
+			if ( dst->length == DeclarationNode::NoLength ) {
+				dst->length = src->length;
+			} else if ( dst->length == DeclarationNode::Long && src->length == DeclarationNode::Long ) {
+				dst->length = DeclarationNode::LongLong;
+			} else if ( src->length != DeclarationNode::NoLength ) {
+				SemanticError( yylloc, "conflicting type specifier \"%s\" and \"%s\".",
+					DeclarationNode::lengthNames[ dst->length ],
+					DeclarationNode::lengthNames[ src->length ] );
+			}
+		} // if
+		break;
+	default:
+		switch ( src->kind ) {
+		case TypeData::Aggregate:
+		case TypeData::Enum:
+			dst->base = new TypeData( TypeData::AggregateInst );
+			dst->base->aggInst.aggregate = src;
+			if ( src->kind == TypeData::Aggregate ) {
+				dst->base->aggInst.params = maybeCopy( src->aggregate.actuals );
+			} // if
+			dst->base->qualifiers |= src->qualifiers;
+			src = nullptr;
+			break;
+		default:
+			if ( dst->forall ) {
+				dst->forall->set_last( src->forall );
+			} else {
+				dst->forall = src->forall;
+			} // if
+			src->forall = nullptr;
+			dst->base = src;
+			src = nullptr;
+		} // switch
+	} // switch
+}
+
+// Takes ownership of all arguments, gives ownership of return value.
+TypeData * addType( TypeData * ltype, TypeData * rtype, std::vector<ast::ptr<ast::Attribute>> & attributes ) {
+	if ( rtype ) {
+		addTypeToType( rtype, ltype );
+		return rtype;
+	} else {
+		if ( ltype->kind == TypeData::Aggregate || ltype->kind == TypeData::Enum ) {
+			// Hide type information aggregate instances.
+			rtype = new TypeData( TypeData::AggregateInst );
+			rtype->aggInst.aggregate = ltype;
+			rtype->aggInst.aggregate->aggregate.attributes.swap( attributes ); // change ownership
+			if ( ltype->kind == TypeData::Aggregate ) {
+				rtype->aggInst.hoistType = ltype->aggregate.body;
+				rtype->aggInst.params = maybeCopy( ltype->aggregate.actuals );
+			} else {
+				rtype->aggInst.hoistType = ltype->enumeration.body;
+			} // if
+			rtype->qualifiers |= ltype->qualifiers;
+		} else {
+			rtype = ltype;
+		} // if
+		return rtype;
+	} // if
+}
+
+// Takes ownership of both arguments, gives ownership of return value.
+TypeData * cloneBaseType( TypeData * type, TypeData * other ) {
+	TypeData * newType = type->getLastBase()->clone();
+	if ( newType->kind == TypeData::AggregateInst ) {
+		// don't duplicate members
+		if ( newType->aggInst.aggregate->kind == TypeData::Enum ) {
+			delete newType->aggInst.aggregate->enumeration.constants;
+			newType->aggInst.aggregate->enumeration.constants = nullptr;
+			newType->aggInst.aggregate->enumeration.body = false;
+		} else {
+			assert( newType->aggInst.aggregate->kind == TypeData::Aggregate );
+			delete newType->aggInst.aggregate->aggregate.fields;
+			newType->aggInst.aggregate->aggregate.fields = nullptr;
+			newType->aggInst.aggregate->aggregate.body = false;
+		} // if
+		// don't hoist twice
+		newType->aggInst.hoistType = false;
+	} // if
+	newType->forall = maybeCopy( type->forall );
+
+	if ( other ) {
+		addTypeToType( other, newType );
+		delete newType;
+		return other;
+	} // if
+	return newType;
+}
+
+TypeData * makeNewBase( TypeData * type ) {
+	switch ( type->kind ) {
+	case TypeData::Aggregate:
+	case TypeData::Enum: {
+		TypeData * out = new TypeData( TypeData::AggregateInst );
+		out->aggInst.aggregate = type;
+		if ( TypeData::Aggregate == type->kind ) {
+			out->aggInst.params = maybeCopy( type->aggregate.actuals );
+		}
+		out->qualifiers |= type->qualifiers;
+		return out;
+	}
+	default:
+		return type;
+	} // switch
+}
+
+
 void buildForall(
 		const DeclarationNode * firstNode,
@@ -494,5 +690,5 @@
 	for ( auto i = outputList.begin() ;
 			i != outputList.end() ;
-			++i, n = (DeclarationNode*)n->get_next() ) {
+			++i, n = n->next ) {
 		// Only the object type class adds additional assertions.
 		if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
@@ -639,5 +835,5 @@
 	for ( auto i = outputForall.begin() ;
 			i != outputForall.end() ;
-			++i, n = (DeclarationNode*)n->get_next() ) {
+			++i, n = n->next ) {
 		// Only the object type class adds additional assertions.
 		if ( n->variable.tyClass != ast::TypeDecl::Otype ) {
@@ -1272,5 +1468,5 @@
 	auto members = ret->members.begin();
 	ret->hide = td->enumeration.hiding == EnumHiding::Hide ? ast::EnumDecl::EnumHiding::Hide : ast::EnumDecl::EnumHiding::Visible;
-	for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ), ++members ) {
+	for ( const DeclarationNode * cur = td->enumeration.constants; cur != nullptr; cur = cur->next, ++members ) {
 		if ( cur->enumInLine ) {
 			// Do Nothing
@@ -1500,7 +1696,7 @@
 	assert( ! function.params );
 	// loop over declaration first as it is easier to spot errors
-	for ( DeclarationNode * decl = function.oldDeclList; decl != nullptr; decl = dynamic_cast< DeclarationNode * >( decl->get_next() ) ) {
+	for ( DeclarationNode * decl = function.oldDeclList; decl != nullptr; decl = decl->next ) {
 		// scan ALL parameter names for each declaration name to check for duplicates
-		for ( DeclarationNode * param = function.idList; param != nullptr; param = dynamic_cast< DeclarationNode * >( param->get_next() ) ) {
+		for ( DeclarationNode * param = function.idList; param != nullptr; param = param->next ) {
 			if ( *decl->name == *param->name ) {
 				// type set => parameter name already transformed by a declaration names so there is a duplicate
@@ -1524,5 +1720,5 @@
 	//    rtb( a, b, c ) const char * b; {} => int rtn( int a, const char * b, int c ) {}
 
-	for ( DeclarationNode * param = function.idList; param != nullptr; param = dynamic_cast< DeclarationNode * >( param->get_next() ) ) {
+	for ( DeclarationNode * param = function.idList; param != nullptr; param = param->next ) {
 		if ( ! param->type ) {							// generate type int for empty parameter type
 			param->type = new TypeData( TypeData::Basic );
Index: src/Parser/TypeData.h
===================================================================
--- src/Parser/TypeData.h	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/TypeData.h	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -111,5 +111,13 @@
 
 	const std::string * leafName() const;
+
+	TypeData * getLastBase();
+	void setLastBase( TypeData * );
 };
+
+TypeData * addQualifiers( TypeData * ltype, TypeData * rtype );
+TypeData * addType( TypeData * ltype, TypeData * rtype, std::vector<ast::ptr<ast::Attribute>> & );
+TypeData * cloneBaseType( TypeData * type, TypeData * other );
+TypeData * makeNewBase( TypeData * type );
 
 ast::Type * typebuild( const TypeData * );
Index: src/Parser/lex.ll
===================================================================
--- src/Parser/lex.ll	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/lex.ll	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -10,6 +10,6 @@
  * Created On       : Sat Sep 22 08:58:10 2001
  * Last Modified By : Peter A. Buhr
- * Last Modified On : Tue Oct  3 17:10:57 2023
- * Update Count     : 773
+ * Last Modified On : Sat Feb 24 11:47:24 2024
+ * Update Count     : 777
  */
 
@@ -407,4 +407,5 @@
 ";"				{ ASCIIOP_RETURN(); }
 "."				{ ASCIIOP_RETURN(); }					// also operator
+"@@"			{ NAMEDOP_RETURN(ATTR); }				// CFA, attribute shorthand
 "..."			{ NAMEDOP_RETURN(ELLIPSIS); }
 
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/Parser/parser.yy	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Feb 23 18:25:46 2024
-// Update Count     : 6484
+// Last Modified On : Mon Mar  4 08:44:25 2024
+// Update Count     : 6562
 //
 
@@ -126,6 +126,6 @@
 	DeclarationNode * cl = (new DeclarationNode)->addType( typeSpec ); // typeSpec IS DELETED!!!
 
-	// Start at second variable in declaration list and clone the type specifiers for each variable..
-	for ( DeclarationNode * cur = dynamic_cast<DeclarationNode *>( declList->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) {
+	// Start at second variable in declaration list and clone the type specifiers for each variable.
+	for ( DeclarationNode * cur = declList->next ; cur != nullptr; cur = cur->next ) {
 		cl->cloneBaseType( cur, copyattr );				// cur is modified
 	} // for
@@ -139,5 +139,5 @@
 void distExt( DeclarationNode * declaration ) {
 	// distribute EXTENSION across all declarations
-	for ( DeclarationNode *iter = declaration; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) {
+	for ( DeclarationNode *iter = declaration ; iter != nullptr ; iter = iter->next ) {
 		iter->set_extension( true );
 	} // for
@@ -146,5 +146,5 @@
 void distInl( DeclarationNode * declaration ) {
 	// distribute INLINE across all declarations
-	for ( DeclarationNode *iter = declaration; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) {
+	for ( DeclarationNode *iter = declaration ; iter != nullptr ; iter = iter->next ) {
 		iter->set_inLine( true );
 	} // for
@@ -153,5 +153,5 @@
 void distQual( DeclarationNode * declaration, DeclarationNode * qualifiers ) {
 	// distribute qualifiers across all non-variable declarations in a distribution statemement
-	for ( DeclarationNode * iter = declaration; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) {
+	for ( DeclarationNode * iter = declaration ; iter != nullptr ; iter = iter->next ) {
 		// SKULLDUGGERY: Distributions are parsed inside out, so qualifiers are added to declarations inside out. Since
 		// addQualifiers appends to the back of the list, the forall clauses are in the wrong order (right to left). To
@@ -389,5 +389,5 @@
 %token LE GE EQ NE										// <=	>=	==	!=
 %token ANDAND OROR										// &&	||
-%token ELLIPSIS											// ...
+%token ATTR ELLIPSIS									// @@	...
 
 %token EXPassign	MULTassign	DIVassign	MODassign	// \=	*=	/=	%=
@@ -433,5 +433,5 @@
 %type<stmt> statement					labeled_statement			compound_statement
 %type<stmt> statement_decl				statement_decl_list			statement_list_nodecl
-%type<stmt> selection_statement			if_statement
+%type<stmt> selection_statement
 %type<clause> switch_clause_list_opt	switch_clause_list
 %type<expr> case_value
@@ -500,5 +500,5 @@
 %type<decl> cfa_identifier_parameter_declarator_tuple cfa_identifier_parameter_ptr
 
-%type<decl> cfa_parameter_declaration cfa_parameter_list cfa_parameter_ellipsis_list_opt
+%type<decl> cfa_parameter_declaration cfa_parameter_list cfa_parameter_list_ellipsis_opt
 
 %type<decl> cfa_typedef_declaration cfa_variable_declaration cfa_variable_specifier
@@ -508,5 +508,5 @@
 %type<decl> KR_parameter_list KR_parameter_list_opt
 
-%type<decl> parameter_declaration parameter_list parameter_type_list_opt
+%type<decl> parameter_declaration parameter_list parameter_list_ellipsis_opt
 
 %type<decl> paren_identifier paren_type
@@ -530,5 +530,5 @@
 %type<decl> type_parameter type_parameter_list type_initializer_opt
 
-%type<expr> type_parameters_opt type_list array_type_list
+%type<expr> type_parameters_opt type_list array_type_list // array_dimension_list
 
 %type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list
@@ -1246,9 +1246,16 @@
 	;
 
+// if, switch, and choose require parenthesis around the conditional because it can be followed by a statement.
+// For example, without parenthesis:
+//
+//    if x + y + z; => "if ( x + y ) + z" or "if ( x ) + y + z"
+//    switch ( S ) { ... } => switch ( S ) { compound literal... } ... or 
+
 selection_statement:
-			// pop causes a S/R conflict without separating the IF statement into a non-terminal even after resolving
-			// the inherent S/R conflict with THEN/ELSE.
-	push if_statement pop
-		{ $$ = $2; }
+	IF '(' conditional_declaration ')' statement		%prec THEN
+		// explicitly deal with the shift/reduce conflict on if/else
+		{ $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), nullptr ) ); }
+	| IF '(' conditional_declaration ')' statement ELSE statement
+		{ $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), maybe_build_compound( yylloc, $7 ) ) ); }
 	| SWITCH '(' comma_expression ')' case_clause
 		{ $$ = new StatementNode( build_switch( yylloc, true, $3, $5 ) ); }
@@ -1274,12 +1281,4 @@
 	| CHOOSE '(' comma_expression ')' '{' error '}'		// CFA, invalid syntax rule
 		{ SemanticError( yylloc, "syntax error, declarations can only appear before the list of case clauses." ); $$ = nullptr; }
-	;
-
-if_statement:
-	IF '(' conditional_declaration ')' statement		%prec THEN
-		// explicitly deal with the shift/reduce conflict on if/else
-		{ $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), nullptr ) ); }
-	| IF '(' conditional_declaration ')' statement ELSE statement
-		{ $$ = new StatementNode( build_if( yylloc, $3, maybe_build_compound( yylloc, $5 ), maybe_build_compound( yylloc, $7 ) ) ); }
 	;
 
@@ -1897,5 +1896,6 @@
 declaration_list:
 	declaration
-	| declaration_list declaration		{ $$ = $1->appendList( $2 ); }
+	| declaration_list declaration
+		{ $$ = $1->set_last( $2 ); }
 	;
 
@@ -1910,5 +1910,5 @@
 		{ $$ = $1; }
 	| KR_parameter_list c_declaration ';'
-		{ $$ = $1->appendList( $2 ); }
+		{ $$ = $1->set_last( $2 ); }
 	;
 
@@ -1968,5 +1968,5 @@
 		{ $$ = $2->addQualifiers( $1 )->addInitializer( $3 ); }
 	| cfa_variable_declaration pop ',' push identifier_or_type_name initializer_opt
-		{ $$ = $1->appendList( $1->cloneType( $5 )->addInitializer( $6 ) ); }
+		{ $$ = $1->set_last( $1->cloneType( $5 )->addInitializer( $6 ) ); }
 	;
 
@@ -1990,40 +1990,32 @@
 	| declaration_qualifier_list type_qualifier_list cfa_function_specifier
 		{ $$ = $3->addQualifiers( $1 )->addQualifiers( $2 ); }
-	| cfa_function_declaration ',' identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')'
+	| cfa_function_declaration ',' identifier_or_type_name '(' push cfa_parameter_list_ellipsis_opt pop ')'
 		{
 			// Append the return type at the start (left-hand-side) to each identifier in the list.
 			DeclarationNode * ret = new DeclarationNode;
 			ret->type = maybeCopy( $1->type->base );
-			$$ = $1->appendList( DeclarationNode::newFunction( $3, ret, $6, nullptr ) );
+			$$ = $1->set_last( DeclarationNode::newFunction( $3, ret, $6, nullptr ) );
 		}
 	;
 
 cfa_function_specifier:									// CFA
-//	'[' ']' identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' // S/R conflict
-//		{
-//			$$ = DeclarationNode::newFunction( $3, DeclarationNode::newTuple( 0 ), $6, nullptr, true );
-//		}
-//	'[' ']' identifier '(' push cfa_parameter_ellipsis_list_opt pop ')'
-//		{
-//			typedefTable.setNextIdentifier( *$5 );
-//			$$ = DeclarationNode::newFunction( $5, DeclarationNode::newTuple( 0 ), $8, nullptr, true );
-//		}
-//	| '[' ']' TYPEDEFname '(' push cfa_parameter_ellipsis_list_opt pop ')'
-//		{
-//			typedefTable.setNextIdentifier( *$5 );
-//			$$ = DeclarationNode::newFunction( $5, DeclarationNode::newTuple( 0 ), $8, nullptr, true );
-//		}
-//	| '[' ']' typegen_name
+	'[' ']' identifier '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
+		{ $$ = DeclarationNode::newFunction( $3,  DeclarationNode::newTuple( nullptr ), $6, nullptr )->addQualifiers( $9 ); }
+	| '[' ']' TYPEDEFname '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
+		{ $$ = DeclarationNode::newFunction( $3,  DeclarationNode::newTuple( nullptr ), $6, nullptr )->addQualifiers( $9 ); }
+	// | '[' ']' TYPEGENname '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
+	// 	{ $$ = DeclarationNode::newFunction( $3,  DeclarationNode::newTuple( nullptr ), $6, nullptr )->addQualifiers( $9 ); }
+
 		// identifier_or_type_name must be broken apart because of the sequence:
 		//
-		//   '[' ']' identifier_or_type_name '(' cfa_parameter_ellipsis_list_opt ')'
+		//   '[' ']' identifier_or_type_name '(' cfa_parameter_list_ellipsis_opt ')'
 		//   '[' ']' type_specifier
 		//
 		// type_specifier can resolve to just TYPEDEFname (e.g., typedef int T; int f( T );). Therefore this must be
 		// flattened to allow lookahead to the '(' without having to reduce identifier_or_type_name.
-	cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
+	| cfa_abstract_tuple identifier_or_type_name '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
 		// To obtain LR(1 ), this rule must be factored out from function return type (see cfa_abstract_declarator).
 		{ $$ = DeclarationNode::newFunction( $2, $1, $5, nullptr )->addQualifiers( $8 ); }
-	| cfa_function_return identifier_or_type_name '(' push cfa_parameter_ellipsis_list_opt pop ')' attribute_list_opt
+	| cfa_function_return identifier_or_type_name '(' push cfa_parameter_list_ellipsis_opt pop ')' attribute_list_opt
 		{ $$ = DeclarationNode::newFunction( $2, $1, $5, nullptr )->addQualifiers( $8 ); }
 	;
@@ -2032,7 +2024,7 @@
 	'[' push cfa_parameter_list pop ']'
 		{ $$ = DeclarationNode::newTuple( $3 ); }
-	| '[' push cfa_parameter_list pop ',' push cfa_abstract_parameter_list pop ']'
+	| '[' push cfa_parameter_list ',' cfa_abstract_parameter_list pop ']'
 		// To obtain LR(1 ), the last cfa_abstract_parameter_list is added into this flattened rule to lookahead to the ']'.
-		{ $$ = DeclarationNode::newTuple( $3->appendList( $7 ) ); }
+		{ $$ = DeclarationNode::newTuple( $3->set_last( $5 ) ); }
 	;
 
@@ -2048,8 +2040,8 @@
 			$$ = $2->addTypedef();
 		}
-	| cfa_typedef_declaration pop ',' push identifier
-		{
-			typedefTable.addToEnclosingScope( *$5, TYPEDEFname, "cfa_typedef_declaration 3" );
-			$$ = $1->appendList( $1->cloneType( $5 ) );
+	| cfa_typedef_declaration ',' identifier
+		{
+			typedefTable.addToEnclosingScope( *$3, TYPEDEFname, "cfa_typedef_declaration 3" );
+			$$ = $1->set_last( $1->cloneType( $3 ) );
 		}
 	;
@@ -2069,5 +2061,5 @@
 		{
 			typedefTable.addToEnclosingScope( *$3->name, TYPEDEFname, "typedef_declaration 2" );
-			$$ = $1->appendList( $1->cloneBaseType( $3 )->addTypedef() );
+			$$ = $1->set_last( $1->cloneBaseType( $3 )->addTypedef() );
 		}
 	| type_qualifier_list TYPEDEF type_specifier declarator // remaining OBSOLESCENT (see 2 )
@@ -2123,5 +2115,5 @@
 
 	| declaring_list ',' attribute_list_opt declarator asm_name_opt initializer_opt
-		{ $$ = $1->appendList( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) ); }
+		{ $$ = $1->set_last( $4->addQualifiers( $3 )->addAsmName( $5 )->addInitializer( $6 ) ); }
 	;
 
@@ -2587,5 +2579,5 @@
 		{ $$ = nullptr; }
 	| field_declaration_list_opt field_declaration
-		{ $$ = $1 ? $1->appendList( $2 ) : $2; }
+		{ $$ = $1 ? $1->set_last( $2 ) : $2; }
 	;
 
@@ -2635,5 +2627,5 @@
 	| field_declarator
 	| field_declaring_list_opt ',' attribute_list_opt field_declarator
-		{ $$ = $1->appendList( $4->addQualifiers( $3 ) ); }
+		{ $$ = $1->set_last( $4->addQualifiers( $3 ) ); }
 	;
 
@@ -2657,5 +2649,5 @@
 	| field_abstract
 	| field_abstract_list_opt ',' attribute_list_opt field_abstract
-		{ $$ = $1->appendList( $4->addQualifiers( $3 ) ); }
+		{ $$ = $1->set_last( $4->addQualifiers( $3 ) ); }
 	;
 
@@ -2670,5 +2662,5 @@
 		{ $$ = $1->addName( $2 ); }
 	| cfa_field_declaring_list ',' identifier_or_type_name
-		{ $$ = $1->appendList( $1->cloneType( $3 ) ); }
+		{ $$ = $1->set_last( $1->cloneType( $3 ) ); }
 	;
 
@@ -2677,5 +2669,5 @@
 	cfa_abstract_declarator_tuple
 	| cfa_field_abstract_list ','
-		{ $$ = $1->appendList( $1->cloneType( 0 ) ); }
+		{ $$ = $1->set_last( $1->cloneType( 0 ) ); }
 	;
 
@@ -2690,4 +2682,8 @@
 		{ $$ = $2; }
 	;
+
+// ***********
+// Enumeration
+// ***********
 
 enum_type:
@@ -2719,5 +2715,5 @@
 	| ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
 		{
-			if ( $3 && ($3->storageClasses.any() || $3->type->qualifiers.val != 0 )) {
+			if ( $3 && ($3->storageClasses.any() || $3->type->qualifiers.val != 0) ) {
 				SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
 			}
@@ -2769,7 +2765,7 @@
 		{ $$ = DeclarationNode::newEnumInLine( *$2->type->symbolic.name ); }
 	| enumerator_list ',' visible_hide_opt identifier_or_type_name enumerator_value_opt
-		{ $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); }
+		{ $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); }
 	| enumerator_list ',' INLINE type_name enumerator_value_opt
-		{ $$ = $1->appendList( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); }
+		{ $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); }
 	;
 
@@ -2789,38 +2785,9 @@
 	;
 
-cfa_parameter_ellipsis_list_opt:						// CFA, abstract + real
-	// empty
-		{ $$ = DeclarationNode::newBasicType( DeclarationNode::Void ); }
-	| ELLIPSIS
-		{ $$ = nullptr; }
-	| cfa_abstract_parameter_list
-	| cfa_parameter_list
-	| cfa_parameter_list pop ',' push cfa_abstract_parameter_list
-		{ $$ = $1->appendList( $5 ); }
-	| cfa_abstract_parameter_list pop ',' push ELLIPSIS
-		{ $$ = $1->addVarArgs(); }
-	| cfa_parameter_list pop ',' push ELLIPSIS
-		{ $$ = $1->addVarArgs(); }
-	;
-
-cfa_parameter_list:										// CFA
-		// To obtain LR(1) between cfa_parameter_list and cfa_abstract_tuple, the last cfa_abstract_parameter_list is
-		// factored out from cfa_parameter_list, flattening the rules to get lookahead to the ']'.
-	cfa_parameter_declaration
-	| cfa_abstract_parameter_list pop ',' push cfa_parameter_declaration
-		{ $$ = $1->appendList( $5 ); }
-	| cfa_parameter_list pop ',' push cfa_parameter_declaration
-		{ $$ = $1->appendList( $5 ); }
-	| cfa_parameter_list pop ',' push cfa_abstract_parameter_list pop ',' push cfa_parameter_declaration
-		{ $$ = $1->appendList( $5 )->appendList( $9 ); }
-	;
-
-cfa_abstract_parameter_list:							// CFA, new & old style abstract
-	cfa_abstract_parameter_declaration
-	| cfa_abstract_parameter_list pop ',' push cfa_abstract_parameter_declaration
-		{ $$ = $1->appendList( $5 ); }
-	;
-
-parameter_type_list_opt:
+// *******************
+// Function parameters
+// *******************
+
+parameter_list_ellipsis_opt:
 	// empty
 		{ $$ = nullptr; }
@@ -2833,14 +2800,62 @@
 
 parameter_list:											// abstract + real
-	abstract_parameter_declaration
-	| parameter_declaration
+	parameter_declaration
+	| abstract_parameter_declaration
+	| parameter_list ',' parameter_declaration
+		{ $$ = $1->set_last( $3 ); }
 	| parameter_list ',' abstract_parameter_declaration
-		{ $$ = $1->appendList( $3 ); }
-	| parameter_list ',' parameter_declaration
-		{ $$ = $1->appendList( $3 ); }
+		{ $$ = $1->set_last( $3 ); }
+	;
+
+cfa_parameter_list_ellipsis_opt:						// CFA, abstract + real
+	// empty
+		{ $$ = DeclarationNode::newBasicType( DeclarationNode::Void ); }
+	| ELLIPSIS
+		{ $$ = nullptr; }
+	| cfa_parameter_list
+	| cfa_abstract_parameter_list
+	| cfa_parameter_list ',' cfa_abstract_parameter_list
+		{ $$ = $1->set_last( $3 ); }
+	| cfa_parameter_list ',' ELLIPSIS
+		{ $$ = $1->addVarArgs(); }
+	| cfa_abstract_parameter_list ',' ELLIPSIS
+		{ $$ = $1->addVarArgs(); }
+	;
+
+cfa_parameter_list:										// CFA
+		// To obtain LR(1) between cfa_parameter_list and cfa_abstract_tuple, the last cfa_abstract_parameter_list is
+		// factored out from cfa_parameter_list, flattening the rules to get lookahead to the ']'.
+	cfa_parameter_declaration
+	| cfa_abstract_parameter_list ',' cfa_parameter_declaration
+		{ $$ = $1->set_last( $3 ); }
+	| cfa_parameter_list ',' cfa_parameter_declaration
+		{ $$ = $1->set_last( $3 ); }
+	| cfa_parameter_list ',' cfa_abstract_parameter_list ',' cfa_parameter_declaration
+		{ $$ = $1->set_last( $3 )->set_last( $5 ); }
+	;
+
+cfa_abstract_parameter_list:							// CFA, new & old style abstract
+	cfa_abstract_parameter_declaration
+	| cfa_abstract_parameter_list ',' cfa_abstract_parameter_declaration
+		{ $$ = $1->set_last( $3 ); }
 	;
 
 // Provides optional identifier names (abstract_declarator/variable_declarator), no initialization, different semantics
 // for typedef name by using type_parameter_redeclarator instead of typedef_redeclarator, and function prototypes.
+
+parameter_declaration:
+		// No SUE declaration in parameter list.
+	declaration_specifier_nobody identifier_parameter_declarator default_initializer_opt
+		{ $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
+	| declaration_specifier_nobody type_parameter_redeclarator default_initializer_opt
+		{ $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
+	;
+
+abstract_parameter_declaration:
+	declaration_specifier_nobody default_initializer_opt
+		{ $$ = $1->addInitializer( $2 ? new InitializerNode( $2 ) : nullptr ); }
+	| declaration_specifier_nobody abstract_parameter_declarator default_initializer_opt
+		{ $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
+	;
 
 cfa_parameter_declaration:								// CFA, new & old style parameter declaration
@@ -2866,19 +2881,4 @@
 	;
 
-parameter_declaration:
-		// No SUE declaration in parameter list.
-	declaration_specifier_nobody identifier_parameter_declarator default_initializer_opt
-		{ $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
-	| declaration_specifier_nobody type_parameter_redeclarator default_initializer_opt
-		{ $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
-	;
-
-abstract_parameter_declaration:
-	declaration_specifier_nobody default_initializer_opt
-		{ $$ = $1->addInitializer( $2 ? new InitializerNode( $2 ) : nullptr ); }
-	| declaration_specifier_nobody abstract_parameter_declarator default_initializer_opt
-		{ $$ = $2->addType( $1 )->addInitializer( $3 ? new InitializerNode( $3 ) : nullptr ); }
-	;
-
 // ISO/IEC 9899:1999 Section 6.9.1(6) : "An identifier declared as a typedef name shall not be redeclared as a
 // parameter." Because the scope of the K&R-style parameter-list sees the typedef first, the following is based only on
@@ -2889,5 +2889,5 @@
 		{ $$ = DeclarationNode::newName( $1 ); }
 	| identifier_list ',' identifier
-		{ $$ = $1->appendList( DeclarationNode::newName( $3 ) ); }
+		{ $$ = $1->set_last( DeclarationNode::newName( $3 ) ); }
 	;
 
@@ -2990,5 +2990,5 @@
 	type_parameter
 	| type_parameter_list ',' type_parameter
-		{ $$ = $1->appendList( $3 ); }
+		{ $$ = $1->set_last( $3 ); }
 	;
 
@@ -3063,5 +3063,5 @@
 	assertion
 	| assertion_list assertion
-		{ $$ = $1->appendList( $2 ); }
+		{ $$ = $1->set_last( $2 ); }
 	;
 
@@ -3091,5 +3091,5 @@
 		{ $$ = $3->addQualifiers( $1 ); }
 	| type_declaring_list ',' type_declarator
-		{ $$ = $1->appendList( $3->copySpecifiers( $1 ) ); }
+		{ $$ = $1->set_last( $3->copySpecifiers( $1 ) ); }
 	;
 
@@ -3134,5 +3134,5 @@
 	trait_declaration
 	| trait_declaration_list pop push trait_declaration
-		{ $$ = $1->appendList( $4 ); }
+		{ $$ = $1->set_last( $4 ); }
 	;
 
@@ -3146,5 +3146,5 @@
 	| cfa_function_specifier
 	| cfa_trait_declaring_list pop ',' push identifier_or_type_name
-		{ $$ = $1->appendList( $1->cloneType( $5 ) ); }
+		{ $$ = $1->set_last( $1->cloneType( $5 ) ); }
 	;
 
@@ -3153,5 +3153,5 @@
 		{ $$ = $2->addType( $1 ); }
 	| trait_declaring_list pop ',' push declarator
-		{ $$ = $1->appendList( $1->cloneBaseType( $5 ) ); }
+		{ $$ = $1->set_last( $1->cloneBaseType( $5 ) ); }
 	;
 
@@ -3161,5 +3161,5 @@
 	// empty, input file
 	| external_definition_list
-		{ parseTree = parseTree ? parseTree->appendList( $1 ) : $1;	}
+		{ parseTree = parseTree ? parseTree->set_last( $1 ) : $1;	}
 	;
 
@@ -3168,5 +3168,5 @@
 		{ $$ = $2; }
 	| external_definition_list push external_definition pop
-		{ $$ = $1 ? $1->appendList( $3 ) : $3; }
+		{ $$ = $1 ? $1->set_last( $3 ) : $3; }
 	;
 
@@ -3395,4 +3395,8 @@
 	ATTRIBUTE '(' '(' attribute_name_list ')' ')'
 		{ $$ = $4; }
+	| ATTRIBUTE '(' attribute_name_list ')'				// CFA
+		{ $$ = $3; }
+	| ATTR '(' attribute_name_list ')'					// CFA
+		{ $$ = $3; }
 	;
 
@@ -3499,7 +3503,7 @@
 
 variable_function:
-	'(' variable_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	'(' variable_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $2->addParamList( $5 ); }
-	| '(' attribute_list variable_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	| '(' attribute_list variable_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
 	| '(' variable_function ')'							// redundant parenthesis
@@ -3522,9 +3526,9 @@
 
 function_no_ptr:
-	paren_identifier '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	paren_identifier '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $1->addParamList( $3 ); }
-	| '(' function_ptr ')' '(' parameter_type_list_opt ')'
+	| '(' function_ptr ')' '(' parameter_list_ellipsis_opt ')'
 		{ $$ = $2->addParamList( $5 ); }
-	| '(' attribute_list function_ptr ')' '(' parameter_type_list_opt ')'
+	| '(' attribute_list function_ptr ')' '(' parameter_list_ellipsis_opt ')'
 		{ $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
 	| '(' function_no_ptr ')'							// redundant parenthesis
@@ -3576,7 +3580,7 @@
 	paren_identifier '(' identifier_list ')'			// function_declarator handles empty parameter
 		{ $$ = $1->addIdList( $3 ); }
-	| '(' KR_function_ptr ')' '(' parameter_type_list_opt ')'
+	| '(' KR_function_ptr ')' '(' parameter_list_ellipsis_opt ')'
 		{ $$ = $2->addParamList( $5 ); }
-	| '(' attribute_list KR_function_ptr ')' '(' parameter_type_list_opt ')'
+	| '(' attribute_list KR_function_ptr ')' '(' parameter_list_ellipsis_opt ')'
 		{ $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
 	| '(' KR_function_no_ptr ')'						// redundant parenthesis
@@ -3668,7 +3672,7 @@
 
 variable_type_function:
-	'(' variable_type_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	'(' variable_type_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $2->addParamList( $5 ); }
-	| '(' attribute_list variable_type_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	| '(' attribute_list variable_type_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
 	| '(' variable_type_function ')'					// redundant parenthesis
@@ -3691,9 +3695,9 @@
 
 function_type_no_ptr:
-	paren_type '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	paren_type '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $1->addParamList( $3 ); }
-	| '(' function_type_ptr ')' '(' parameter_type_list_opt ')'
+	| '(' function_type_ptr ')' '(' parameter_list_ellipsis_opt ')'
 		{ $$ = $2->addParamList( $5 ); }
-	| '(' attribute_list function_type_ptr ')' '(' parameter_type_list_opt ')'
+	| '(' attribute_list function_type_ptr ')' '(' parameter_list_ellipsis_opt ')'
 		{ $$ = $3->addQualifiers( $2 )->addParamList( $6 ); }
 	| '(' function_type_no_ptr ')'						// redundant parenthesis
@@ -3738,5 +3742,6 @@
 		{ $$ = $1->addQualifiers( $2 ); }
 	| '&' MUTEX paren_identifier attribute_list_opt
-		{ $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
+		{ $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ),
+															OperKinds::AddressOf ) )->addQualifiers( $4 ); }
 	| identifier_parameter_ptr
 	| identifier_parameter_array attribute_list_opt
@@ -3767,7 +3772,7 @@
 
 identifier_parameter_function:
-	paren_identifier '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	paren_identifier '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $1->addParamList( $3 ); }
-	| '(' identifier_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	| '(' identifier_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $2->addParamList( $5 ); }
 	| '(' identifier_parameter_function ')'				// redundant parenthesis
@@ -3788,5 +3793,6 @@
 		{ $$ = $1->addQualifiers( $2 ); }
 	| '&' MUTEX typedef_name attribute_list_opt
-		{ $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
+		{ $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( ast::CV::Mutex ),
+															OperKinds::AddressOf ) )->addQualifiers( $4 ); }
 	| type_parameter_ptr
 	| type_parameter_array attribute_list_opt
@@ -3820,7 +3826,7 @@
 
 type_parameter_function:
-	typedef_name '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	typedef_name '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $1->addParamList( $3 ); }
-	| '(' type_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	| '(' type_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $2->addParamList( $5 ); }
 	;
@@ -3870,7 +3876,7 @@
 
 abstract_function:
-	'(' parameter_type_list_opt ')'			// empty parameter list OBSOLESCENT (see 3)
+	'(' parameter_list_ellipsis_opt ')'			// empty parameter list OBSOLESCENT (see 3)
 		{ $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
-	| '(' abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	| '(' abstract_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $2->addParamList( $5 ); }
 	| '(' abstract_function ')'							// redundant parenthesis
@@ -3888,8 +3894,17 @@
 		{ $$ = DeclarationNode::newArray( $3, nullptr, false )->addArray( DeclarationNode::newArray( $6, nullptr, false ) ); }
 		// { SemanticError( yylloc, "New array dimension is currently unimplemented." ); $$ = nullptr; }
+
+		// If needed, the following parses and does not use comma_expression, so the array structure can be built.
+	// | '[' push assignment_expression pop ',' push array_dimension_list pop ']' // CFA
+
 	| '[' push array_type_list pop ']'					// CFA
 		{ $$ = DeclarationNode::newArray( $3, nullptr, false ); }
 	| multi_array_dimension
 	;
+
+// array_dimension_list:
+// 	assignment_expression
+// 	| array_dimension_list ',' assignment_expression
+// 	;
 
 array_type_list:
@@ -3993,7 +4008,7 @@
 
 abstract_parameter_function:
-	'(' parameter_type_list_opt ')'			// empty parameter list OBSOLESCENT (see 3)
+	'(' parameter_list_ellipsis_opt ')'			// empty parameter list OBSOLESCENT (see 3)
 		{ $$ = DeclarationNode::newFunction( nullptr, nullptr, $2, nullptr ); }
-	| '(' abstract_parameter_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	| '(' abstract_parameter_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $2->addParamList( $5 ); }
 	| '(' abstract_parameter_function ')'				// redundant parenthesis
@@ -4072,5 +4087,5 @@
 
 variable_abstract_function:
-	'(' variable_abstract_ptr ')' '(' parameter_type_list_opt ')' // empty parameter list OBSOLESCENT (see 3)
+	'(' variable_abstract_ptr ')' '(' parameter_list_ellipsis_opt ')' // empty parameter list OBSOLESCENT (see 3)
 		{ $$ = $2->addParamList( $5 ); }
 	| '(' variable_abstract_function ')'				// redundant parenthesis
@@ -4158,5 +4173,5 @@
 //
 //		cfa_abstract_tuple identifier_or_type_name
-//		'[' cfa_parameter_list ']' identifier_or_type_name '(' cfa_parameter_ellipsis_list_opt ')'
+//		'[' cfa_parameter_list ']' identifier_or_type_name '(' cfa_parameter_list_ellipsis_opt ')'
 //
 // since a function return type can be syntactically identical to a tuple type:
@@ -4224,9 +4239,9 @@
 
 cfa_abstract_function:									// CFA
-//	'[' ']' '(' cfa_parameter_ellipsis_list_opt ')'
-//		{ $$ = DeclarationNode::newFunction( nullptr, DeclarationNode::newTuple( nullptr ), $4, nullptr ); }
-	cfa_abstract_tuple '(' push cfa_parameter_ellipsis_list_opt pop ')'
+	'[' ']' '(' cfa_parameter_list_ellipsis_opt ')'
+		{ $$ = DeclarationNode::newFunction( nullptr, DeclarationNode::newTuple( nullptr ), $4, nullptr ); }
+	| cfa_abstract_tuple '(' push cfa_parameter_list_ellipsis_opt pop ')'
 		{ $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); }
-	| cfa_function_return '(' push cfa_parameter_ellipsis_list_opt pop ')'
+	| cfa_function_return '(' push cfa_parameter_list_ellipsis_opt pop ')'
 		{ $$ = DeclarationNode::newFunction( nullptr, $1, $4, nullptr ); }
 	;
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision bbf2cb164e26be1589f185df9bf81b21c503c1d2)
+++ src/ResolvExpr/Resolver.cc	(revision f6e8c672a67785468988dfd68943c378679cbddf)
@@ -412,4 +412,5 @@
 
 	void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
+	bool shouldGenCtorInit( const ast::ObjectDecl * ) const;
 
 	void beginScope() { managedTypes.beginScope(); }
@@ -581,4 +582,15 @@
 }
 
+bool Resolver::shouldGenCtorInit( ast::ObjectDecl const * decl ) const {
+	// If we shouldn't try to construct it, then don't.
+	if ( !InitTweak::tryConstruct( decl ) ) return false;
+	// Otherwise, if it is a managed type, we may construct it.
+	if ( managedTypes.isManaged( decl ) ) return true;
+	// Skip construction if it is trivial at compile-time.
+	if ( InitTweak::isConstExpr( decl->init ) ) return false;
+	// Skip construction for local declarations.
+	return ( !isInFunction() || decl->storage.is_static );
+}
+
 const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) {
 	// To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
@@ -615,5 +627,5 @@
 			// this object in visitor pass, thus disabling CtorInit codegen.
 			// this happens on aggregate members and function parameters.
-			if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) {
+			if ( shouldGenCtorInit( mutDecl ) ) {
 				// constructed objects cannot be designated
 				if ( InitTweak::isDesignated( mutDecl->init ) ) {
