Index: doc/LaTeXmacros/common.sty
===================================================================
--- doc/LaTeXmacros/common.sty	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ doc/LaTeXmacros/common.sty	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -11,6 +11,6 @@
 %% Created On       : Sat Apr  9 10:06:17 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Sun Jan 21 13:17:48 2024
-%% Update Count     : 633
+%% Last Modified On : Sun Feb 25 17:37:46 2024
+%% Update Count     : 640
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -40,13 +40,15 @@
 \newcommand{\CFA}{\protect\CFAIcon\xspace}				% CFA symbolic name
 \newcommand{\CFL}{\textrm{Cforall}\xspace}				% Cforall non-icon name
-\newcommand{\Celeven}{\textrm{C11}\xspace}				% C11 symbolic name
+\newcommand{\Celeven}{\textrm{C1\!1}\xspace}			% C11 symbolic name
+
 \newcommand{\CCIcon}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}} % C++ icon
-\newcommand{\CC}[1][]{\protect\CCIcon{#1}\xspace}		% C++ symbolic name
-\newcommand{\Cpp}[1][]{\CC{#1}}							% C++ synonym
 % numbers disallowed in latex variables names => use number names
-\newcommand{\CCeleven}{\protect\CCIcon{11}\xspace}		% C++11 symbolic name
+\newcommand{\CCeleven}{\protect\CCIcon{1\!1}\xspace}	% C++11 symbolic name
 \newcommand{\CCfourteen}{\protect\CCIcon{14}\xspace}	% C++14 symbolic name
 \newcommand{\CCseventeen}{\protect\CCIcon{17}\xspace}	% C++17 symbolic name
 \newcommand{\CCtwenty}{\protect\CCIcon{20}\xspace}		% C++20 symbolic name
+\newcommand{\CC}[1][]{\protect\CCIcon{#1}\xspace}		% C++ symbolic name
+\newcommand{\Cpp}[1][]{\CC{#1}}							% C++ synonym
+
 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\relsize{2}$^\sharp$}\xspace} % C# symbolic name
 
@@ -293,5 +295,4 @@
 xleftmargin=\parindentlnth,				% indent code to paragraph indentation
 extendedchars=true,						% allow ASCII characters in the range 128-255
-escapechar=§,							% LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'
 mathescape=false,						% disable LaTeX math escape in CFA code $...$
 keepspaces=true,						%
@@ -304,7 +305,8 @@
 literate=
 %  {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1
-  {-}{\raisebox{-1pt}{\texttt{-}}}1
+  {-}{\raisebox{-1pt}{\ttfamily-}}1
   {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
   {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1
+  {'}{\ttfamily'\!}1
   {`}{\ttfamily\upshape\hspace*{-0.3ex}`}1
   {<-}{$\leftarrow$}2
@@ -318,5 +320,5 @@
 \lstset{
 language=CFA,
-%moredelim=**[is][\color{red}]{@}{@},	% red highlighting @...@
+escapechar=§,							% LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'
 moredelim=**[is][\color{red}]{®}{®},	% red highlighting ®...® (registered trademark symbol) emacs: C-q M-.
 %moredelim=**[is][\color{blue}]{ß}{ß},	% blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_
@@ -328,10 +330,11 @@
 % inline code ©...© (copyright symbol) emacs: C-q M-)
 \lstMakeShortInline©					% single-character for \lstinline
+
 \else% regular ASCI characters
+
 \lstnewenvironment{cfa}[1][]{% necessary
 \lstset{
 language=CFA,
 escapechar=\$,							% LaTeX escape in CFA code
-mathescape=false,						% LaTeX math escape in CFA code $...$
 moredelim=**[is][\color{red}]{@}{@},	% red highlighting @...@
 }% lstset
Index: doc/LaTeXmacros/common.tex
===================================================================
--- doc/LaTeXmacros/common.tex	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ doc/LaTeXmacros/common.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -11,6 +11,6 @@
 %% Created On       : Sat Apr  9 10:06:17 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Wed Jan 24 08:43:57 2024
-%% Update Count     : 593
+%% Last Modified On : Sun Feb 25 18:11:56 2024
+%% Update Count     : 614
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -40,13 +40,15 @@
 \newcommand{\CFA}{\protect\CFAIcon\xspace}				% CFA symbolic name
 \newcommand{\CFL}{\textrm{Cforall}\xspace}				% Cforall non-icon name
-\newcommand{\Celeven}{\textrm{C11}\xspace}				% C11 symbolic name
+\newcommand{\Celeven}{\textrm{C1\!1}\xspace}			% C11 symbolic name
+
 \newcommand{\CCIcon}{\textrm{C}\kern-.1em\hbox{+\kern-.25em+}} % C++ icon
-\newcommand{\CC}[1][]{\protect\CCIcon{#1}\xspace}		% C++ symbolic name
-\newcommand{\Cpp}[1][]{\CC{#1}}							% C++ synonym
 % numbers disallowed in latex variables names => use number names
-\newcommand{\CCeleven}{\protect\CCIcon{11}\xspace}		% C++11 symbolic name
+\newcommand{\CCeleven}{\protect\CCIcon{1\!1}\xspace}	% C++11 symbolic name
 \newcommand{\CCfourteen}{\protect\CCIcon{14}\xspace}	% C++14 symbolic name
 \newcommand{\CCseventeen}{\protect\CCIcon{17}\xspace}	% C++17 symbolic name
 \newcommand{\CCtwenty}{\protect\CCIcon{20}\xspace}		% C++20 symbolic name
+\newcommand{\CC}[1][]{\protect\CCIcon{#1}\xspace}		% C++ symbolic name
+\newcommand{\Cpp}[1][]{\CC{#1}}							% C++ synonym
+
 \newcommand{\Csharp}{C\raisebox{-0.7ex}{\relsize{2}$^\sharp$}\xspace} % C# symbolic name
 
@@ -297,5 +299,4 @@
 xleftmargin=\parindentlnth,				% indent code to paragraph indentation
 extendedchars=true,						% allow ASCII characters in the range 128-255
-escapechar=§,							% LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'
 mathescape=false,						% disable LaTeX math escape in CFA code $...$
 keepspaces=true,						%
@@ -308,7 +309,8 @@
 literate=
 %  {-}{\makebox[1ex][c]{\raisebox{0.4ex}{\rule{0.75ex}{0.1ex}}}}1
-  {-}{\raisebox{-1pt}{\texttt{-}}}1
+  {-}{\raisebox{-1pt}{\ttfamily-}}1
   {^}{\raisebox{0.6ex}{$\scriptstyle\land\,$}}1
   {~}{\raisebox{0.3ex}{$\scriptstyle\sim\,$}}1
+  {'}{\ttfamily'\!}1
   {`}{\ttfamily\upshape\hspace*{-0.3ex}`}1
   {<-}{$\leftarrow$}2
@@ -322,5 +324,5 @@
 \lstset{
 language=CFA,
-%moredelim=**[is][\color{red}]{@}{@},	% red highlighting @...@
+escapechar=§,							% LaTeX escape in CFA code §...§ (section symbol), emacs: C-q M-'
 moredelim=**[is][\color{red}]{®}{®},	% red highlighting ®...® (registered trademark symbol) emacs: C-q M-.
 %moredelim=**[is][\color{blue}]{ß}{ß},	% blue highlighting ß...ß (sharp s symbol) emacs: C-q M-_
@@ -332,10 +334,11 @@
 % inline code ©...© (copyright symbol) emacs: C-q M-)
 \lstMakeShortInline©					% single-character for \lstinline
+
 \else% regular ASCI characters
+
 \lstnewenvironment{cfa}[1][]{% necessary
 \lstset{
 language=CFA,
 escapechar=\$,							% LaTeX escape in CFA code
-mathescape=false,						% LaTeX math escape in CFA code $...$
 moredelim=**[is][\color{red}]{@}{@},	% red highlighting @...@
 }% lstset
Index: doc/LaTeXmacros/lstlang.sty
===================================================================
--- doc/LaTeXmacros/lstlang.sty	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ doc/LaTeXmacros/lstlang.sty	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -8,6 +8,6 @@
 %% Created On       : Sat May 13 16:34:42 2017
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Thu Sep 21 08:40:05 2023
-%% Update Count     : 31
+%% Last Modified On : Fri Feb 16 07:59:29 2024
+%% Update Count     : 37
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -125,11 +125,6 @@
 }
 
-% C++ programming language
-\lstdefinelanguage{C++}[ANSI]{C++}{
-	morekeywords={nullptr,}
-}
-
 % uC++ programming language, based on ANSI C++
-\lstdefinelanguage{uC++}[ANSI]{C++}{
+\lstdefinelanguage{uC++}[GNU]{C++}{
 	morekeywords={
 		_Accept, _AcceptReturn, _AcceptWait, _Actor, _At, _Catch, _CatchResume, _CorActor, _Cormonitor, _Coroutine,
Index: doc/bibliography/pl.bib
===================================================================
--- doc/bibliography/pl.bib	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ doc/bibliography/pl.bib	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -3742,4 +3742,14 @@
     month	= jul, year = 1987,
     volume	= 4, number = 4, pages = {9-16}
+}
+
+@manual{FreePascal,
+    keywords	= {Pascal, object oriented},
+    contributer	= {pabuhr@plg},
+    author	= {Micha\"{e}l Van Canneyt},
+    title	= {{F}ree {P}ascal Reference Guide, version 3.2.2},
+    month	= may,
+    year	= 2021,
+    note	= {\url{http://downloads.freepascal.org/fpc/docs-pdf/ref.pdf}},
 }
 
@@ -8243,4 +8253,17 @@
 }
 
+@manual{Swift,
+    keywords	= {Swift programming language},
+    contributer	= {pabuhr@plg},
+    key		= {Swift},
+    author	= {Chris Lattner and Doug Gregor and John McCall and Ted Kremenek and Joe Groff and Apple Inc.},
+    title	= {The Swift Programming Language},
+    edition	= {5.9.2},
+    organization= {Apple Inc.},
+    address	= {Cupertino, CA, USA},
+    year	= 2024,
+    note	= {\url{https://docs.swift.org/swift-book/documentation/the-swift-programming-language}},
+}
+
 @inproceedings{Burns81,
     keywords	= {N-thread software-solution mutual exclusion},
Index: doc/proposals/enum.tex
===================================================================
--- doc/proposals/enum.tex	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ doc/proposals/enum.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -117,8 +117,8 @@
 \end{abstract}
 
-\section{Background}
+\section{Introduction}
 
 Naming values is a common practice in mathematics and engineering, e.g., $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MHz (1E6), etc.
-Naming is also commonly used to represent many other numerical phenomenon, such as days of the week, months of a year, floors of a building (basement), time (noon, New Years).
+Naming is also commonly used to represent many other numerical phenomenon, such as days of the week, months of a year, floors of a building (basement), specific times (noon, New Years).
 Many programming languages capture this important software-engineering capability through a mechanism called an \newterm{enumeration}.
 An enumeration is similar to other programming-language types by providing a set of constrained values, but adds the ability to name \emph{all} the values in its set.
@@ -126,43 +126,57 @@
 
 Specifically, an enumerated type restricts its values to a fixed set of named constants.
-Fundamentally, all types are restricted to a fixed set of values because of the underlying von Neumann architecture, and hence, to a corresponding set of constants, e.g., @3@, @3.5@, @3.5+2.1i@, @'c'@, @"abc"@, etc.
-However, the values for basic types are not named, other than the programming-language supplied constants.
-
-
-\section{C-Style Enum}
-
-The C-Style enumeration has the following syntax and semantics, and is representative of enumerations in many other programming languages (see Section~\ref{s:RelatedWork}).
-\begin{lstlisting}[label=lst:weekday]
-enum Weekday { Monday, Tuesday, Wednesday, Thursday@ = 10@, Friday, Saturday, Sunday };
-                $\(\uparrow\)$                                                                        $\(\uparrow\)$
-    ${\rm \newterm{enumeration name}}$                                          ${\rm \newterm{enumerator names}}
-\end{lstlisting}
-Here, the enumeration type @Weekday@ defines the ordered \newterm{enumerator}s @Monday@, @Tuesday@, @Wednesday@, @Thursday@, @Friday@, @Saturday@ and @Sunday@.
-By convention, the successor of @Tuesday@ is @Monday@ and the predecessor of @Tuesday@ is @Wednesday@, independent of the associated enumerator constants.
-Because an enumerator is a constant, it cannot appear in a mutable context, e.g. @Mon = Sun@ is meaningless, and has no address, it is an rvalue\footnote{
-The term rvalue defines an expression that can only appear on the right-hand side of an assignment.}.
-Enumerators without explicitly designated constants are auto-initialized by the compiler: from left to right, starting at zero or the next explicitly initialized constant, incrementing by @1@.
-For example, @Monday@ to @Wednesday@ are implicitly assigned with constants 0--2, @Thursday@ is explicitly set to constant @10@, and @Friday@ to @Sunday@ are implicitly assigned with constants 11--13.
-Hence, there are 3 universal enumeration attributes: \newterm{position}, \newterm{label}, and \newterm{value}:
+While all types are restricted to a fixed set of values because of the underlying von Neumann architecture, and hence, to a corresponding set of constants, e.g., @3@, @3.5@, @3.5+2.1i@, @'c'@, @"abc"@, etc., these values are not named, other than the programming-language supplied constant names.
+
+Fundamentally, all enumeration systems have an \newterm{enumeration} type with an associated set of \newterm{enumerator} names.
+An enumeration has three universal attributes, \newterm{position}, \newterm{label}, and \newterm{value}, as shown by this representative enumeration, where position and value can be different.
 \begin{cquote}
 \small\sf\setlength{\tabcolsep}{3pt}
 \begin{tabular}{rccccccccccc}
-@enum@ Weekday \{	& Monday,	& Tuesday,	& Wednesday,	& Thursday = 10,& Friday, 	& Saturday,	& Sunday \}; \\
-\it\color{red}position		& 0			& 1			& 2				& 3				& 4			& 5			& 6			\\
-\it\color{red}label			& Monday	& Tuesday	& Wednesday		& Thursday		& Friday 	& Saturday	& Sunday	\\
-\it\color{red}value			& 0			& 1			& 2				& {\color{red}10}& 11		& 12		& 13
+\it\color{red}enumeration & \multicolumn{7}{c}{\it\color{red}enumerators}	\\
+$\downarrow$\hspace*{25pt} & \multicolumn{7}{c}{$\downarrow$}				\\
+@enum@ Weekday \{				& Monday,	& Tuesday,	& Wednesday,	& Thursday,& Friday, 	& Saturday,	& Sunday \}; \\
+\it\color{red}position			& 0			& 1			& 2				& 3				& 4			& 5			& 6			\\
+\it\color{red}label				& Monday	& Tuesday	& Wednesday		& Thursday		& Friday 	& Saturday	& Sunday	\\
+\it\color{red}value				& 0			& 1			& 2				& 3				& 4			& 5		& 6
 \end{tabular}
 \end{cquote}
-Finally, C enumerators are \newterm{unscoped}, i.e., enumerators declared inside of an @enum@ are visible in the enclosing scope of the @enum@ type.
+Here, the \newterm{enumeration} @Weekday@ defines the ordered \newterm{enumerator}s @Monday@, @Tuesday@, @Wednesday@, @Thursday@, @Friday@, @Saturday@ and @Sunday@.
+By convention, the successor of @Tuesday@ is @Monday@ and the predecessor of @Tuesday@ is @Wednesday@, independent of the associated enumerator constant values.
+Because an enumerator is a constant, it cannot appear in a mutable context, e.g. @Mon = Sun@ is meaningless, and an enumerator has no address, it is an \newterm{rvalue}\footnote{
+The term rvalue defines an expression that can only appear on the right-hand side of an assignment.}.
+
+
+\section{C-Style Enum}
+
+The C-Style enumeration has the following syntax and semantics.
+\begin{lstlisting}
+enum Weekday { Monday, Tuesday, Wednesday, Thursday@ = 10@, Friday, Saturday, Sunday };
+\end{lstlisting}
+Enumerators without an explicitly designated constant value are \newterm{auto-initialized} by the compiler: from left to right, starting at zero or the next explicitly initialized constant, incrementing by @1@.
+For example, @Monday@ to @Wednesday@ are implicitly assigned with constants @0@--@2@, @Thursday@ is explicitly set to constant @10@, and @Friday@ to @Sunday@ are implicitly assigned with constants @11@--@13@.
+Initialization may occur in any order.
+\begin{lstlisting}
+enum Weekday { Thursday@ = 10@, Friday, Saturday, Sunday, Monday@ = 0@, Tuesday, Wednesday };
+\end{lstlisting}
+Note, the comma in the enumerator list can be a terminator or a separator, allowing the list to end with a dangling comma.
+\begin{lstlisting}
+enum Weekday {
+	Thursday = 10, Friday, Saturday, Sunday,
+	Monday = 0, Tuesday, Wednesday@,@ // terminating comma
+};
+\end{lstlisting}
+This feature allow enumerator lines to be interchanged without moving a comma.\footnote{
+A terminating comma appears in other C syntax, e.g., the initializer list.}
+Finally, C enumerators are \newterm{unscoped}, i.e., enumerators declared inside of an @enum@ are visible (projected) into the enclosing scope of the @enum@ type.
 
 In theory, a C enumeration \emph{variable} is an implementation-defined integral type large enough to hold all enumerated values.
-In practice, since integral constants in C have type @int@ (unless qualified with a size suffix), C uses @int@ as the underlying type for enumeration variables.
-Furthermore, there is an implicit bidirectional conversion between an enumeration and integral types.
+In practice, since integral constants are used, which have type @int@ (unless qualified with a size suffix), C uses @int@ as the underlying type for enumeration variables.
+Finally, there is an implicit bidirectional conversion between an enumeration and integral types.
 \begin{lstlisting}[label=lst:enum_scope]
 {
-	enum Weekday { ... };				$\C{// enumerators implicitly projected into local scope}$
+	enum Weekday { /* as above */ };	$\C{// enumerators implicitly projected into local scope}$
 	Weekday weekday = Monday;			$\C{// weekday == 0}$
 	weekday = Friday;					$\C{// weekday == 11}$
-	int i = Sunday						$\C{// implicit conversion to int, i == 13}$
+	int i = Sunday;						$\C{// implicit conversion to int, i == 13}$
 	weekday = 10000;					$\C{// UNDEFINED! implicit conversion to Weekday}$
 }
@@ -171,4 +185,17 @@
 The implicit conversion from @int@ to an enumeration type is an unnecessary source of error.
 
+It is common for C programmers to ``believe'' there are 3 equivalent forms of constant enumeration.
+\begin{lstlisting}[label=lst:enum_scope]
+#define Monday 0
+static const int Monday = 0;
+enum { Monday };
+\end{lstlisting}
+For @#define@, the programmer has to play compiler and explicitly manage the enumeration values;
+furthermore, these are independent constants outside of any language type mechanism.
+The same explicit management is true for @const@ declarations, and the @const@ variable cannot appear in constant-expression locations, like @case@ labels, array dimensions,\footnote{
+C allows variable-length array-declarations (VLA), so this case does work, but it fails in \CC, which does not support VLAs, unless it is \lstinline{g++}.} and immediate operands of assembler instructions.
+Only the @enum@ form is managed by the compiler, is part of the language type-system, and works in all C constant-expression locations.
+
+
 \section{\CFA-Style Enum}
 
@@ -176,30 +203,65 @@
 \CFA also extends C-Style enumeration by adding a number of new features that bring enumerations inline with other modern programming languages.
 
+
+\subsection{Enumerator Name Resolution}
+\label{s:EnumeratorNameResolution}
+
+In C, unscoping of enumerators presents a \newterm{naming problem} when multiple enumeration types appear in the same scope with duplicate enumerator names.
+There is no mechanism in C to resolve these naming conflicts other than renaming of one of the duplicates, which may be impossible.
+
+The \CFA type-system allows extensive overloading, including enumerators.
+Furthermore, \CFA uses the left-hand of assignment in type resolution to pinpoint the best overloaded name.
+Finally, qualification is provided to disambiguate any ambiguous situations.
+\begin{lstlisting}
+enum C1 { First, Second, Third, Fourth };
+enum C2 { @Fourth@, @Third@, @Second@, @First@ };
+C1 p() { return Third; }				$\C{// correctly resolved duplicate names}$
+C2 p() { return Fourth; }
+void foo() {
+	C1 e1 = First;   C2 e2 = First;
+	e1 = Second;   e2 = Second;
+	e1 = p();   e2 = p();				$\C{// correctly resolved function call}$
+	int i = @C1.@First + @C2.@First;	$\C{// ambiguous without qualification}$
+}
+\end{lstlisting}
+\CFA overloading allows programmers to use the most meaningful names without fear of unresolvable clashes from included files, which are correctable with qualification.
+
+
+\subsection{Enumerator Scoping}
+
+An enumeration can be scoped, so the enumerator constants are not projected into the enclosing scope, using @'!'@.
+\begin{lstlisting}
+enum Weekday @!@ { /* as above */ };
+enum( char * ) Names @!@ { /* as above */ };
+\end{lstlisting}
+Now the enumerators \emph{must} be qualified with the associated enumeration.
+\begin{lstlisting}
+Weekday weekday = @Weekday@.Monday;
+Names names = @Names.@Fred;
+names = @Names.@Jane;
+\end{lstlisting}
+It is possible to toggle back to unscoping using the \CFA @with@ clause/statement (see also \CC \lstinline[language=c++]{using enum} in Section~\ref{s:C++RelatedWork}).
+\begin{lstlisting}
+Weekday weekday;
+with ( @Weekday@, @Names@ ) {			$\C{// type names}$
+	 Names names = @Fred@;
+	 names = @Jane@;
+	 weekday = Saturday;
+}
+\end{lstlisting}
+As in Section~\ref{s:EnumeratorNameResolution}, opening multiple unscoped enumerations can result in duplicate enumeration names, but \CFA type resolution and falling back to explicit qualification handles name resolution.
+
 \subsection{Enumerator Typing}
 
-\CFA extends the enumeration by parameterizing the enumeration with a type for the enumerators, allowing enumerators to be assigned any values from the declared type.
-Figure~\ref{f:EumeratorTyping} shows a series of examples illustrating that all \CFA types can be use with an enumeration and each type's constants used to set the enumerators.
-
-Typed enumerates deals with \emph{harmonizing} problem between an enumeration and its companion data.
-The following example is from the \CFA compiler, written in \CC.
-\begin{lstlisting}
-enum integral_types { chr, schar, uschar, sshort, ushort, sint, usint, ..., NO_OF_ITYPES };
-char * integral_names[NO_OF_ITYPES] = {
-	"char", "signed char", "unsigned char",
-	"signed short int", "unsigned short int",
-	"signed int", "unsigned int",
-	...
-};
-\end{lstlisting}
-The \emph{harmonizing} problem occurs because the enumeration declaration is in one header file and the names are declared in another translation unit.
-It is up to the programmer to ensure changes made in one location are harmonized with the other location (by identifying this requirement within a comment).
-The typed enumeration largely solves this problem by combining and managing the two data types.
-\begin{lstlisting}
-enum( char * ) integral_types {
-	chr = "char", schar = "signed char", uschar = "unsigned char",
-	sshort = "signed short int", ushort = "unsigned short int",
-	sint = "signed int", usint = "unsigned int",
-	...
-};
+\CFA extends the enumeration declaration by parameterizing with a type (like a generic type), allowing enumerators to be assigned any values from the declared type.
+Figure~\ref{f:EumeratorTyping} shows a series of examples illustrating that all \CFA types can be use with an enumeration and each type's constants used to set the enumerator constants.
+Note, the synonyms @Liz@ and @Beth@ in the last declaration.
+
+Because enumerators are constants, the enumeration type is implicitly @const@, so all the enumerator types in Figure~\ref{f:EumeratorTyping} are rewritten with @const@.
+A typed enumeration has an implicit (safe) conversion to its base type.
+\begin{lstlisting}
+char currency = Dollar;
+string fred = Fred;						$\C{// implicit conversion from char * to \CFA string type}$
+Person student = Beth;
 \end{lstlisting}
 
@@ -223,10 +285,10 @@
 	enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i };
 // pointer
-	enum( @char *@ ) Names { Fred = "Fred", Mary = "Mary", Jane = "Jane" };
+	enum( @char *@ ) Names { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
 	int i, j, k;
 	enum( @int *@ ) ptr { I = &i,  J = &j,  K = &k };
 	enum( @int &@ ) ref { I = i,   J = j,   K = k };
 // tuple
-	enum( @[int, int]@ ) { T = [ 1, 2 ] };
+	enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$
 // function
 	void f() {...}   void g() {...}
@@ -234,5 +296,5 @@
 // aggregate
 	struct Person { char * name; int age, height; };
-	enum( @Person@ ) friends { Liz = { "Elizabeth", 22, 170 }, Beth = Liz, Jon = { "Jonathan", 35, 190 } };
+@***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz, Jon = { "JONATHAN", 35, 190 } };
 \end{lstlisting}
 \caption{Enumerator Typing}
@@ -240,47 +302,77 @@
 \end{figure}
 
+Typed enumerations deals with the \emph{harmonizing} problem between an enumeration and any companion data.
+The following example is from the \CFA compiler, written in \CC.
+\begin{lstlisting}
+enum integral_types { chr, schar, uschar, sshort, ushort, sint, usint, ..., NO_OF_ITYPES };
+char * integral_names[NO_OF_ITYPES] = {
+	"char", "signed char", "unsigned char",
+	"signed short int", "unsigned short int",
+	"signed int", "unsigned int",
+	...
+};
+\end{lstlisting}
+The \emph{harmonizing} problem occurs because the enumeration declaration is in one header file and the names are declared in another translation unit.
+It is up to the programmer to ensure changes made in one location are harmonized with the other location (by identifying this requirement within a comment).
+The typed enumeration largely solves this problem by combining and managing the two data types.
+\begin{lstlisting}
+enum( char * ) integral_types {
+	chr = "char", schar = "signed char", uschar = "unsigned char",
+	sshort = "signed short int", ushort = "unsigned short int",
+	sint = "signed int", usint = "unsigned int",
+	...
+};
+\end{lstlisting}
+Note, the enumeration type can be a structure (see @Person@ in Figure~\ref{f:EumeratorTyping}), so it is possible to have the equivalent of multiple arrays of companion data using an array of structures.
+
+
 \subsection{Pure Enumerators}
 
-An empty type, @enum()@, implies the enumerators are pure symbols without values;
+An empty enumerator type, @enum()@, implies the enumerators are pure symbols without values but set properties;
 hence, there is no default conversion to @int@. 
 
 \begin{lstlisting}
 enum() Mode { O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC, O_APPEND };
-Mode iomode = O_RDONLY;
+@***@Mode iomode = O_RDONLY;
+bool b = iomode == O_RDONLY || iomode < O_APPEND;
 int i = iomode;							$\C{\color{red}// disallowed}$
-sout | O_TRUNC;							$\C{\color{red}// disallowed}$
 \end{lstlisting}
 
 \subsection{Enumerator Subset}
 
-If follows from enumerator typing that the type of the enumerators can be another enumerator.
-\begin{lstlisting}
+If follows from enumerator typing that the enumerator type can be another enumerator.
+\begin{lstlisting}
+enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$'  };
+enum( @Currency@ ) Europe { Euro = Currency.Euro, Pound = Currency.Pound }; // intersection
 enum( char ) Letter { A = 'A',  B = 'B', C = 'C', ..., Z = 'Z' };
-enum( Letter ) Greek { Alph = A, Beta = B, ..., Zeta = Z }; // alphabet intersection
+enum( @Letter@ ) Greek { Alph = A, Beta = B, ..., Zeta = Z }; // intersection
+\end{lstlisting}
+Subset enumerations may have more or less enumerators than their typed enumeration, but the enumerator values must be from the typed enumeration.
+For example, @Greek@ enumerators are a subset of type @Letter@ and are type compatible with enumeration @Letter@, but @Letter@ enumerators are not type compatible with enumeration @Greek@. 
+\begin{lstlisting}
 Letter letter = A;
-Greak greek = Alph;
-letter = Alph;							$\C{// allowed}$
+@***@Greak greek = Beta;
+letter = Beta;							$\C{// allowed, letter == B}$
 greek = A;								$\C{\color{red}// disallowed}$
 \end{lstlisting}
-Enumeration @Greek@ may have more or less enumerators than @Letter@, but the enumerator values must be from @Letter@.
-Therefore, @Greek@ enumerators are a subset of type @Letter@ and are type compatible with enumeration @Letter@, but @Letter@ enumerators are not type compatible with enumeration @Greek@. 
+
 
 \subsection{Enumeration Inheritance}
 
-\CFA Plan-9 inheritance may be used with enumerations.
-\begin{lstlisting}
-enum( char * ) Name2 { @inline Name@, Jack = "Jack", Jill = "Jill" };
-enum /* inferred */ Name3 { @inline Name2@, Sue = "Sue", Tom = "Tom" };
-\end{lstlisting}
-Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Name@ by containment, and a @Name@ enumeration is a subtype of enumeration @Name2@.
+\CFA Plan-9 inheritance may be used with enumerations, where Plan-9 inheritance is containment inheritance with implicit unscoping (like a nested unnamed @struct@/@union@ in C).
+\begin{lstlisting}
+enum( char * ) Names { /* as above */ };
+enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" };
+@***@enum /* inferred */ Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" };
+\end{lstlisting}
+Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a subtype of enumeration @Name2@.
 Note, enumerators must be unique in inheritance but enumerator values may be repeated.
 
 The enumeration type for the inheriting type must be the same as the inherited type;
 hence the enumeration type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for @Name3@.
-When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important.
-
-Specifically, the inheritance relationship for Names is:
-\begin{lstlisting}
-Name $\(\subset\)$ Name2 $\(\subset\)$ Name3 $\(\subset\)$ const char *		// enum type of Name
+% When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important.
+Specifically, the inheritance relationship for @Names@ is:
+\begin{lstlisting}
+Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\(\subset\)$ const char * $\C{// enum type of Names}$
 \end{lstlisting}
 For the given function prototypes, the following calls are valid.
@@ -288,7 +380,7 @@
 \begin{tabular}{ll}
 \begin{lstlisting}
-void f( Name );
-void g( Name2 );
-void h( Name3 );
+void f( Names );
+void g( Names2 );
+void h( Names3 );
 void j( const char * );
 \end{lstlisting}
@@ -298,76 +390,80 @@
 g( Fred );   g( Jill );
 h( Fred );   h( Jill );   h( Sue );
-j( Fred );   j( Jill );   j( Sue );   j( "Will" );
+j( Fred );   j( Jill );   j( Sue );   j( "WILL" );
 \end{lstlisting}
 \end{tabular}
 \end{cquote}
-Note, the validity of calls is the same for call-by-reference as for call-by-value, and const restrictions are the same as for other types.
-
-\subsection{Enumerator Scoping}
-
-A \CFA-enum can be scoped, meaning the enumerator constants are not projected into the enclosing scope.
-\begin{lstlisting}
-enum Weekday @!@ { /* as above */ };
-enum Colour( char * ) @!@ { /* as above */ };
-\end{lstlisting}
-where the @'!'@ implies the enumerators are \emph{not} projected.
-The enumerators of a scoped enumeration are accessed using qualifications, like the fields of an aggregate.
-% The syntax of $qualified\_expression$ for \CFA-enum is the following:
-% $$<qualified\_expression> := <enum\_type>.<enumerator>$$
-\begin{lstlisting}
-Weekday weekday = @Weekday.Monday@;		$\C{// qualification}$
-Colour colour = @Colour.@Red;
-colour = @Colour.@Blue;
-\end{lstlisting}
+Note, the validity of calls is the same for call-by-reference as for call-by-value, and @const@ restrictions are the same as for other types.
+
 
 \subsection{Enumeration Pseudo-functions}
 
-Pseudo-functions are function-like operators that do not result in any run-time computations, i.e., like @sizeof@.
+Pseudo-functions are function-like operators that do not result in any run-time computations, i.e., like @sizeof@, @offsetof@, @typeof@.
 Often a call to a pseudo-function is substituted with information extracted from the symbol table at compilation time, like storage size or alignment associated with the underlying architecture..
 
-\subsubsection{Enumerator Attributes}
 The attributes of an enumerator are accessed by pseudo-functions @position@, @value@, and @label@.
 \begin{lstlisting}
-int green_pos = @position@( Colour.Green );	$\C{// 1}$
-char * green_value = @value@( Colour.Green ); $\C{// "G"}$
-char * green_label = @label@( Colour.Green ); $\C{// "Green"}$
-\end{lstlisting}
-
-Enumeration Greek may have more or less enumerators than Letter, but the enumerator values must be from Letter.
-Therefore, Greek enumerators are a subset of type Letter and are type compatible with enumeration Letter, but Letter enumerators are not type compatible with enumeration Greek. 
-
-% An instance of \CFA-enum (denoted as @<enum_instance>@) is a label for the defined enum name.
-% The label can be retrieved by calling the function @label( <enum_instance> )@.
-% Similarly, the @value()@ function returns the value used to initialize the \CFA-enum.
-
-\subsubsection{\lstinline{enumerate()}}
-
-\begin{lstlisting}[label=lst:c_switch]
-enum(int) C_ENUM { First, Second, Third = First, Fourth };
-int v( C_ENUM e ) {
-	switch( e ) {
-		case First: return 0; break;
-		case Second: return 1; break;
-		// case Third: return 2; break;
-		// case Fourth: return 3; break;
-	};
-};
-\end{lstlisting}
-In the @C_ENUM@ example, @Third@ is an alias of @First@ and @Fourth@ is an alias of @Second@.
-Programmers cannot make case branches for @Third@ and @Fourth@ because the switch statement matches cases by the enumerator's value.
-Case @First@ and @Third@, or @Second@ and @Fourth@, has duplicate case values.
-
-@enumerate()@ is a pseudo-function that makes the switch statement match by an enumerator instead.
-\begin{lstlisting}[label=lst:c_switch_enumerate]
-enum(double) C_ENUM { First, Second, Third = First, Fourth };
-C_ENUM variable_a = First, variable_b = Second, variable_c = Third, variable_d = Fourth;
-int v(C_ENUM e) {
-	switch( enumeratate( e ) ) {
-		case First: return e; break;
-		case Second: return value( e ); break;
-		case Third: return label( e ); break;
-		case Fourth: return position( e ); break;
-	};
-};
+@***@int jane_pos = @position@( Names.Jane );   $\C{// 2}$
+@***@char * jane_value = @value@( Names.Jane ); $\C{// "JANE"}$
+@***@char * jane_label = @label@( Names.Jane ); $\C{// "Jane"}$
+sout | @label@( Names.Jane ) | @value@( Names.Jane );
+\end{lstlisting}
+Note the ability to print both enumerator label and value.
+
+
+\subsection{Enumerator Position or Value}
+
+Enumerators can be used in multiple contexts.
+In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution).
+However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts.
+In these contexts, a programmer's initition assumes an implicit conversion to postion.
+
+For example, an intuitive use of enumerations is with the \CFA @switch@/@choose@ statement, where @choose@ performs an implict @break@ rather than a fall-through at the end of a @case@ clause.
+\begin{cquote}
+\begin{lstlisting}
+enum Count { First, Second, Third, Fourth };
+Count e;
+\end{lstlisting}
+\begin{tabular}{ll}
+\begin{lstlisting}
+
+choose( e ) {
+	case @First@: ...;
+	case @Second@: ...;
+	case @Third@: ...;
+	case @Fourth@: ...;
+}
+\end{lstlisting}
+&
+\begin{lstlisting}
+// rewrite
+choose( @value@( e ) ) {
+	case @value@( First ): ...;
+	case @value@( Second ): ...;
+	case @value@( Third ): ...;
+	case @value@( Fourth ): ...;
+}
+\end{lstlisting}
+\end{tabular}
+\end{cquote}
+Here, the intuitive code on the left is implicitly transformed into the statndard implementation on the right, using the value of the enumeration variable and enumerators.
+However, this implementation is fragile, e.g., if the enumeration is changed to:
+\begin{lstlisting}
+enum Count { First, Second, Third @= First@, Fourth };
+\end{lstlisting}
+which make @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicase @case@ clauses.
+To better match with programmer intuition, \CFA toggles between value and position semantics depneding on the language context.
+For conditional clauses and switch statments, \CFA uses the robust position implementation.
+\begin{lstlisting}
+choose( @position@( e ) ) {
+	case @position@( First ): ...;
+	case @position@( Second ): ...;
+	case @position@( Third ): ...;
+	case @position@( Fourth ): ...;
+}
+\end{lstlisting}
+
+\begin{lstlisting}
+Count variable_a = First, variable_b = Second, variable_c = Third, variable_d = Fourth;
 p(variable_a); // 0
 p(variable_b); // 1
@@ -1015,25 +1111,4 @@
 If the @aggregation_name@ is identified as a \CFA enumeration, the compiler checks if @field@ presents in the declared \CFA enumeration.
 
-\subsection{\lstinline{with} Clause/Statement}
-
-Instead of qualifying an enumeration expression every time, the @with@ can be used to expose enumerators to the current scope, making them directly accessible.
-\begin{lstlisting}[label=lst:declaration]
-enum Color( char * ) { Red="R", Green="G", Blue="B" };
-enum Animal( int ) { Cat=10, Dog=20 };
-with ( Color, Animal ) {
-	char * red_string = Red; // value( Color.Red )
-	int cat = Cat; // value( Animal.Cat )
-}
-\end{lstlisting}
-The \lstinline{with} might introduce ambiguity to a scope. Consider the example:
-\begin{lstlisting}[label=lst:declaration]
-enum Color( char * ) { Red="R", Green="G", Blue="B" };
-enum RGB( int ) { Red=0, Green=1, Blue=2 };
-with ( Color, RGB ) {
-	// int red = Red;
-}
-\end{lstlisting}
-\CFA will not try to resolve the expression with ambiguity. It would report an error. In this case, it is necessary to qualify @Red@ even inside of the \lstinline{with} clause.
-
 \subsection{Instance Declaration}
 
@@ -1218,22 +1293,70 @@
 
 \subsection{\CC}
-
-\CC is backwards compatible with C, so it inherited C's enumerations, except there is no implicit conversion from an integral value to an enumeration;
-hence, the values in a \CC enumeration can only be its enumerators (without a cast).
-There is no mechanism to iterate through an enumeration.
-
-\CC{11} added a scoped enumeration, \lstinline[language=c++]{enum class} (or \lstinline[language=c++]{enum struct}), so the enumerators are local to the enumeration and must be accessed using type qualification, e.g., @Weekday::Monday@.
+\label{s:C++RelatedWork}
+
+\CC is backwards compatible with C, so it inherited C's enumerations.
+However, the following non-backwards compatible changes have been made.
+\begin{quote}
+7.2 Change: \CC objects of enumeration type can only be assigned values of the same enumeration type.
+In C, objects of enumeration type can be assigned values of any integral type. \\
+Example:
+\begin{lstlisting}
+enum color { red, blue, green };
+color c = 1;			 				$\C{// valid C, invalid C++}$
+\end{lstlisting}
+\textbf{Rationale}: The type-safe nature of C++. \\
+\textbf{Effect on original feature}: Deletion of semantically well-defined feature. \\
+\textbf{Difficulty of converting}: Syntactic transformation. (The type error produced by the assignment can be automatically corrected by applying an explicit cast.) \\
+\textbf{How widely used}: Common.
+\end{quote}
+\begin{quote}
+7.2 Change: In \CC, the type of an enumerator is its enumeration.
+In C, the type of an enumerator is @int@. \\
+Example:
+\begin{lstlisting}
+enum e { A };
+sizeof(A) == sizeof(int)		 		$\C{// in C}$
+sizeof(A) == sizeof(e)		 			$\C{// in C++}$
+/* and sizeof(int) is not necessary equal to sizeof(e) */
+\end{lstlisting}
+\textbf{Rationale}: In C++, an enumeration is a distinct type. \\
+\textbf{Effect on original feature}: Change to semantics of well-defined feature. \\
+\textbf{Difficulty of converting}: Semantic transformation. \\
+\textbf{How widely used}: Seldom. The only time this affects existing C code is when the size of an enumerator is taken.
+Taking the size of an enumerator is not a common C coding practice.
+\end{quote}
+Hence, the values in a \CC enumeration can only be its enumerators (without a cast).
+While the storage size of an enumerator is up to the compiler, there is still an implicit cast to @int@.
+\begin{lstlisting}
+enum E { A, B, C };
+E e = A;
+int i = A;   i = e;	 					$\C{// implicit casts to int}$
+\end{lstlisting}
+\CC{11} added a scoped enumeration, \lstinline[language=c++]{enum class} (or \lstinline[language=c++]{enum struct}), so the enumerators are local to the enumeration and must be accessed using type qualification.
+\begin{lstlisting}[language=c++,{moredelim=**[is][\color{red}]{@}{@}}]
+enum class E { A, B, C };
+E e = @E::@A;	 						$\C{// qualified enumerator}$
+e = B;	 								$\C{// B not in scope}$
+\end{lstlisting}
 \CC{20} supports unscoped access with a \lstinline[language=c++]{using enum} declaration.
-
-For both unscoped and scoped enumerations, the underlying type is an implementation-defined integral type large enough to hold all enumerated values; it does not have to be the smallest possible type.
-In \CC{11}, the underlying integral type can be explicitly specified:
 \begin{lstlisting}[language=c++,{moredelim=**[is][\color{red}]{@}{@}}]
-enum class RGB : @long@ { Red, Green, Blue };
-enum class rgb : @char@ { Red = 'r', Green = 'g', Blue = 'b' };
-enum class srgb : @signed char@ { Red = -1, Green = 0, Blue = 1 };
-RGB colour1 = @RGB::@Red;
-rgb colour2 = @rgb::@Red;
-srgb colour3 = @srgb::@Red;
-\end{lstlisting}
+enum class E { A, B, C };
+@using enum E;@
+E e = A;	 							$\C{// direct access}$
+e = B;	 								$\C{// direct access}$
+\end{lstlisting}
+\CC{11} added the ability to explicitly declare the underlying integral type for \lstinline[language=c++]{enum class}.
+\begin{lstlisting}[language=c++,{moredelim=**[is][\color{red}]{@}{@}}]
+enum class RGB @: long@ { Red, Green, Blue };
+enum class rgb @: char@ { Red = 'r', Green = 'g', Blue = 'b' };
+enum class srgb @: signed char@ { Red = -1, Green = 0, Blue = 1 };
+\end{lstlisting}
+There is no implicit conversion from the \lstinline[language=c++]{enum class} type and to its type.
+\begin{lstlisting}[language=c++,{moredelim=**[is][\color{red}]{@}{@}}]
+rgb crgb = rgb::Red;
+char ch = rgb::Red;   ch = crgb;		$\C{// disallowed}$
+\end{lstlisting}
+Finally, there is no mechanism to iterate through an enumeration nor use the enumeration type to declare an array dimension.
+
 
 \subsection{Go}
Index: doc/theses/jiada_liang_MMath/CFAenum.tex
===================================================================
--- doc/theses/jiada_liang_MMath/CFAenum.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
+++ doc/theses/jiada_liang_MMath/CFAenum.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -0,0 +1,274 @@
+\chapter{\CFA-Style Enum}
+
+
+\CFA supports C-Style enumeration using the same syntax and semantics for backwards compatibility.
+\CFA also extends C-Style enumeration by adding a number of new features that bring enumerations inline with other modern programming languages.
+
+
+\section{Enumerator Name Resolution}
+\label{s:EnumeratorNameResolution}
+
+In C, unscoping of enumerators presents a \Newterm{naming problem} when multiple enumeration types appear in the same scope with duplicate enumerator names.
+There is no mechanism in C to resolve these naming conflicts other than renaming of one of the duplicates, which may be impossible.
+
+The \CFA type-system allows extensive overloading, including enumerators.
+Furthermore, \CFA uses the left-hand of assignment in type resolution to pinpoint the best overloaded name.
+Finally, qualification is provided to disambiguate any ambiguous situations.
+\begin{cfa}
+enum C1 { First, Second, Third, Fourth };
+enum C2 { @Fourth@, @Third@, @Second@, @First@ };
+C1 p() { return Third; }				$\C{// correctly resolved duplicate names}$
+C2 p() { return Fourth; }
+void foo() {
+	C1 e1 = First;   C2 e2 = First;
+	e1 = Second;   e2 = Second;
+	e1 = p();   e2 = p();				$\C{// correctly resolved function call}$
+	int i = @C1.@First + @C2.@First;	$\C{// ambiguous without qualification}$
+}
+\end{cfa}
+\CFA overloading allows programmers to use the most meaningful names without fear of unresolvable clashes from included files, which are correctable with qualification.
+
+
+\section{Enumerator Scoping}
+
+An enumeration can be scoped, so the enumerator constants are not projected into the enclosing scope, using @'!'@.
+\begin{cfa}
+enum Weekday @!@ { /* as above */ };
+enum( char * ) Names @!@ { /* as above */ };
+\end{cfa}
+Now the enumerators \emph{must} be qualified with the associated enumeration.
+\begin{cfa}
+Weekday weekday = @Weekday@.Monday;
+Names names = @Names.@Fred;
+names = @Names.@Jane;
+\end{cfa}
+It is possible to toggle back to unscoping using the \CFA @with@ clause/statement (see also \CC \lstinline[language=c++]{using enum} in Section~\ref{s:C++RelatedWork}).
+\begin{cfa}
+Weekday weekday;
+with ( @Weekday@, @Names@ ) {			$\C{// type names}$
+	 Names names = @Fred@;
+	 names = @Jane@;
+	 weekday = Saturday;
+}
+\end{cfa}
+As in Section~\ref{s:EnumeratorNameResolution}, opening multiple unscoped enumerations can result in duplicate enumeration names, but \CFA type resolution and falling back to explicit qualification handles name resolution.
+
+\section{Enumerator Typing}
+
+\CFA extends the enumeration declaration by parameterizing with a type (like a generic type), allowing enumerators to be assigned any values from the declared type.
+Figure~\ref{f:EumeratorTyping} shows a series of examples illustrating that all \CFA types can be use with an enumeration and each type's constants used to set the enumerator constants.
+Note, the synonyms @Liz@ and @Beth@ in the last declaration.
+
+Because enumerators are constants, the enumeration type is implicitly @const@, so all the enumerator types in Figure~\ref{f:EumeratorTyping} are rewritten with @const@.
+A typed enumeration has an implicit (safe) conversion to its base type.
+\begin{cfa}
+char currency = Dollar;
+string fred = Fred;						$\C{// implicit conversion from char * to \CFA string type}$
+Person student = Beth;
+\end{cfa}
+
+% \begin{cfa}
+% struct S { int i, j; };
+% enum( S ) s { A = { 3,  4 }, B = { 7,  8 } };
+% enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$'  };
+% enum( @double@ ) Planet { Venus = 4.87, Earth = 5.97, Mars = 0.642  }; // mass
+% enum( @char *@ ) Colour { Red = "red", Green = "green", Blue = "blue"  };
+% enum( @Currency@ ) Europe { Euro = '$\texteuro$', Pound = '$\textsterling$' }; // intersection
+% \end{cfa}
+
+\begin{figure}
+\begin{cfa}
+// integral
+	enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$'  };
+	enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 };
+	enum( @long long int@ ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 };
+// non-integral
+	enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 };
+	enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i };
+// pointer
+	enum( @char *@ ) Names { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
+	int i, j, k;
+	enum( @int *@ ) ptr { I = &i,  J = &j,  K = &k };
+	enum( @int &@ ) ref { I = i,   J = j,   K = k };
+// tuple
+	enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$
+// function
+	void f() {...}   void g() {...}
+	enum( @void (*)()@ ) funs { F = f,  G = g };
+// aggregate
+	struct Person { char * name; int age, height; };
+@***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz, Jon = { "JONATHAN", 35, 190 } };
+\end{cfa}
+\caption{Enumerator Typing}
+\label{f:EumeratorTyping}
+\end{figure}
+
+Typed enumerations deals with the \emph{harmonizing} problem between an enumeration and any companion data.
+The following example is from the \CFA compiler, written in \CC.
+\begin{cfa}
+enum integral_types { chr, schar, uschar, sshort, ushort, sint, usint, ..., NO_OF_ITYPES };
+char * integral_names[NO_OF_ITYPES] = {
+	"char", "signed char", "unsigned char",
+	"signed short int", "unsigned short int",
+	"signed int", "unsigned int",
+	...
+};
+\end{cfa}
+The \emph{harmonizing} problem occurs because the enumeration declaration is in one header file and the names are declared in another translation unit.
+It is up to the programmer to ensure changes made in one location are harmonized with the other location (by identifying this requirement within a comment).
+The typed enumeration largely solves this problem by combining and managing the two data types.
+\begin{cfa}
+enum( char * ) integral_types {
+	chr = "char", schar = "signed char", uschar = "unsigned char",
+	sshort = "signed short int", ushort = "unsigned short int",
+	sint = "signed int", usint = "unsigned int",
+	...
+};
+\end{cfa}
+Note, the enumeration type can be a structure (see @Person@ in Figure~\ref{f:EumeratorTyping}), so it is possible to have the equivalent of multiple arrays of companion data using an array of structures.
+
+
+\section{Pure Enumerators}
+
+An empty enumerator type, @enum()@, implies the enumerators are pure symbols without values but set properties;
+hence, there is no default conversion to @int@. 
+
+\begin{cfa}
+enum() Mode { O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC, O_APPEND };
+@***@Mode iomode = O_RDONLY;
+bool b = iomode == O_RDONLY || iomode < O_APPEND;
+int i = iomode;							$\C{\color{red}// disallowed}$
+\end{cfa}
+
+\section{Enumerator Subset}
+
+If follows from enumerator typing that the enumerator type can be another enumerator.
+\begin{cfa}
+enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$'  };
+enum( @Currency@ ) Europe { Euro = Currency.Euro, Pound = Currency.Pound }; // intersection
+enum( char ) Letter { A = 'A',  B = 'B', C = 'C', ..., Z = 'Z' };
+enum( @Letter@ ) Greek { Alph = A, Beta = B, ..., Zeta = Z }; // intersection
+\end{cfa}
+Subset enumerations may have more or less enumerators than their typed enumeration, but the enumerator values must be from the typed enumeration.
+For example, @Greek@ enumerators are a subset of type @Letter@ and are type compatible with enumeration @Letter@, but @Letter@ enumerators are not type compatible with enumeration @Greek@. 
+\begin{cfa}
+Letter letter = A;
+@***@Greak greek = Beta;
+letter = Beta;							$\C{// allowed, letter == B}$
+greek = A;								$\C{\color{red}// disallowed}$
+\end{cfa}
+
+
+\section{Enumeration Inheritance}
+
+\CFA Plan-9 inheritance may be used with enumerations, where Plan-9 inheritance is containment inheritance with implicit unscoping (like a nested unnamed @struct@/@union@ in C).
+\begin{cfa}
+enum( char * ) Names { /* as above */ };
+enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" };
+@***@enum /* inferred */ Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" };
+\end{cfa}
+Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a subtype of enumeration @Name2@.
+Note, enumerators must be unique in inheritance but enumerator values may be repeated.
+
+The enumeration type for the inheriting type must be the same as the inherited type;
+hence the enumeration type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for @Name3@.
+% When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important.
+Specifically, the inheritance relationship for @Names@ is:
+\begin{cfa}
+Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\(\subset\)$ const char * $\C{// enum type of Names}$
+\end{cfa}
+For the given function prototypes, the following calls are valid.
+\begin{cquote}
+\begin{tabular}{ll}
+\begin{cfa}
+void f( Names );
+void g( Names2 );
+void h( Names3 );
+void j( const char * );
+\end{cfa}
+&
+\begin{cfa}
+f( Fred );
+g( Fred );   g( Jill );
+h( Fred );   h( Jill );   h( Sue );
+j( Fred );   j( Jill );   j( Sue );   j( "WILL" );
+\end{cfa}
+\end{tabular}
+\end{cquote}
+Note, the validity of calls is the same for call-by-reference as for call-by-value, and @const@ restrictions are the same as for other types.
+
+
+\section{Enumeration Pseudo-functions}
+
+Pseudo-functions are function-like operators that do not result in any run-time computations, \ie like @sizeof@, @offsetof@, @typeof@.
+Often a call to a pseudo-function is substituted with information extracted from the symbol table at compilation time, like storage size or alignment associated with the underlying architecture..
+
+The attributes of an enumerator are accessed by pseudo-functions @position@, @value@, and @label@.
+\begin{cfa}
+@***@int jane_pos = @position@( Names.Jane );   $\C{// 2}$
+@***@char * jane_value = @value@( Names.Jane ); $\C{// "JANE"}$
+@***@char * jane_label = @label@( Names.Jane ); $\C{// "Jane"}$
+sout | @label@( Names.Jane ) | @value@( Names.Jane );
+\end{cfa}
+Note the ability to print both enumerator label and value.
+
+
+\section{Enumerator Position or Value}
+
+Enumerators can be used in multiple contexts.
+In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution).
+However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts.
+In these contexts, a programmer's initition assumes an implicit conversion to postion.
+
+For example, an intuitive use of enumerations is with the \CFA @switch@/@choose@ statement, where @choose@ performs an implict @break@ rather than a fall-through at the end of a @case@ clause.
+\begin{cquote}
+\begin{cfa}
+enum Count { First, Second, Third, Fourth };
+Count e;
+\end{cfa}
+\begin{tabular}{ll}
+\begin{cfa}
+
+choose( e ) {
+	case @First@: ...;
+	case @Second@: ...;
+	case @Third@: ...;
+	case @Fourth@: ...;
+}
+\end{cfa}
+&
+\begin{cfa}
+// rewrite
+choose( @value@( e ) ) {
+	case @value@( First ): ...;
+	case @value@( Second ): ...;
+	case @value@( Third ): ...;
+	case @value@( Fourth ): ...;
+}
+\end{cfa}
+\end{tabular}
+\end{cquote}
+Here, the intuitive code on the left is implicitly transformed into the statndard implementation on the right, using the value of the enumeration variable and enumerators.
+However, this implementation is fragile, \eg if the enumeration is changed to:
+\begin{cfa}
+enum Count { First, Second, Third @= First@, Fourth };
+\end{cfa}
+which make @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicase @case@ clauses.
+To better match with programmer intuition, \CFA toggles between value and position semantics depneding on the language context.
+For conditional clauses and switch statments, \CFA uses the robust position implementation.
+\begin{cfa}
+choose( @position@( e ) ) {
+	case @position@( First ): ...;
+	case @position@( Second ): ...;
+	case @position@( Third ): ...;
+	case @position@( Fourth ): ...;
+}
+\end{cfa}
+
+\begin{cfa}
+Count variable_a = First, variable_b = Second, variable_c = Third, variable_d = Fourth;
+p(variable_a); // 0
+p(variable_b); // 1
+p(variable_c); // "Third"
+p(variable_d); // 3
+\end{cfa}
Index: doc/theses/jiada_liang_MMath/background.tex
===================================================================
--- doc/theses/jiada_liang_MMath/background.tex	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ doc/theses/jiada_liang_MMath/background.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -1,1 +1,52 @@
 \chapter{Background}
+
+
+\section{C-Style Enum}
+
+The C-Style enumeration has the following syntax and semantics.
+\begin{cfa}
+enum Weekday { Monday, Tuesday, Wednesday, Thursday@ = 10@, Friday, Saturday, Sunday };
+\end{cfa}
+Enumerators without an explicitly designated constant value are \Newterm{auto-initialized} by the compiler: from left to right, starting at zero or the next explicitly initialized constant, incrementing by @1@.
+For example, @Monday@ to @Wednesday@ are implicitly assigned with constants @0@--@2@, @Thursday@ is explicitly set to constant @10@, and @Friday@ to @Sunday@ are implicitly assigned with constants @11@--@13@.
+Initialization may occur in any order.
+\begin{cfa}
+enum Weekday { Thursday@ = 10@, Friday, Saturday, Sunday, Monday@ = 0@, Tuesday, Wednesday };
+\end{cfa}
+Note, the comma in the enumerator list can be a terminator or a separator, allowing the list to end with a dangling comma.
+\begin{cfa}
+enum Weekday {
+	Thursday = 10, Friday, Saturday, Sunday,
+	Monday = 0, Tuesday, Wednesday@,@ // terminating comma
+};
+\end{cfa}
+This feature allow enumerator lines to be interchanged without moving a comma.\footnote{
+A terminating comma appears in other C syntax, \eg the initializer list.}
+Finally, C enumerators are \Newterm{unscoped}, \ie enumerators declared inside of an @enum@ are visible (projected) into the enclosing scope of the @enum@ type.
+
+In theory, a C enumeration \emph{variable} is an implementation-defined integral type large enough to hold all enumerated values.
+In practice, since integral constants are used, which have type @int@ (unless qualified with a size suffix), C uses @int@ as the underlying type for enumeration variables.
+Finally, there is an implicit bidirectional conversion between an enumeration and its integral type.
+\begin{cfa}
+{
+	enum Weekday { /* as above */ };	$\C{// enumerators implicitly projected into local scope}$
+	Weekday weekday = Monday;			$\C{// weekday == 0}$
+	weekday = Friday;					$\C{// weekday == 11}$
+	int i = Sunday;						$\C{// implicit conversion to int, i == 13}$
+	weekday = 10000;					$\C{// UNDEFINED! implicit conversion to Weekday}$
+}
+int j = Wednesday;						$\C{// ERROR! Wednesday is not declared in this scope}$
+\end{cfa}
+The implicit conversion from @int@ to an enumeration type is an unnecessary source of error.
+
+It is common for C programmers to ``believe'' there are 3 equivalent forms of constant enumeration.
+\begin{cfa}
+#define Monday 0
+static const int Monday = 0;
+enum { Monday };
+\end{cfa}
+For @#define@, the programmer has to play compiler and explicitly manage the enumeration values;
+furthermore, these are independent constants outside of any language type mechanism.
+The same explicit management is true for @const@ declarations, and the @const@ variable cannot appear in constant-expression locations, like @case@ labels, array dimensions,\footnote{
+C allows variable-length array-declarations (VLA), so this case does work, but it fails in \CC, which does not support VLAs, unless it is \lstinline{g++}.} and immediate operands of assembler instructions.
+Only the @enum@ form is managed by the compiler, is part of the language type-system, and works in all C constant-expression locations.
Index: c/theses/jiada_liang_MMath/content1.tex
===================================================================
--- doc/theses/jiada_liang_MMath/content1.tex	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ 	(revision )
@@ -1,8 +1,0 @@
-\chapter{Content1}
-\label{c:content1}
-
-This chapter ...
-
-\section{Section 1}
-
-\section{Section 2}
Index: c/theses/jiada_liang_MMath/content2.tex
===================================================================
--- doc/theses/jiada_liang_MMath/content2.tex	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ 	(revision )
@@ -1,8 +1,0 @@
-\chapter{Content1}
-\label{c:content1}
-
-This chapter ...
-
-\section{Section 1}
-
-\section{Section 2}
Index: doc/theses/jiada_liang_MMath/implementation.tex
===================================================================
--- doc/theses/jiada_liang_MMath/implementation.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
+++ doc/theses/jiada_liang_MMath/implementation.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -0,0 +1,650 @@
+\chapter{Enumeration Implementation}
+
+
+\section{Enumeration Variable}
+
+Although \CFA enumeration captures three different attributes, an enumeration instance does not store all this information.
+The @sizeof@ a \CFA enumeration instance is always 4 bytes, the same size as a C enumeration instance (@sizeof( int )@).
+It comes from the fact that:
+\begin{enumerate}
+\item
+a \CFA enumeration is always statically typed;
+\item
+it is always resolved as one of its attributes regarding real usage.
+\end{enumerate}
+When creating an enumeration instance @colour@ and assigning it with the enumerator @Color.Green@, the compiler allocates an integer variable and stores the position 1.
+The invocations of $positions()$, $value()$, and $label()$ turn into calls to special functions defined in the prelude:
+\begin{cfa}
+position( green );
+>>> position( Colour, 1 ) -> int
+value( green );
+>>> value( Colour, 1 ) -> T
+label( green );
+>>> label( Colour, 1) -> char *
+\end{cfa}
+@T@ represents the type declared in the \CFA enumeration defined and @char *@ in the example.
+These generated functions are $Companion Functions$, they take an $companion$ object and the position as parameters.
+
+
+\section{Enumeration Data}
+
+\begin{cfa}
+enum(T) E { ... };
+// backing data
+T * E_values;
+char ** E_labels;
+\end{cfa}
+Storing values and labels as arrays can sometimes help support enumeration features.
+However, the data structures are the overhead for the programs. We want to reduce the memory usage for enumeration support by:
+\begin{itemize}
+	\item Only generates the data array if necessary
+	\item The compilation units share the data structures.
+	No extra overhead if the data structures are requested multiple times.
+\end{itemize}
+
+
+\section{Unification}
+
+\section{Enumeration as Value}
+\label{section:enumeration_as_value}
+An \CFA enumeration with base type T can be used seamlessly as T, without explicitly calling the pseudo-function value.
+\begin{cfa}
+char * green_value = Colour.Green; // "G"
+// Is equivalent to
+// char * green_value = value( Color.Green ); "G"
+\end{cfa}
+
+
+\section{Unification Distance}
+
+\begin{cfa}
+T_2 Foo(T1);
+\end{cfa}
+The @Foo@ function expects a parameter with type @T1@. In C, only a value with the exact type T1 can be used as a parameter for @Foo@. In \CFA, @Foo@ accepts value with some type @T3@ as long as @distance(T1, T3)@ is not @Infinite@.
+
+@path(A, B)@ is a compiler concept that returns one of the following:
+\begin{itemize}
+	\item Zero or 0, if and only if $A == B$.
+	\item Safe, if B can be used as A without losing its precision, or B is a subtype of A.
+	\item Unsafe, if B loses its precision when used as A, or A is a subtype of B.
+	\item Infinite, if B cannot be used as A. A is not a subtype of B and B is not a subtype of A.
+\end{itemize}
+
+For example, @path(int, int)==Zero@, @path(int, char)==Safe@, @path(int, double)==Unsafe@, @path(int, struct S)@ is @Infinite@ for @struct S{}@.
+@distance(A, C)@ is the minimum sum of paths from A to C. For example, if @path(A, B)==i@, @path(B, C)==j@, and @path(A, C)=k@, then $$distance(A,C)==min(path(A,B), path(B,C))==i+j$$.
+
+(Skip over the distance matrix here because it is mostly irrelevant for enumeration discussion. In the actual implementation, distance( E, T ) is 1.)
+
+The arithmetic of distance is the following:
+\begin{itemize}
+	\item $Zero + v= v$, for some value v.
+	\item $Safe * k <  Unsafe$, for finite k.
+	\item $Unsafe * k < Infinite$, for finite k.
+	\item $Infinite + v = Infinite$, for some value v.
+\end{itemize}
+
+For @enum(T) E@, @path(T, E)==Safe@ and @path(E,T)==Infinite@. In other words, enumeration type E can be @safely@ used as type T, but type T cannot be used when the resolution context expects a variable with enumeration type @E@.
+
+
+\section{Variable Overloading and Parameter Unification}
+
+\CFA allows variable names to be overloaded. It is possible to overload a variable that has type T and an enumeration with type T.
+\begin{cfa}
+char * green = "Green";
+Colour green = Colour.Green; // "G"
+
+void bar(char * s) { return s; }
+void foo(Colour c) { return value( c ); }
+
+foo( green ); // "G"
+bar( green ); // "Green"
+\end{cfa}
+\CFA's conversion distance helps disambiguation in this overloading. For the function @bar@ which expects the parameter s to have type @char *@, $distance(char *,char *) == Zero$ while $distance(char *, Colour) == Safe$, the path from @char *@ to the enumeration with based type @char *@, \CFA chooses the @green@ with type @char *@ unambiguously. On the other hand, for the function @foo@, @distance(Colour, char *)@ is @Infinite@, @foo@ picks the @green@ with type @char *@.
+
+\section{Function Overloading}
+Similarly, functions can be overloaded with different signatures. \CFA picks the correct function entity based on the distance between parameter types and the arguments.
+\begin{cfa}
+Colour green = Colour.Green;
+void foo(Colour c) { sout | "It is an enum"; } // First foo
+void foo(char * s) { sout | "It is a string"; } // Second foo
+foo( green ); // "It is an enum"
+\end{cfa}
+Because @distance(Colour, Colour)@ is @Zero@ and @distance(char *, Colour)@ is @Safe@, \CFA determines the @foo( green )@ is a call to the first foo.
+
+\section{Attributes Functions}
+The pseudo-function @value()@ "unboxes" the enumeration and the type of the expression is the underlying type. Therefore, in the section~\ref{section:enumeration_as_value} when assigning @Colour.Green@ to variable typed @char *@, the resolution distance is @Safe@, while assigning @value(Color.Green) to @char *) has resolution distance @Zero@.
+
+\begin{cfa}
+int s1;
+\end{cfa}
+The generated code for an enumeration instance is simply an int. It is to hold the position of an enumeration. And usage of variable @s1@ will be converted to return one of its attributes: label, value, or position, concerning the @Unification@ rule
+
+% \section{Unification and Resolution (this implementation will probably not be used, safe as reference for now)}
+
+% \begin{cfa}
+% enum Colour( char * ) { Red = "R", Green = "G", Blue = "B"  };
+% \end{cfa}
+% The @EnumInstType@ is convertible to other types.
+% A \CFA enumeration expression is implicitly \emph{overloaded} with its three different attributes: value, position, and label.
+% The \CFA compilers need to resolve an @EnumInstType@ as one of its attributes based on the current context.
+
+% \begin{cfa}[caption={Null Context}, label=lst:null_context]
+% {
+% 	Colour.Green;
+% }
+% \end{cfa}
+% In example~\ref{lst:null_context}, the environment gives no information to help with the resolution of @Colour.Green@.
+% In this case, any of the attributes is resolvable.
+% According to the \textit{precedence rule}, the expression with @EnumInstType@ resolves as @value( Colour.Green )@.
+% The @EnumInstType@ is converted to the type of the value, which is statically known to the compiler as @char *@.
+% When the compilation reaches the code generation, the compiler outputs code for type @char *@ with the value @"G"@.
+% \begin{cfa}[caption={Null Context Generated Code}, label=lst:null_context]
+% {
+% 	"G";
+% }
+% \end{cfa}
+% \begin{cfa}[caption={int Context}, label=lst:int_context]
+% {
+% 	int g = Colour.Green;
+% }
+% \end{cfa}
+% The assignment expression gives a context for the EnumInstType resolution.
+% The EnumInstType is used as an @int@, and \CFA needs to determine which of the attributes can be resolved as an @int@ type.
+% The functions $Unify( T1, T2 ): bool$ take two types as parameters and determine if one type can be used as another.
+% In example~\ref{lst:int_context}, the compiler is trying to unify @int@ and @EnumInstType@ of @Colour@.
+% $$Unification( int, EnumInstType<Colour> )$$ which turns into three Unification call
+% \begin{cfa}[label=lst:attr_resolution_1]
+% {
+% 	Unify( int, char * ); // unify with the type of value
+% 	Unify( int, int ); // unify with the type of position
+% 	Unify( int, char * ); // unify with the type of label
+% }
+% \end{cfa}
+% \begin{cfa}[label=lst:attr_resolution_precedence]
+% {
+% 	Unification( T1, EnumInstType<T2> ) {
+% 		if ( Unify( T1, T2 ) ) return T2;
+% 		if ( Unify( T1, int ) ) return int;
+% 		if ( Unify( T1, char * ) ) return char *;
+% 		Error: Cannot Unify T1 with EnumInstType<T2>;
+% 	}
+% }
+% \end{cfa}
+% After the unification, @EnumInstType@ is replaced by its attributes.
+
+% \begin{cfa}[caption={Unification Functions}, label=lst:unification_func_call]
+% {
+% 	T2 foo ( T1 ); // function take variable with T1 as a parameter
+% 	foo( EnumInstType<T3> ); // Call foo with a variable has type EnumInstType<T3>
+% 	>>>> Unification( T1, EnumInstType<T3> )
+% }
+% \end{cfa}
+% % The conversion can work backward: in restrictive cases, attributes of can be implicitly converted back to the EnumInstType.
+% Backward conversion:
+% \begin{cfa}[caption={Unification Functions}, label=lst:unification_func_call]
+% {
+% 	enum Colour colour = 1;
+% }
+% \end{cfa}
+
+% \begin{cfa}[caption={Unification Functions}, label=lst:unification_func_call]
+% {
+%	Unification( EnumInstType<Colour>, int ) >>> label
+% }
+% \end{cfa}
+% @int@ can be unified with the label of Colour.
+% @5@ is a constant expression $\Rightarrow$ Compiler knows the value during the compilation $\Rightarrow$ turns it into
+% \begin{cfa}
+% {
+%	enum Colour colour = Colour.Green;
+% }
+% \end{cfa}
+% Steps:
+% \begin{enumerate}
+% \item
+% identify @1@ as a constant expression with type @int@, and the value is statically known as @1@
+% \item
+% @unification( EnumInstType<Colour>, int )@: @position( EnumInstType< Colour > )@
+% \item
+% return the enumeration constant at position 1
+% \end{enumerate}
+% \begin{cfa}
+% {
+% 	enum T (int) { ... } // Declaration
+% 	enum T t = 1;
+% }
+% \end{cfa}
+% Steps:
+% \begin{enumerate}
+% \item
+% identify @1@ as a constant expression with type @int@, and the value is statically known as @1@
+% \item
+% @unification( EnumInstType<Colour>, int )@: @value( EnumInstType< Colour > )@
+% \item
+% return the FIRST enumeration constant that has the value 1, by searching through the values array
+% \end{enumerate}
+% The downside of the precedence rule: @EnumInstType@ $\Rightarrow$ @int ( value )@ $\Rightarrow$ @EnumInstType@ may return a different @EnumInstType@ because the value can be repeated and there is no way to know which one is expected $\Rightarrow$ want uniqueness
+
+% \section{Casting}
+% Casting an EnumInstType to some other type T works similarly to unify the EnumInstType with T. For example:
+% \begin{cfa}
+% enum( int ) Foo { A = 10, B = 100, C = 1000 };
+% (int) Foo.A;
+% \end{cfa}
+% The \CFA-compiler unifies @EnumInstType<int>@ with int, with returns @value( Foo.A )@, which has statically known value 10. In other words, \CFA-compiler is aware of a cast expression, and it forms the context for EnumInstType resolution. The expression with type @EnumInstType<int>@ can be replaced by the compile with a constant expression 10, and optionally discard the cast expression.
+
+% \section{Value Conversion}
+% As discussed in section~\ref{lst:var_declaration}, \CFA only saves @position@ as the necessary information. It is necessary for \CFA to generate intermediate code to retrieve other attributes.
+
+% \begin{cfa}
+% Foo a; // int a;
+% int j = a;
+% char * s = a;
+% \end{cfa}
+% Assume stores a value x, which cannot be statically determined. When assigning a to j in line 2, the compiler @Unify@ j with a, and returns @value( a )@. The generated code for the second line will be
+% \begin{cfa}
+% int j = value( Foo, a )
+% \end{cfa}
+% Similarly, the generated code for the third line is
+% \begin{cfa}
+% char * j = label( Foo, a )
+% \end{cfa}
+
+
+\section{Enumerator Initialization}
+
+An enumerator must have a deterministic immutable value, either be explicitly initialized in the enumeration definition, or implicitly initialized by rules.
+
+
+\section{C Enumeration Rule}
+
+A C enumeration has an integral type. If not initialized, the first enumerator implicitly has the integral value 0, and other enumerators have a value equal to its $predecessor + 1$.
+
+
+\section{Auto Initialization}
+
+C auto-initialization works for the integral type @int@ with constant expressions.
+\begin{cfa}
+enum Alphabet ! {
+	A = 'A', B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
+	a = 'a', b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z
+};
+\end{cfa}
+The complexity of the constant expression depends on the level of runtime computation the compiler implements, \eg \CC \lstinline[language={[GNU]C++}]{constexpr} provides complex compile-time computation across multiple types, which blurs the compilation/runtime boundary.
+
+The notion of auto-initialization can be generalized in \CFA through the trait @AutoInitializable@.
+\begin{cfa}
+forall(T) @trait@ AutoInitializable {
+	void ?{}( T & o, T v );				$\C{// initialization}$
+	void ?{}( T & t, zero_t );			$\C{// 0}$
+	T ?++( T & t);						$\C{// increment}$
+};
+\end{cfa}
+In addition, there is an implicit enumeration counter, @ecnt@ of type @T@, managed by the compiler.
+For example, the type @Odd@ satisfies @AutoInitializable@:
+\begin{cfa}
+struct Odd { int i; };
+void ?{}( Odd & o, int v ) { if ( v & 1 ) o.i = v; else /* error not odd */ ; };
+void ?{}( Odd & o, zero_t ) { o.i = 1; };
+Odd ?++( Odd o ) { return (Odd){ o.i + 2 }; };
+\end{cfa}
+and implicit initialization is available.
+\begin{cfa}
+enum( Odd ) { A, B, C = 7, D };			$\C{// 1, 3, 7, 9}$
+\end{cfa}
+where the compiler performs the following transformation and runs the code.
+\begin{cfa}
+enum( Odd ) {
+	?{}( ecnt, @0@ }  ?{}( A, ecnt },	?++( ecnt )  ?{}( B, ecnt ),
+	?{}( ecnt, 7 )  ?{}( C, ecnt ),	?++( ecnt )  ?{}( D, ecnt )
+};
+\end{cfa}
+
+Unfortunately, auto-initialization is not implemented because \CFA is only a transpiler, relying on generated C code to perform the detail work.
+C does not have the equivalent of \CC \lstinline[language={[GNU]C++}]{constexpr}, and it is currently beyond the scope of the \CFA project to implement a complex runtime interpreter in the transpiler.
+Nevertheless, the necessary language concepts exist to support this feature.
+
+
+\section{Enumeration Features}
+
+
+\section{Iteration and Range}
+
+It is convenient to iterate over a \CFA enumeration value, \eg:
+\begin{cfa}[label=lst:range_functions]
+for ( Alphabet alph; Alphabet ) { sout | alph; }
+>>> A B C ... D
+\end{cfa}
+The for-loop uses the enumeration type @Alphabet@ its range, and iterates through all enumerators in the order defined in the enumeration.
+@alph@ is the iterating enumeration object, which returns the value of an @Alphabet@ in this context according to the precedence rule.
+
+\textbullet\ \CFA offers a shorthand for iterating all enumeration constants:
+\begin{cfa}[label=lst:range_functions]
+for ( Alphabet alph ) { sout | alph; }
+>>> A B C ... D
+\end{cfa}
+
+The following are examples for constructing for-control using an enumeration. Note that the type declaration of the iterating variable is optional, because \CFA can infer the type as EnumInstType based on the range expression, and possibly convert it to one of its attribute types.
+
+\textbullet\ H is implicit up-to exclusive range [0, H).
+\begin{cfa}[label=lst:range_function_1]
+for ( alph; Alphabet.D ) { sout | alph; }
+>>> A B C
+\end{cfa}
+
+\textbullet\ ~= H is implicit up-to inclusive range [0,H].
+\begin{cfa}[label=lst:range_function_2]
+for ( alph; ~= Alphabet.D ) { sout | alph; }
+>>> A B C D
+\end{cfa}
+
+\textbullet\ L ~ H is explicit up-to exclusive range [L,H).
+\begin{cfa}[label=lst:range_function_3]
+for ( alph; Alphabet.B ~ Alphabet.D  ) { sout | alph; }
+// for ( Alphabet alph = Alphabet.B; alph < Alphabet.D; alph += 1  ); 1 is one_t
+>>> B C
+\end{cfa}
+
+\textbullet\ L ~= H is explicit up-to inclusive range [L,H].
+\begin{cfa}[label=lst:range_function_4]
+for ( alph; Alphabet.B ~= Alphabet.D  ) { sout | alph; }
+>>> B C D
+\end{cfa}
+
+\textbullet\ L -~ H is explicit down-to exclusive range [H,L), where L and H are implicitly interchanged to make the range down-to.
+\begin{cfa}[label=lst:range_function_5]
+for ( alph; Alphabet.D -~ Alphabet.B  ) { sout | alph; }
+>>> D C
+\end{cfa}
+
+\textbullet\ L -~= H is explicit down-to exclusive range [H,L], where L and H are implicitly interchanged to make the range down-to.
+\begin{cfa}[label=lst:range_function_6]
+for ( alph; Alphabet.D -~= Alphabet.B  ) { sout | alph; }
+>>> D C B
+\end{cfa}
+
+A user can specify the ``step size'' of an iteration. There are two different stepping schemes of enumeration for-loop.
+\begin{cfa}[label=lst:range_function_stepping]
+enum(int) Sequence { A = 10, B = 12, C = 14, D = 16, D  = 18 };
+for ( s; Sequence.A ~= Sequence.D ~ 1  ) { sout | alph; }
+>>> 10 12 14 16 18
+for ( s; Sequence.A ~= Sequence.D; s+=1  ) { sout | alph; }
+>>> 10 11 12 13 14 15 16 17 18
+\end{cfa}
+The first syntax is stepping to the next enumeration constant, which is the default stepping scheme if not explicitly specified. The second syntax, on the other hand, is to call @operator+=@ @one_type@ on the @value( s )@. Therefore, the second syntax is equivalent to
+\begin{cfa}[label=lst:range_function_stepping_converted]
+for ( typeof( value(Sequence.A) ) s=value( Sequence.A ); s <= Sequence.D; s+=1  ) { sout | alph; }
+>>> 10 11 12 13 14 15 16 17 18
+\end{cfa}
+
+% \PAB{Explain what each loop does.}
+
+It is also possible to iterate over an enumeration's labels, implicitly or explicitly:
+\begin{cfa}[label=lst:range_functions_label_implicit]
+for ( char * alph; Alphabet )
+\end{cfa}
+This for-loop implicitly iterates every label of the enumeration, because a label is the only valid resolution to @ch@ with type @char *@ in this case.
+If the value can also be resolved as the @char *@, you might iterate the labels explicitly with the array iteration.
+\begin{cfa}[label=lst:range_functions_label_implicit]
+for ( char * ch; labels( Alphabet ) )
+\end{cfa}
+
+
+% \section{Non-uniform Type}
+% TODO: Working in Progress, might need to change other sections. Conflict with the resolution right now.
+
+% \begin{cfa}
+% enum T( int, char * ) {
+%	 a=42, b="Hello World"
+% };
+% \end{cfa}
+% The enum T declares two different types: int and char *. The enumerators of T hold values of one of the declared types.
+
+\section{Enumeration Inheritance}
+
+\begin{cfa}[label=lst:EnumInline]
+enum( char * ) Name { Jack = "Jack", Jill = "Jill" };
+enum /* inferred */ Name2 { inline Name, Sue = "Sue", Tom = "Tom" };
+\end{cfa}
+\lstinline{Inline} allows Enumeration Name2 to inherit enumerators from Name1 by containment, and a Name enumeration is a subtype of enumeration Name2. An enumeration instance of type Name can be used where an instance of Name2 is expected.
+\begin{cfa}[label=lst:EnumInline]
+Name Fred;
+void f( Name2 );
+f( Fred );
+\end{cfa}
+If enumeration A declares @inline B@ in its enumeration body, enumeration A is the "inlining enum" and enumeration B is the "inlined enum".
+
+An enumeration can inline at most one other enumeration. The inline declaration must be placed before the first enumerator of the inlining enum. The inlining enum has all the enumerators from the inlined enum, with the same labels, values, and position.
+\begin{cfa}[label=lst:EnumInline]
+enum /* inferred */ Name2 { inline Name, Sue = "Sue", Tom = "Tom" };
+// is equivalent to enum Name2 { Jack = "Jack", Jill="Jill", Sue = "Sue", Tom = "Tom" };
+\end{cfa}
+Name.Jack is equivalent to Name2.Jack. Their attributes are all identical. Opening both Name and Name2 in the same scope will not introduce ambiguity.
+\begin{cfa}[label=lst:EnumInline]
+with( Name, Name2 ) { Jack; } // Name.Jack and Name2.Jack are equivalent. No ambiguity
+\end{cfa}
+
+\section{Implementation}
+
+\section{Static Attribute Expression}
+\begin{cfa}[label=lst:static_attr]
+enum( char * ) Colour {
+	Red = "red", Blue = "blue", Green = "green"
+};
+\end{cfa}
+An enumerator expression returns its enumerator value as a constant expression with no runtime cost. For example, @Colour.Red@ is equivalent to the constant expression "red", and \CFA finishes the expression evaluation before generating the corresponding C code. Applying a pseudo-function to a constant enumerator expression results in a constant expression as well. @value( Colour.Red )@, @position( Colour. Red )@, and @label( Colour.Red )@ are equivalent to constant expression with char * value "red", int value 0, and char * value "Red", respectively.
+
+\section{Runtime Attribute Expression and Weak Referenced Data}
+\begin{cfa}[label=lst:dynamic_attr]
+Colour c;
+...
+value( c ); // or c
+\end{cfa}
+An enumeration variable c is equivalent to an integer variable with the value of @position( c )@ In Example~\ref{lst:dynamic_attr}, the value of enumeration variable c is unknown at compile time. In this case, the pseudo-function calls are reduced to expression that returns the enumerator values at runtime.
+
+\CFA stores the variables and labels in @const@ arrays to provide runtime lookup for enumeration information.
+
+\begin{cfa}[label=lst:attr_array]
+const char * Colour_labels [3] = { "Red", "Blue", "Green" };
+const char * Colour_values [3] = { "red", "blue", "green" };
+\end{cfa}
+The \CFA compiles transforms the attribute expressions into array access.
+\begin{cfa}[label=lst:attr_array_access]
+position( c ) // c; an integer
+value( c ); // Colour_values[c]
+label( c ); // Colour_labels[c]
+\end{cfa}
+
+To avoid unnecessary memory usage, the labels and values array are only generated as needed, and only generate once across all compilation units. By default, \CFA defers the declaration of the label and value arrays until an call to attribute function with a dynamic value. If an attribute function is never called on a dynamic value of an enumerator, the array will never be allocated. Once the arrays are created, all compilation units share a weak reference to the allocation array.
+
+\section{Enum Prelude}
+
+\begin{cfa}[label=lst:enum_func_dec]
+forall( T ) {
+	unsigned position( unsigned );
+	T value( unsigned );
+	char * label( unsigned );
+}
+\end{cfa}
+\CFA loads the declaration of enumeration function from the enum.hfa.
+
+\section{Internal Representation}
+
+The definition of an enumeration is represented by an internal type called @EnumDecl@. At the minimum, it stores all the information needed to construct the companion object. Therefore, an @EnumDecl@ can be represented as the following:
+\begin{cfa}[label=lst:EnumDecl]
+forall(T)
+class EnumDecl {
+	T* values;
+	char** label;
+};
+\end{cfa}
+
+The internal representation of an enumeration constant is @EnumInstType@.
+An @EnumInstType@ has a reference to the \CFA-enumeration declaration and the position of the enumeration constant.
+\begin{cfa}[label=lst:EnumInstType]
+class EnumInstType {
+	EnumDecl enumDecl;
+	int position;
+};
+\end{cfa}
+In the later discussion, we will use @EnumDecl<T>@ to symbolize a @EnumDecl@ parameterized by type T, and @EnumInstType<T>@ is a declared instance of @EnumDecl<T>@.
+
+\begin{cfa}[caption={Enum Type Functions}, label=lst:cforall_enum_data]
+const T * const values;
+const char * label;
+int length;
+\end{cfa}
+Companion data are necessary information to represent an enumeration. They are stored as standalone pieces, rather than a structure. Those data will be loaded "on demand".
+Companion data are needed only if the according pseudo-functions are called. For example, the value of the enumeration Workday is loaded only if there is at least one compilation that has call $value(Workday)$. Once the values are loaded, all compilations share these values array to reduce memory usage.
+
+
+% \section{(Rework) Companion Object and Companion Function}
+
+% \begin{cfa}[caption={Enum Type Functions}, label=lst:cforall_enum_functions]
+% forall( T )
+% struct Companion {
+% 	const T * const values;
+%		 const char * label;
+% 	int length;
+% };
+% \end{cfa}
+% \CFA generates companion objects, an instance of structure that encloses @necessary@ data to represent an enumeration. The size of the companion is unknown at the compilation time, and it "grows" in size to compensate for the @usage@.
+
+% The companion object is singleton across the compilation (investigation).
+
+% \CFA generates the definition of companion functions.
+% Because \CFA implicitly stores an enumeration instance as its position, the companion function @position@ does nothing but return the position it is passed.
+% Companions function @value@ and @label@ return the array item at the given position of @values@ and @labels@, respectively.
+% \begin{cfa}[label=lst:companion_definition]
+% int position( Companion o, int pos ) { return pos; }
+% T value( Companion o, int pos ) { return o.values[ pos ]; }
+% char * label( Companion o, int pos ) { return o.labels[ pos ]; }
+% \end{cfa}
+% Notably, the @Companion@ structure definition, and all companion objects, are visible to users.
+% A user can retrieve values and labels defined in an enumeration by accessing the values and labels directly, or indirectly by calling @Companion@ functions @values@ and @labels@
+% \begin{cfa}[label=lst:companion_definition_values_labels]
+% Colour.values; // read the Companion's values
+% values( Colour ); // same as Colour.values
+% \end{cfa}
+
+\section{Companion Traits (experimental)}
+Not sure its semantics yet, and it might replace a companion object.
+\begin{cfa}[label=lst:companion_trait]
+forall(T1) {
+	trait Companion(otype T2<otype T1>) {
+		T1 value((otype T2<otype T1> const &);
+		int position(otype T2<otype T1> const &);
+		char * label(otype T2<otype T1> const &);
+	}
+}
+\end{cfa}
+All enumerations implicitly implement the Companion trait, an interface to access attributes. The Companion can be a data type because it fulfills to requirements to have concrete instances, which are:
+
+\begin{enumerate}
+  \item The instance of enumeration has a single polymorphic type.
+  \item Each assertion should use the type once as a parameter.
+\end{enumerate}
+
+\begin{cfa}
+enum(int) Weekday {
+	Monday=10, Tuesday, ...
+};
+
+T value( enum Weekday<T> & this);
+int position( enum Weekday<T> & this )
+char * label( enum Weekday<T> & this )
+
+trait Companion obj = (enum(int)) Workday.Weekday;
+value(obj); // 10
+\end{cfa}
+The enumeration comes with default implementation to the Companion traits functions. The usage of Companion functions would make \CFA allocates and initializes the necessary companion arrays, and return the data at the position represented by the enumeration.
+(...)
+
+\section{User Define Enumeration Functions}
+
+Companion objects make extending features for \CFA enumeration easy.
+\begin{cfa}[label=lst:companion_user_definition]
+char * charastic_string( Companion o, int position ) {
+	return sprintf( "Label: %s; Value: %s", label( o, position ), value( o, position) );
+}
+printf( charactic_string ( Color, 1 ) );
+>>> Label: Green; Value: G
+\end{cfa}
+Defining a function takes a Companion object effectively defines functions for all \CFA enumeration.
+
+The \CFA compiler turns a function call that takes an enumeration instance as a parameter into a function call with a companion object plus a position.
+Therefore, a user can use the syntax with a user-defined enumeration function call:
+\begin{cfa}[label=lst:companion_user_definition]
+charactic_string( Color.Green ); // equivalent to charactic_string( Color, 1 )
+>>> Label: Green; Value: G
+\end{cfa}
+Similarly, the user can work with the enumeration type itself: (see section ref...)
+\begin{cfa}[ label=lst:companion_user_definition]
+void print_enumerators ( Companion o ) {
+	for ( c : Companion o ) {
+		sout | label (c) | value( c ) ;
+	}
+}
+print_enumerators( Colour );
+\end{cfa}
+
+
+\section{Declaration}
+
+The qualified enumeration syntax is dedicated to \CFA enumeration.
+\begin{cfa}[label=lst:range_functions]
+enum (type_declaration) name { enumerator = const_expr, enumerator = const_expr, ... }
+\end{cfa}
+A compiler stores the name, the underlying type, and all enumerators in an @enumeration table@.
+During the $Validation$ pass, the compiler links the type declaration to the type's definition.
+It ensures that the name of an enumerator is unique within the enumeration body, and checks if all values of the enumerator have the declaration type.
+If the declared type is not @AutoInitializable@, \CFA rejects the enumeration definition.
+Otherwise, it attempts to initialize enumerators with the enumeration initialization pattern. (a reference to a future initialization pattern section)
+
+\begin{cfa}[label=lst:init]
+struct T { ... };
+void ?{}( T & t, zero_t ) { ... };
+void ?{}( T & t, one_t ) { ... };
+T ?+?( T & lhs, T & rhs ) { ... };
+
+enum (T) Sample {
+	Zero: 0 /* zero_t */,
+	One: Zero + 1 /* ?+?( Zero, one_t ) */ , ...
+};
+\end{cfa}
+Challenge: \\
+The value of an enumerator, or the initializer, requires @const_expr@.
+While previously getting around the issue by pushing it to the C compiler, it might not work anymore because of the user-defined types, user-defined @zero_t@, @one_t@, and addition operation.
+Might not be able to implement a \emph{correct} static check.
+
+\CFA $autogens$ a Companion object for the declared enumeration.
+\begin{cfa}[label=lst:companion]
+Companion( T ) Sample {
+	.values: { 0, 0+1, 0+1+1, 0+1+1+1, ... }, /* 0: zero_t, 1: one_t, +: ?+?{} */
+	.labels: { "Zero", "One", "Two", "Three", ...},
+	.length: /* number of enumerators */
+};
+\end{cfa}
+\CFA stores values as intermediate expressions because the result of the function call to the function @?+?{}(T&, T&)@ is statically unknown to \CFA.
+But the result is computed at run time, and the compiler ensures the @values@ are not changed.
+
+\section{Qualified Expression}
+
+\CFA uses qualified expression to address the scoping of \CFA-enumeration.
+\begin{cfa}[label=lst:qualified_expression]
+aggregation_name.field;
+\end{cfa}
+The qualified expression is not dedicated to \CFA enumeration.
+It is a feature that is supported by other aggregation in \CFA as well, including a C enumeration.
+When C enumerations are unscoped, the qualified expression syntax still helps to disambiguate names in the context.
+\CFA recognizes if the expression references a \CFA aggregation by searching the presence of @aggregation_name@ in the \CFA enumeration table.
+If the @aggregation_name@ is identified as a \CFA enumeration, the compiler checks if @field@ presents in the declared \CFA enumeration.
+
+\section{Instance Declaration}
+
+
+\begin{cfa}[label=lst:var_declaration]
+enum Sample s1;
+\end{cfa}
+
+The declaration \CFA-enumeration variable has the same syntax as the C-enumeration. Internally, such a variable will be represented as an EnumInstType.
Index: doc/theses/jiada_liang_MMath/intro.tex
===================================================================
--- doc/theses/jiada_liang_MMath/intro.tex	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ doc/theses/jiada_liang_MMath/intro.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -1,5 +1,30 @@
 \chapter{Introduction}
 
-Testing glossy abbreviations \gls{foo} and \gls{bar}, and glossy definitions \gls{git} and \gls{gulp}.
+Naming values is a common practice in mathematics and engineering, \eg $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MHz (1E6), etc.
+Naming is also commonly used to represent many other numerical phenomenon, such as days of the week, months of a year, floors of a building (basement), specific times (noon, New Years).
+Many programming languages capture this important software engineering capability through a mechanism called an \Newterm{enumeration}.
+An enumeration is similar to other programming-language types by providing a set of constrained values, but adds the ability to name \emph{all} the values in its set.
+Note, all enumeration names must be unique but different names can represent the same value (eight note, quaver), which are synonyms.
 
-And use the glossy abbreviations \gls{foo} and \gls{bar}, and definitions \gls{git} and \gls{gulp} again.
+Specifically, an enumerated type restricts its values to a fixed set of named constants.
+While all types are restricted to a fixed set of values because of the underlying von Neumann architecture, and hence, to a corresponding set of constants, \eg @3@, @3.5@, @3.5+2.1i@, @'c'@, @"abc"@, etc., these values are not named, other than the programming-language supplied constant names.
+
+Fundamentally, all enumeration systems have an \Newterm{enumeration} type with an associated set of \Newterm{enumerator} names.
+An enumeration has three universal attributes, \Newterm{position}, \Newterm{label}, and \Newterm{value}, as shown by this representative enumeration, where position and value can be different.
+\begin{cquote}
+\small\sf\setlength{\tabcolsep}{3pt}
+\begin{tabular}{rccccccccccc}
+\it\color{red}enumeration & \multicolumn{7}{c}{\it\color{red}enumerators}	\\
+$\downarrow$\hspace*{25pt} & \multicolumn{7}{c}{$\downarrow$}				\\
+@enum@ Weekday \{				& Monday,	& Tuesday,	& Wednesday,	& Thursday,& Friday, 	& Saturday,	& Sunday \}; \\
+\it\color{red}position			& 0			& 1			& 2				& 3				& 4			& 5			& 6			\\
+\it\color{red}label				& Monday	& Tuesday	& Wednesday		& Thursday		& Friday 	& Saturday	& Sunday	\\
+\it\color{red}value				& 0			& 1			& 2				& 3				& 4			& 5		& 6
+\end{tabular}
+\end{cquote}
+Here, the \Newterm{enumeration} @Weekday@ defines the ordered \Newterm{enumerator}s @Monday@, @Tuesday@, @Wednesday@, @Thursday@, @Friday@, @Saturday@ and @Sunday@.
+By convention, the successor of @Tuesday@ is @Monday@ and the predecessor of @Tuesday@ is @Wednesday@, independent of the associated enumerator constant values.
+Because an enumerator is a constant, it cannot appear in a mutable context, \eg @Mon = Sun@ is meaningless, and an enumerator has no address, it is an \Newterm{rvalue}\footnote{
+The term rvalue defines an expression that can only appear on the right-hand side of an assignment.}.
+
+\section{Contributions}
Index: doc/theses/jiada_liang_MMath/relatedwork.tex
===================================================================
--- doc/theses/jiada_liang_MMath/relatedwork.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
+++ doc/theses/jiada_liang_MMath/relatedwork.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -0,0 +1,1142 @@
+\chapter{Related Work}
+\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.
+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
+}{}
+
+Classic Pascal has the \lstinline[language=pascal]{const} declaration binding a name to a constant literal/expression.
+\begin{pascal}
+const one = 0 + 1;   Vowels = set of (A,E,I,O,U);   NULL = NIL;
+		 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.
+
+Free Pascal~\cite[\S~3.1.1]{FreePascal} is a modern, object-oriented version of classic Pascal, with a C-style enumeration type.
+Enumerators must be assigned in ascending numerical order with a constant expression and the range can be non-consecutive.
+\begin{pascal}
+Type EnumType = ( one, two, three, forty @= 40@, fortyone );
+\end{pascal}
+Pseudo-functions @Pred@ and @Succ@ can only be used if the range is consecutive.
+The underlying type is an implementation-defined integral-type large enough to hold all enumerated values; it does not have to be the smallest possible type.
+The integral size can be explicitly specified using compiler directive @$PACKENUM@~$N$, where $N$ is the number of bytes, \eg:
+\begin{pascal}
+Type @{$\color{red}\$$PACKENUM 1}@ SmallEnum = ( one, two, three );
+	    @{$\color{red}\$$PACKENUM 4}@ LargeEnum = ( BigOne, BigTwo, BigThree );
+Var S : SmallEnum; { 1 byte }
+	  L : LargeEnum; { 4 bytes}
+\end{pascal}
+
+
+\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
+}{}
+
+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)
+\end{ada}
+No other enumerators are assignable to objects 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.
+\begin{ada}
+type RGB is ( Red, Green, Blue );
+@for RGB use ( Red => 10, Green => 20, Blue => 30 );@ -- ascending order
+\end{ada}
+Hence, the position, value, label tuples are:
+\begin{ada}
+(0, 10, RED)  (1, 20, GREEN)  (2, 30, BLUE) 
+\end{ada}
+
+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.
+
+Ada enumerators are overloadable.
+\begin{ada}
+type Traffic_Light is ( @Red@, Yellow, @Green@ );
+\end{ada}
+Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded names.
+\VRef[Figure]{f:AdaEnumeration} shows how ambiguity is handled using a cast, \eg \lstinline[language=ada]{RGB'(Red)}.
+
+\begin{figure}
+\begin{ada}
+with Ada.Text_IO; use Ada.Text_IO;
+procedure test is
+   type RGB is ( @Red@, Green, Blue );
+   type Traffic_Light is ( @Red@, Yellow, Green );         -- overload
+   procedure @Red@( Colour : RGB ) is begin            -- overload
+       Put_Line( "Colour is " & RGB'Image( Colour ) );
+   end Red;
+   procedure @Red@( TL : Traffic_Light ) is begin       -- overload
+       Put_Line( "Light is " & Traffic_Light'Image( TL ) );
+   end Red;
+begin
+    @Red@( Blue );				 -- RGB
+    @Red@( Yellow );				-- Traffic_Light
+    @Red@( @RGB'(Red)@ );		-- ambiguous without cast
+end test;
+\end{ada}
+\caption{Ada Enumeration Overload Resolution} 
+\label{f:AdaEnumeration} 
+\end{figure}
+
+Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package names.
+\begin{ada}
+OtherRed : RGB renames Red;
+\end{ada}
+which suggests a possible \CFA extension to @typedef@.
+\begin{cfa}
+typedef RGB.Red OtherRed;
+\end{cfa}
+
+There are three pairs of inverse enumeration pseudo-functions (attributes): @'Pos@ and @'Val@, @'Enum_Rep@ and @'Enum_Val@, and @'Image@ and @'Value@,
+\begin{cquote}
+\lstDeleteShortInline@
+\setlength{\tabcolsep}{15pt}
+\begin{tabular}{@{}ll@{}}
+\begin{ada}
+RGB'Pos( Red ) = 0;
+RGB'Enum_Rep( Red ) = 10;
+RGB'Image( Red ) = "RED";
+\end{ada}
+&
+\begin{ada}
+RGB'Val( 0 ) = Red
+RGB'Enum_Val( 10 ) =  Red
+RGB'Value( "Red" ) =  Red
+\end{ada}
+\end{tabular}
+\lstMakeShortInline@
+\end{cquote}
+These attributes are important for IO.
+An enumeration type @T@ also has the following attributes: @T'First@, @T'Last@, @T'Range@, @T'Pred@, @T'Succ@, @T'Min@, and @T'Max@, producing an intuitive result based on the attribute name.
+
+Ada allows the enumerator label to be a character constant.
+\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.
+\begin{ada}
+Op := '+';
+case Op is                    -- all enumerators must appear
+	when '+' => ... ;
+	when '-' => ... ;
+	when '*' => ... ;
+	when '/' => ... ;
+end case;
+\end{ada}
+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.
+\begin{ada}
+type Boolean is (False, True); -- False / True not keywords
+@Flag@ : Boolean;
+if @Flag@ then ...    -- conditional
+\end{ada}
+Since only types derived from @Boolean@ can be a conditional, @Boolean@ is essentially  a builtin type.
+
+Ada provides \emph{consecutive} subtyping of an enumeration using \lstinline[language=ada]{range}.
+\begin{ada}
+type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
+subtype Weekday is Week @range Mon .. Fri@;
+subtype Weekend is Week @range Sat .. Sun@;
+Day : Week;
+\end{ada}
+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.
+\begin{cquote}
+\lstDeleteShortInline@
+\setlength{\tabcolsep}{15pt}
+\begin{tabular}{@{}ll@{}}
+\begin{ada}
+case Day is
+	when @Mon .. Fri@ => ... ;
+	when @Sat .. Sun@ => ... ;
+end case;
+\end{ada}
+&
+\begin{ada}
+case Day is
+	when @Weekday@ => ... ;  -- subtype ranges
+	when @Weekend@ => ... ;
+end case;
+\end{ada}
+\end{tabular}
+\end{cquote}
+
+\begin{cquote}
+\setlength{\tabcolsep}{12pt}
+\begin{tabular}{@{}lll@{}}
+\begin{ada}
+for Day in @Mon .. Sun@ loop
+	...
+end loop;
+\end{ada}
+&
+\begin{ada}
+for Day in @Weekday@ loop
+	...
+end loop;
+\end{ada}
+&
+\begin{ada}
+for Day in @Weekend@ loop
+	...
+end loop;
+\end{ada}
+\end{tabular}
+\lstMakeShortInline@
+\end{cquote}
+
+An enumeration type can be used as an array dimension and subscript.
+\begin{ada}
+Lunch : array( @Week@ ) of Time;
+for Day in Week loop
+	Lunch( @Day@ ) := ... ;       -- set lunch time
+end loop;
+\end{ada}
+
+
+\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
+}{}
+
+\CC is largely backwards compatible with C, so it inherited C's enumerations.
+However, the following non-backwards compatible changes have been made.
+
+\begin{cquote}
+7.2 Change: \CC objects of enumeration type can only be assigned values of the same enumeration type.
+In C, objects of enumeration type can be assigned values of any integral type. \\
+Example:
+\begin{c++}
+enum color { red, blue, green };
+color c = 1;			 				$\C{// valid C, invalid C++}$
+\end{c++}
+\textbf{Rationale}: The type-safe nature of \CC. \\
+\textbf{Effect on original feature}: Deletion of semantically well-defined feature. \\
+\textbf{Difficulty of converting}: Syntactic transformation. (The type error produced by the assignment can be automatically corrected by applying an explicit cast.) \\
+\textbf{How widely used}: Common.
+\end{cquote}
+
+\begin{cquote}
+7.2 Change: In \CC, the type of an enumerator is its enumeration.
+In C, the type of an enumerator is @int@. \\
+Example:
+\begin{c++}
+enum e { A };
+sizeof(A) == sizeof(int)		 		$\C{// in C}$
+sizeof(A) == sizeof(e)		 			$\C{// in C++}$
+/* and sizeof(int) is not necessary equal to sizeof(e) */
+\end{c++}
+\textbf{Rationale}: In \CC, an enumeration is a distinct type. \\
+\textbf{Effect on original feature}: Change to semantics of well-defined feature. \\
+\textbf{Difficulty of converting}: Semantic transformation. \\
+\textbf{How widely used}: Seldom. The only time this affects existing C code is when the size of an enumerator is taken.
+Taking the size of an enumerator is not a common C coding practice.
+\end{cquote}
+
+Hence, the values in a \CC enumeration can only be its enumerators (without a cast).
+While the storage size of an enumerator is up to the compiler, there is still an implicit cast to @int@.
+\begin{c++}
+enum E { A, B, C };
+E e = A;
+int i = A;   i = e;	 					$\C{// implicit casts to int}$
+\end{c++}
+\CC{11} added a scoped enumeration, \lstinline[language=c++]{enum class} (or \lstinline[language=c++]{enum struct}), where the enumerators are accessed using type qualification.
+\begin{c++}
+enum class E { A, B, C };
+E e = @E::@A;	 						$\C{// qualified enumerator}$
+e = B;	 								$\C{// B not in scope}$
+\end{c++}
+\CC{20} supports explicit unscoping with a \lstinline[language=c++]{using enum} declaration.
+\begin{c++}
+enum class E { A, B, C };
+@using enum E;@
+E e = A;	 							$\C{// direct access}$
+e = B;	 								$\C{// direct access}$
+\end{c++}
+\CC{11} added the ability to explicitly declare the underlying \emph{integral} type for \lstinline[language=c++]{enum class}.
+\begin{c++}
+enum class RGB @: long@ { Red, Green, Blue };
+enum class rgb @: char@ { Red = 'r', Green = 'g', Blue = 'b' };
+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.
+\begin{c++}
+rgb crgb = rgb::Red;
+char ch = rgb::Red;   ch = crgb;		$\C{// disallowed}$
+\end{c++}
+Finally, there is no mechanism to iterate through an enumeration nor use the enumeration type to declare an array dimension.
+
+
+\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
+}{}
+
+% 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.
+\begin{csharp}
+enum Weekday : byte { Monday, Tuesday, Wednesday, Thursday@ = 10@, Friday, Saturday, Sunday@,@ };
+\end{csharp}
+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();
+\end{csharp}
+
+The @Enum.GetValues@ pseudo-method retrieves an array of the enumeration constants for looping over an enumeration type or variable.
+\begin{csharp}
+foreach ( Weekday constant in @Enum.GetValues@( typeof(Weekday) ) ) {
+	Console.WriteLine( constant + " " + (int)constant ); // label, position
+}
+\end{csharp}
+
+The @Flags@ attribute creates a bit-flags enumeration, allowing bitwise operators @&@, @|@, @~@ (complement), @^@ (xor).
+\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
+\end{csharp}
+
+\Csharp supports an enumeration class to embed enumeration operations, where the enumerators are objects.
+\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) { }
+}
+\end{csharp}
+Find a meaningful example and test it.
+
+
+\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.
+\begin{Go}
+const ( R = 0; G; B )					$\C{// implicit: 0 0 0}$
+const ( Fred = "Fred"; Mary = "Mary"; Jane = "Jane" ) $\C{// explicit: Fred Mary Jane}$
+const ( S = 0; T; USA = "USA"; U; V = 3.1; W ) $\C{// type change, implicit/explicit: 0 0 USA USA 3.1 3.1}$
+\end{Go}
+Constant names are unscoped and must be unique (no overloading).
+The first enumerator \emph{must} be explicitly initialized;
+subsequent enumerators can be implicitly or explicitly initialized.
+Implicit initialization is the previous (predecessor) enumerator value.
+
+Auto-incrementing is supported by the keyword \lstinline[language=Go]{iota}, available only in the \lstinline[language=Go]{const} declaration.
+The \lstinline[language=Go]{iota} is a \emph{per \lstinline[language=golang]{const} declaration} integer counter, starting at zero and implicitly incremented by one for each \lstinline[language=golang]{const} identifier (enumerator).
+\begin{Go}
+const ( R = @iota@; G; B )				$\C{// implicit: 0 1 2}$
+const ( C = @iota + B + 1@; G; Y )		$\C{// implicit: 3 4 5}$
+\end{Go}
+An underscore \lstinline[language=golang]{const} identifier advances \lstinline[language=Go]{iota}.
+\begin{Go}
+const ( O1 = iota + 1; @_@; O3; @_@; O5 ) // 1, 3, 5 
+\end{Go}
+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
+\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
+\end{Go}
+Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier.
+
+
+\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:
+\begin{Java}
+public enum PizzaStatus {
+    ORDERED,
+    READY, 
+    DELIVERED; 
+}
+\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:
+\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.
+}
+\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:
+\begin{Java}
+if(testPz.getStatus().equals(Pizza.PizzaStatus.DELIVERED)); 
+if(testPz.getStatus() == Pizza.PizzaStatus.DELIVERED); 
+\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:
+\begin{Java}
+if(testPz.getStatus().equals(TestColor.GREEN));
+if(testPz.getStatus() == TestColor.GREEN);
+\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;
+}
+\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:
+\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.
+}
+\end{Java}
+The test snippet below demonstrates how this works:
+\begin{Java}
+@Test
+public void givenPizaOrder_whenReady_thenDeliverable() {
+    Pizza testPz = new Pizza();
+    testPz.setStatus(Pizza.PizzaStatus.READY);
+    assertTrue(testPz.isDeliverable());
+}
+\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:
+\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.
+}
+\end{Java}
+
+Executing the following test demonstrates the power of the EnumSet implementation of the Set interface:
+\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); 
+}
+\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}
+
+
+\section{Modula-3}
+
+\section{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.
+
+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.
+
+If you are familiar with C, you will know that C enumerations assign related names to a set of integer values.
+Enumerations in Swift are much more flexible, and don't have to provide a value for each case of the enumeration.
+If a value (known as a raw value) is provided for each enumeration case, the value can be a string, a character, or a value of any integer or floating-point type.
+
+Alternatively, enumeration cases can specify associated values of any type to be stored along with each different case value, much as unions or variants do in other languages.
+You can define a common set of related cases as part of one enumeration, each of which has a different set of values of appropriate types associated with it.
+
+Enumerations in Swift are first-class types in their own right.
+They adopt many features traditionally supported only by classes, such as computed properties to provide additional information about the enumeration's current value, and instance methods to provide functionality related to the values the enumeration represents.
+Enumerations can also define initializers to provide an initial case value;
+can be extended to expand their functionality beyond their original implementation; and can conform to protocols to provide standard functionality.
+
+For more about these capabilities, see Properties, Methods, Initialization, Extensions, and Protocols.
+
+\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:
+Swift enumeration cases don't have an integer value set by default, unlike languages like C and Objective-C.
+In the CompassPoint example above, @north@, @south@, @east@ and @west@ don't implicitly equal 0, 1, 2 and 3.
+Instead, the different enumeration cases are values in their own right, with an explicitly defined type of CompassPoint.
+
+Multiple cases can appear on a single line, separated by commas:
+\begin{swift}
+enum Planet {
+	case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
+}
+\end{swift}
+Each enumeration definition defines a new type.
+Like other types in Swift, their names (such as @CompassPoint@ and @Planet@) start with a capital letter.
+Give enumeration types singular rather than plural names, so that they read as self-evident:
+\begin{swift}
+var directionToHead = CompassPoint.west
+\end{swift}
+The type of @directionToHead@ is inferred when it's initialized with one of the possible values of @CompassPoint@.
+Once @directionToHead@ is declared as a @CompassPoint@, you can set it to a different @CompassPoint@ value using a shorter dot syntax:
+\begin{swift}
+directionToHead = .east
+\end{swift}
+The type of @directionToHead@ is already known, and so you can drop the type when setting its value.
+This makes for highly readable code when working with explicitly typed enumeration values.
+
+\paragraph{Matching Enumeration Values with a Switch Statement}
+
+You can match individual enumeration values with a switch statement:
+\begin{swift}
+directionToHead = .south
+switch directionToHead {
+case .north:
+	print("Lots of planets have a north")
+case .south:
+	print("Watch out for penguins")
+case .east:
+	print("Where the sun rises")
+case .west:
+	print("Where the skies are blue")
+}
+// Prints "Watch out for penguins"
+\end{swift}
+You can read this code as:
+\begin{quote}
+"Consider the value of directionToHead.
+In the case where it equals @.north@, print "Lots of planets have a north".
+In the case where it equals @.south@, print "Watch out for penguins"."
+
+...and so on.
+\end{quote}
+As described in Control Flow, a switch statement must be exhaustive when considering an enumeration's cases.
+If the case for @.west@ is omitted, this code doesn't compile, because it doesn't consider the complete list of @CompassPoint@ cases.
+Requiring exhaustiveness ensures that enumeration cases aren't accidentally omitted.
+
+When it isn't appropriate to provide a case for every enumeration case, you can provide a default case to cover any cases that aren't addressed explicitly:
+\begin{swift}
+let somePlanet = Planet.earth
+switch somePlanet {
+case .earth:
+	print("Mostly harmless")
+default:
+	print("Not a safe place for humans")
+}
+// Prints "Mostly harmless"
+\end{swift}
+
+\paragraph{Iterating over Enumeration Cases}
+
+For some enumerations, it's useful to have a collection of all of that enumeration's cases.
+You enable this by writing @CaseIterable@ after the enumeration's name.
+Swift exposes a collection of all the cases as an allCases property of the enumeration type.
+Here's an example:
+\begin{swift}
+enum Beverage: CaseIterable {
+	case coffee, tea, juice
+}
+let numberOfChoices = Beverage.allCases.count
+print("\(numberOfChoices) beverages available")
+// Prints "3 beverages available"
+\end{swift}
+In the example above, you write @Beverage.allCases@ to access a collection that contains all of the cases of the @Beverage@ enumeration.
+You can use @allCases@ like any other collection -- the collection's elements are instances of the enumeration type, so in this case they're Beverage values.
+The example above counts how many cases there are, and the example below uses a for-in loop to iterate over all the cases.
+\begin{swift}
+for beverage in Beverage.allCases {
+	print(beverage)
+}
+// coffee
+// tea
+// juice
+\end{swift}
+The syntax used in the examples above marks the enumeration as conforming to the @CaseIterable@ protocol.
+For information about protocols, see Protocols.
+
+\paragraph{Associated Values}
+The examples in the previous section show how the cases of an enumeration are a defined (and typed) value in their own right.
+You can set a constant or variable to Planet.earth, and check for this value later.
+However, it's sometimes useful to be able to store values of other types alongside these case values.
+This additional information is called an associated value, and it varies each time you use that case as a value in your code.
+
+You can define Swift enumerations to store associated values of any given type, and the value types can be different for each case of the enumeration if needed.
+Enumerations similar to these are known as discriminated unions, tagged unions, or variants in other programming languages.
+
+For example, suppose an inventory tracking system needs to track products by two different types of barcode.
+Some products are labeled with 1D barcodes in UPC format, which uses the numbers 0 to 9.
+Each barcode has a number system digit, followed by five manufacturer code digits and five product code digits.
+These are followed by a check digit to verify that the code has been scanned correctly:
+
+Other products are labeled with 2D barcodes in QR code format, which can use any ISO 8859-1 character and can encode a string up to 2,953 characters long:
+
+It's convenient for an inventory tracking system to store UPC barcodes as a tuple of four integers, and QR code barcodes as a string of any length.
+
+In Swift, an enumeration to define product barcodes of either type might look like this:
+\begin{swift}
+enum Barcode {
+	case upc(Int, Int, Int, Int)
+	case qrCode(String)
+}
+\end{swift}
+This can be read as:
+\begin{quote}
+"Define an enumeration type called Barcode, which can take either a value of upc with an associated value of type @(Int, Int, Int, Int)@, or a value of @qrCode@ with an associated value of type @String@."
+\end{quote}
+This definition doesn't provide any actual @Int@ or @String@ values -- it just defines the type of associated values that Barcode constants and variables can store when they're equal to @Barcode.upc@ or @Barcode.qrCode@.
+
+You can then create new barcodes using either type:
+\begin{swift}
+var productBarcode = Barcode.upc(8, 85909, 51226, 3)
+\end{swift}
+This example creates a new variable called @productBarcode@ and assigns it a value of @Barcode.upc@ with an associated tuple value of @(8, 85909, 51226, 3)@.
+
+You can assign the same product a different type of barcode:
+\begin{swift}
+productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
+\end{swift}
+At this point, the original @Barcode.upc@ and its integer values are replaced by the new @Barcode.qrCode@ and its string value.
+Constants and variables of type Barcode can store either a @.upc@ or a @.qrCode@ (together with their associated values), but they can store only one of them at any given time.
+
+You can check the different barcode types using a switch statement, similar to the example in Matching Enumeration Values with a Switch Statement.
+This time, however, the associated values are extracted as part of the switch statement.
+You extract each associated value as a constant (with the let prefix) or a variable (with the var prefix) for use within the switch case's body:
+\begin{swift}
+switch productBarcode {
+case .upc(let numberSystem, let manufacturer, let product, let check):
+	print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
+case .qrCode(let productCode):
+	print("QR code: \(productCode).")
+}
+// Prints "QR code: ABCDEFGHIJKLMNOP."
+\end{swift}
+If all of the associated values for an enumeration case are extracted as constants, or if all are extracted as variables, you can place a single let or var annotation before the case name, for brevity:
+\begin{swift}
+switch productBarcode {
+case let .upc(numberSystem, manufacturer, product, check):
+	print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
+case let .qrCode(productCode):
+	print("QR code: \(productCode).")
+}
+// Prints "QR code: ABCDEFGHIJKLMNOP."
+\end{swift}
+
+\paragraph{Raw Values}
+
+The barcode example in Associated Values shows how cases of an enumeration can declare that they store associated values of different types.
+As an alternative to associated values, enumeration cases can come prepopulated with default values (called raw values), which are all of the same type.
+
+Here's an example that stores raw ASCII values alongside named enumeration cases:
+\begin{swift}
+enum ASCIIControlCharacter: Character {
+	case tab = "\t"
+	case lineFeed = "\n"
+	case carriageReturn = "\r"
+}
+\end{swift}
+Here, the raw values for an enumeration called ASCIIControlCharacter are defined to be of type Character, and are set to some of the more common ASCII control characters.
+Character values are described in Strings and Characters.
+
+Raw values can be strings, characters, or any of the integer or floating-point number types.
+Each raw value must be unique within its enumeration declaration.
+
+Note
+
+Raw values are not the same as associated values.
+Raw values are set to prepopulated values when you first define the enumeration in your code, like the three ASCII codes above.
+The raw value for a particular enumeration case is always the same.
+Associated values are set when you create a new constant or variable based on one of the enumeration's cases, and can be different each time you do so.
+Implicitly Assigned Raw Values
+
+When you're working with enumerations that store integer or string raw values, you don't have to explicitly assign a raw value for each case.
+When you don't, Swift automatically assigns the values for you.
+
+For example, when integers are used for raw values, the implicit value for each case is one more than the previous case.
+If the first case doesn't have a value set, its value is 0.
+
+The enumeration below is a refinement of the earlier Planet enumeration, with integer raw values to represent each planet's order from the sun:
+
+\begin{swift}
+enum Planet: Int {
+	case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
+}
+\end{swift}
+In the example above, Planet.mercury has an explicit raw value of 1, Planet.venus has an implicit raw value of 2, and so on.
+
+When strings are used for raw values, the implicit value for each case is the text of that case's name.
+
+The enumeration below is a refinement of the earlier CompassPoint enumeration, with string raw values to represent each direction's name:
+\begin{swift}
+enum CompassPoint: String {
+	case north, south, east, west
+}
+\end{swift}
+In the example above, CompassPoint.south has an implicit raw value of "south", and so on.
+
+You access the raw value of an enumeration case with its rawValue property:
+\begin{swift}
+let earthsOrder = Planet.earth.rawValue
+// earthsOrder is 3
+
+let sunsetDirection = CompassPoint.west.rawValue
+// sunsetDirection is "west"
+\end{swift}
+
+\paragraph{Initializing from a Raw Value}
+
+If you define an enumeration with a raw-value type, the enumeration automatically receives an initializer that takes a value of the raw value's type (as a parameter called rawValue) and returns either an enumeration case or nil.
+You can use this initializer to try to create a new instance of the enumeration.
+
+This example identifies Uranus from its raw value of 7:
+\begin{swift}
+let possiblePlanet = Planet(rawValue: 7)
+// possiblePlanet is of type Planet? and equals Planet.uranus
+\end{swift}
+Not all possible Int values will find a matching planet, however.
+Because of this, the raw value initializer always returns an optional enumeration case.
+In the example above, possiblePlanet is of type Planet?, or "optional Planet."
+Note
+
+The raw value initializer is a failable initializer, because not every raw value will return an enumeration case.
+For more information, see Failable Initializers.
+
+If you try to find a planet with a position of 11, the optional Planet value returned by the raw value initializer will be nil:
+\begin{swift}
+let positionToFind = 11
+if let somePlanet = Planet(rawValue: positionToFind) {
+	switch somePlanet {
+	case .earth:
+		print("Mostly harmless")
+	default:
+		print("Not a safe place for humans")
+	}
+} else {
+	print("There isn't a planet at position \(positionToFind)")
+}
+// Prints "There isn't a planet at position 11"
+\end{swift}
+This example uses optional binding to try to access a planet with a raw value of 11.
+The statement if let somePlanet = Planet(rawValue: 11) creates an optional Planet, and sets somePlanet to the value of that optional Planet if it can be retrieved.
+In this case, it isn't possible to retrieve a planet with a position of 11, and so the else branch is executed instead.
+
+\paragraph{Recursive Enumerations}
+
+A recursive enumeration is an enumeration that has another instance of the enumeration as the associated value for one or more of the enumeration cases.
+You indicate that an enumeration case is recursive by writing indirect before it, which tells the compiler to insert the necessary layer of indirection.
+
+For example, here is an enumeration that stores simple arithmetic expressions:
+\begin{swift}
+enum ArithmeticExpression {
+	case number(Int)
+	indirect case addition(ArithmeticExpression, ArithmeticExpression)
+	indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
+}
+\end{swift}
+You can also write indirect before the beginning of the enumeration to enable indirection for all of the enumeration's cases that have an associated value:
+\begin{swift}
+indirect enum ArithmeticExpression {
+	case number(Int)
+	case addition(ArithmeticExpression, ArithmeticExpression)
+	case multiplication(ArithmeticExpression, ArithmeticExpression)
+}
+\end{swift}
+This enumeration can store three kinds of arithmetic expressions: a plain number, the addition of two expressions, and the multiplication of two expressions.
+The addition and multiplication cases have associated values that are also arithmetic expressions -- these associated values make it possible to nest expressions.
+For example, the expression (5 + 4) * 2 has a number on the right-hand side of the multiplication and another expression on the left-hand side of the multiplication.
+Because the data is nested, the enumeration used to store the data also needs to support nesting -- this means the enumeration needs to be recursive.
+The code below shows the ArithmeticExpression recursive enumeration being created for (5 + 4) * 2:
+\begin{swift}
+let five = ArithmeticExpression.number(5)
+let four = ArithmeticExpression.number(4)
+let sum = ArithmeticExpression.addition(five, four)
+let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
+\end{swift}
+A recursive function is a straightforward way to work with data that has a recursive structure.
+For example, here's a function that evaluates an arithmetic expression:
+\begin{swift}
+func evaluate(_ expression: ArithmeticExpression) -> Int {
+	switch expression {
+	case let .number(value):
+		return value
+	case let .addition(left, right):
+		return evaluate(left) + evaluate(right)
+	case let .multiplication(left, right):
+		return evaluate(left) * evaluate(right)
+	}
+}
+
+print(evaluate(product))
+// Prints "18"
+\end{swift}
+This function evaluates a plain number by simply returning the associated value.
+It evaluates an addition or multiplication by evaluating the expression on the left-hand side, evaluating the expression on the right-hand side, and then adding them or multiplying them.
+
+
+\section{Python}
+
+\section{Algebraic Data Type}
Index: doc/theses/jiada_liang_MMath/uw-ethesis-frontpgs.tex
===================================================================
--- doc/theses/jiada_liang_MMath/uw-ethesis-frontpgs.tex	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ doc/theses/jiada_liang_MMath/uw-ethesis-frontpgs.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -131,5 +131,8 @@
 \begin{center}\textbf{Abstract}\end{center}
 
-Enumerated type ...
+An enumeration is a type defining an ordered set of named constant values, where a name abstracts a value, \eg @PI@ versus @3.145159@.
+C restrict an enumeration type to the integral type @signed int@, which \CC support , meaning enumeration names bind to integer constants.
+\CFA extends C enumerations to allow all basic and custom types for the enumeration type, like other modern programming languages.
+Furthermore, \CFA adds other useful features for enumerations to support better software-engineering practices and simplify program development.
 
 \cleardoublepage
Index: doc/theses/jiada_liang_MMath/uw-ethesis.tex
===================================================================
--- doc/theses/jiada_liang_MMath/uw-ethesis.tex	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ doc/theses/jiada_liang_MMath/uw-ethesis.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -91,8 +91,8 @@
 % cfa macros used in the document
 \input{common}
-%\usepackageinput{common}
+%\usepackage{common}
 \CFAStyle						% CFA code-style
-\lstset{language=CFA}					% default language
-\lstset{basicstyle=\linespread{0.9}\sf}			% CFA typewriter font
+\lstset{language=cfa,belowskip=-1pt}					% set default language to CFA
+
 \newcommand{\newtermFont}{\emph}
 \newcommand{\Newterm}[1]{\newtermFont{#1}}
@@ -211,6 +211,7 @@
 \input{intro}
 \input{background}
-\input{content1}
-\input{content2}
+\input{CFAenum}
+\input{implementation}
+\input{relatedwork}
 \input{performance}
 \input{conclusion}
Index: doc/user/user.tex
===================================================================
--- doc/user/user.tex	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ doc/user/user.tex	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -11,6 +11,6 @@
 %% Created On       : Wed Apr  6 14:53:29 2016
 %% Last Modified By : Peter A. Buhr
-%% Last Modified On : Tue Jan 30 09:02:41 2024
-%% Update Count     : 6046
+%% Last Modified On : Mon Feb 12 11:50:26 2024
+%% Update Count     : 6199
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
@@ -4177,4 +4177,7 @@
 The \CFA header file for the I/O library is \Indexc{fstream.hfa}.
 
+
+\subsubsection{Stream Output}
+
 For implicit formatted output, the common case is printing a series of variables separated by whitespace.
 \begin{cquote}
@@ -4255,9 +4258,12 @@
 Note, \CFA stream variables ©stdin©, ©stdout©, ©stderr©, ©exit©, and ©abort© overload C variables ©stdin©, ©stdout©, ©stderr©, and functions ©exit© and ©abort©, respectively.
 
+
+\subsubsection{Stream Input}
+
 For implicit formatted input, the common case is reading a sequence of values separated by whitespace, where the type of an input constant must match with the type of the input variable.
 \begin{cquote}
 \begin{lrbox}{\myboxA}
 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
-int x;   double y   char z;
+char c;   int i;   double d
 \end{cfa}
 \end{lrbox}
@@ -4266,17 +4272,17 @@
 \multicolumn{1}{c@{\hspace{2em}}}{\textbf{\CFA}}	& \multicolumn{1}{c@{\hspace{2em}}}{\textbf{\CC}}	& \multicolumn{1}{c}{\textbf{Python}}	\\
 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
-sin | x | y | z;
+sin | c | i | d;
 \end{cfa}
 &
 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
-cin >> x >> y >> z;
+cin >> c >> i >> d;
 \end{cfa}
 &
 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
-x = int(input());  y = float(input());  z = input();
+c = input();   i = int(input());   d = float(input());
 \end{cfa}
 \\
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
-®1® ®2.5® ®A®
+®A® ®1® ®2.5®
 
 
@@ -4284,5 +4290,5 @@
 &
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
-®1® ®2.5® ®A®
+®A® ®1® ®2.5®
 
 
@@ -4290,7 +4296,7 @@
 &
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
+®A®
 ®1®
 ®2.5®
-®A®
 \end{cfa}
 \end{tabular}
@@ -4309,12 +4315,43 @@
 For floating-point types, any number of decimal digits, optionally preceded by a sign (©+© or ©-©), optionally containing a decimal point, and optionally followed by an exponent, ©e© or ©E©, with signed (optional) decimal digits.
 Floating-point values can also be written in hexadecimal format preceded by ©0x© or ©0X© with hexadecimal digits and exponent denoted by ©p© or ©P©.
-In all cases, all whitespace characters are skipped until an appropriate value is found.
-\Textbf{If an appropriate value is not found, the exception ©missing_data© is raised.}
-
-For the C-string type, there are two input forms: any number of \Textbf{non-whitespace} characters or a quoted sequence containing any characters except the closing quote, \ie there is no escape character supported in the string..
-In both cases, the string is null terminated ©'\0'©.
-For the quoted string, the start and end quote characters can be any character and do not have to match \see{\ref{XXX}}.
-
-\VRef[Figure]{f:IOStreamFunctions} shows the I/O stream operations for interacting with files other than ©cin©, ©cout©, and ©cerr©.
+In all cases, whitespace characters are skipped until an appropriate value is found.
+\begin{cfa}[belowskip=0pt]
+char ch;  int i;  float f; double d;  _Complex double cxd;
+sin | ch | i | f | d | cxd;
+X   42   1234.5     0xfffp-2    3.5+7.1i
+\end{cfa}
+It is also possible to scan and ignore specific strings and whitespace using a string format.
+\begin{cfa}[belowskip=0pt]
+sin | "abc def";						§\C{// space matches arbitrary whitespace (2 blanks, 2 tabs)}§
+\end{cfa}
+\begin{cfa}[showspaces=true,showtabs=true,aboveskip=0pt,belowskip=0pt]
+®abc  		def®
+\end{cfa}
+A non-whitespace format character reads the next input character, compares the format and input characters, and if equal, the input character is discarded and the next format character is tested.
+Note, a single whitespace in the format string matches \Textbf{any} quantity of whitespace characters from the stream (including none).
+
+For the C-string type, the default input format is any number of \Textbf{non-whitespace} characters.
+There is no escape character supported in an input string, but any Latin-1 character can be typed directly in the input string.
+For example, if the following non-whitespace output is redirected into a file by the shell:
+\begin{cfa}[belowskip=0pt]
+sout | "\n\t\f\0234\x23";
+\end{cfa}
+it can be read back from the file by redirecting the file as input using:
+\begin{cfa}[belowskip=0pt]
+char s[64];
+sin | wdi( sizeof(s), s );				§\C{// must specify string size}§
+\end{cfa}
+The input string is always null terminated ©'\0'© in the input variable.
+Because of potential buffer overrun when reading C strings, strings are restricted to work with input manipulators \see{\VRef{s:InputManipulators}}.
+As well, there are multiple input-manipulators for scanning complex input string formats, \eg a quoted character or string.
+
+\Textbf{In all cases, if an invalid data value is not found for a type or format string, the exception ©missing_data© is raised and the input variable is unchanged.}
+For example, when reading an integer and the string ©"abc"© is found, the exception ©missing_data© is raised to ensure the program does not proceed erroneously.
+If a valid data value is found, but it is larger than the capacity of the input variable, such reads are undefined.
+
+
+\subsubsection{Stream Files}
+
+\VRef[Figure]{f:IOStreamFunctions} shows the I/O stream operations for interacting with files other than ©sin©, ©sout©, and ©cerr©.
 \begin{itemize}[topsep=4pt,itemsep=2pt,parsep=0pt]
 \item
@@ -4932,49 +4969,43 @@
 
 \subsection{Input Manipulators}
-
-The following \Index{manipulator}s control scanning of input values (reading), and only affect the format of the argument.
-
-Certain manipulators support a \newterm{scanset}, which is a simple regular expression, where the matching set contains any Latin-1 character (8-bits) or character ranges using minus.
+\label{s:InputManipulators}
+
+A string variable \emph{must} be large enough to contain the input sequence.
+To force programmers to consider buffer overruns for C-string input, C-strings may only be read with a width field, which should specify a size less than or equal to the C-string size, \eg:
+\begin{cfa}
+char line[64];
+sin | wdi( ®sizeof(line)®, line );		§\C{// must specify string size}§
+\end{cfa}
+
+Certain input manipulators support a \newterm{scanset}, which is a simple regular expression, where the matching set contains any Latin-1 character (8-bits) or character ranges using minus.
 For example, the scanset \lstinline{"a-zA-Z -/?§"} matches any number of characters between ©'a'© and ©'z'©, between ©'A'© and ©'Z'©, between space and ©'/'©, and characters ©'?'© and (Latin-1) ©'§'©.
 The following string is matched by this scanset:
 \begin{cfa}
-!&%$  abAA () ZZZ  ??  xx§\S\S\S§
-\end{cfa}
-To match a minus, put it as the first character, ©"-0-9"©.
-Other complex forms of regular-expression matching are not supported.
-
-A string variable \emph{must} be large enough to contain the input sequence.
-To force programmers to consider buffer overruns for C-string input, C-strings can only be read with a width field, which should specify a size less than or equal to the C-string size, \eg:
-\begin{cfa}
-char line[64];
-sin | wdi( ®sizeof(line)®, line ); // must specify size
-\end{cfa}
-
-Currently, there is no mechanism to detect if a value read exceeds the capwhen Most types are finite sized, \eg integral types only store value that fit into their corresponding storage, 8, 16, 32, 64, 128 bits.
-Hence, an input value may be too large, and the result of the read is often considered undefined, which leads to difficlt to locate runtime errors.
-All reads in \CFA check if values do not fit into the argument variable's type and raise the exception 
-All types are
+!&%$  abAA () ZZZ  ??§\S§  xx§\S\S§
+\end{cfa}
+To match a minus, make it the first character in the set, \eg ©"©{\color{red}\raisebox{-1pt}{\texttt{-}}}©0-9"©.
+Other complex forms of regular-expression matching are unsupported.
+
+The following \Index{manipulator}s control scanning of input values (reading) and only affect the format of the argument.
 
 \begin{enumerate}
 \item
-\Indexc{skip}( scanset )\index{manipulator!skip@©skip©}, ©skip©( $N$ )
-The first form uses a scanset to skip matching characters.
-The second form skips the next $N$ characters, including newline.
-If the match successes, the input characters are discarded, and input continues with the next character.
+\Indexc{skip}( \textit{scanset} )\index{manipulator!skip@©skip©}, ©skip©( $N$ )
+consumes either the \textit{scanset} or the next $N$ characters, including newlines.
+If the match successes, the input characters are ignored, and input continues with the next character.
 If the match fails, the input characters are left unread.
 \begin{cfa}[belowskip=0pt]
-char sk[§\,§] = "abc";
-sin | "abc " | skip( sk ) | skip( 5 ); // match input sequence
+char scanset[§\,§] = "abc";
+sin | "abc§\textvisiblespace§" | skip( scanset ) | skip( 5 ); §\C{// match and skip input sequence}§
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
-®abc   ®
-®abc  ®
-®xx®
-\end{cfa}
-
-\item
-\Indexc{wdi}( maximum, variable )\index{manipulator!wdi@©wdi©}
-For all types except ©char *©, whitespace is skipped until an appropriate value is found for the specified variable type.
-maximum is the maximum number of characters read for the current operation.
+®abc   abc  xxx®
+\end{cfa}
+Again, the blank in the format string ©"abc©\textvisiblespace©"© matches any number of whitespace characters.
+
+\item
+\Indexc{wdi}( \textit{maximum}, ©T & v© )\index{manipulator!wdi@©wdi©}
+For all types except ©char *©, whitespace is skipped and the longest sequence of non-whitespace characters matching an appropriate typed (©T©) value is read, converted into its corresponding internal form, and written into the ©T© variable.
+\textit{maximum} is the maximum number of characters read for the current value rather than the longest sequence.
 \begin{cfa}[belowskip=0pt]
 char ch;   char ca[3];   int i;   double d;   
@@ -4985,4 +5016,5 @@
 \end{cfa}
 Here, ©ca[0]© is type ©char©, so the width reads 3 characters \Textbf{without} a null terminator.
+If an input value is not found for a variable, the exception ©missing_data© is raised, and the input variable is unchanged.
 
 Note, input ©wdi© cannot be overloaded with output ©wd© because both have the same parameters but return different types.
@@ -4990,44 +5022,78 @@
 
 \item
-\Indexc{wdi}( maximum size, ©char s[]© )\index{manipulator!wdi@©wdi©}
-For type ©char *©, maximum is the maximum number of characters read for the current operation.
-Any number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence
+\Indexc{wdi}( $maximum\ size$, ©char s[]© )\index{manipulator!wdi@©wdi©}
+For type ©char *©, whitespace is skippped and the longest sequence of non-whitespace characters is read, without conversion, and written into the string variable (null terminated).
+$maximum\ size$ is the maximum number of characters in the string variable.
+If the non-whitespace sequence of input characters is greater than $maximum\ size - 1$ (null termination), the exception ©cstring_length© is raised.
 \begin{cfa}[belowskip=0pt]
-char cstr[10];
-sin | wdi( sizeof(cstr), cstr );
+char cs[10];
+sin | wdi( sizeof(cs), cs );
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
-®abcd1233.456E+2®
-\end{cfa}
-
-\item
-\Indexc{wdi}( maximum size, maximum read, ©char s[]© )\index{manipulator!wdi@©wdi©}
-For type ©char *©, maximum is the maximum number of characters read for the current operation.
+®012345678®
+\end{cfa}
+Nine non-whitespace character are read and the null character is added to make ten.
+
+\item
+\Indexc{wdi}( $maximum\ size$, $maximum\ read$, ©char s[]© )\index{manipulator!wdi@©wdi©}
+This manipulator is the same as the previous one, except $maximum$ $read$ is the maximum number of characters read for the current value rather than the longest sequence, where $maximum\ read$ $\le$ $maximum\ size$.
 \begin{cfa}[belowskip=0pt]
-char ch;   char ca[3];   int i;   double d;   
-sin | wdi( sizeof(ch), ch ) | wdi( sizeof(ca), ca[0] ) | wdi( 3, i ) | wdi( 8, d );  // c == 'a', ca == "bcd", i == 123, d == 345.6
+char cs[10];
+sin | wdi( sizeof(cs), 9, cs );
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
-®abcd1233.456E+2®
-\end{cfa}
-
-\item
-\Indexc{ignore}( reference-value )\index{manipulator!ignore@©ignore©}
-For all types, the data is read from the stream depending on the argument type but ignored, \ie it is not stored in the argument.
+®012345678®9
+\end{cfa}
+The exception ©cstring_length© is not raised, because the read stops reading after nine characters.
+
+\item
+\Indexc{getline}( $wdi\ manipulator$, ©const char delimiter = '\n'© )\index{manipulator!getline@©getline©}
+consumes the scanset ©"[^D]D"©, where ©D© is the ©delimiter© character, which reads all characters from the current input position to the delimiter character into the string (null terminated), and consumes and ignores the delimiter.
+If the delimiter character is omitted, it defaults to ©'\n'© (newline).
 \begin{cfa}[belowskip=0pt]
-double d;
-sin | ignore( d );  // d is unchanged
+char cs[10];
+sin | getline( wdi( sizeof(cs), cs ) );
+sin | getline( wdi( sizeof(cs), cs ), 'X' ); §\C{// X is the line delimiter}§
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
-®  -75.35e-4® 25
-\end{cfa}
-
-\item
-\Indexc{incl}( scanset, wdi-input-string )\index{manipulator!incl@©incl©}
-For C-string types only, the scanset matches any number of characters \emph{in} the set.
-Matching characters are read into the C input-string and null terminated.
+®abc ?? #@%®
+®abc ?? #@%X® w
+\end{cfa}
+The same value is read for both input strings.
+
+\item
+\Indexc{quoted}( ©char & ch©, ©const char Ldelimiter = '\''©, ©const char Rdelimiter = '\0'© )\index{manipulator!quoted@©quoted©}
+consumes the string ©"LCR"©, where ©L© is the left ©delimiter© character, ©C© is the value in ©ch©, and ©R© is the right delimiter character, which skips whitespace, consumes and ignores the left delimiter, reads a single character into ©ch©, and consumes and ignores the right delimiter (3 characters).
+If the delimit character is omitted, it defaults to ©'\''© (single quote).
 \begin{cfa}[belowskip=0pt]
-char s[10];
-sin | incl( "abc", s );
+char ch;
+sin | quoted( ch );   sin | quoted( ch, '"' );   sin | quoted( ch, '[', ']' );
+\end{cfa}
+\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
+®   'a'  "a"[a]®
+\end{cfa}
+
+\item
+\begin{sloppypar}
+\Indexc{quoted}( $wdi\ manipulator$, ©const char Ldelimiter = '\''©, ©const char Rdelimiter = '\0'© )\index{manipulator!quoted@©quoted©}
+consumes the scanset ©"L[^R]R"©, where ©L© is the left ©delimiter© character and ©R© is the right delimiter character, which skips whitespace, consumes and ignores the left delimiter, reads characters until the right-delimiter into the string variable (null terminated), and consumes and ignores the right delimiter.
+If the delimit character is omitted, it defaults to ©'\''© (single quote).
+\end{sloppypar}
+\begin{cfa}[belowskip=0pt]
+char cs[10];
+sin | quoted( wdi( sizeof(cs), cs ) ); §\C[3in]{// " is the start/end delimiter}§
+sin | quoted( wdi( sizeof(cs), cs ), '\'' ); §\C{// ' is the start/end delimiter}§
+sin | quoted( wdi( sizeof(cs), cs ), '[', ']' ); §\C{// [ is the start and ] is the end delimiter}\CRT§
+\end{cfa}
+\begin{cfa}[showspaces=true]
+®   "abc"  'abc'[abc]®
+\end{cfa}
+
+\item
+\Indexc{incl}( scanset, $wdi\ manipulator$ )\index{manipulator!incl@©incl©}
+consumes the scanset, which reads all the scanned characters into the string variable (null terminated).
+\begin{cfa}[belowskip=0pt]
+char cs[10];
+sin | incl( "abc", cs );
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -5036,10 +5102,9 @@
 
 \item
-\Indexc{excl}( scanset, wdi-input-string )\index{manipulator!excl@©excl©}
-For C-string types, the scanset matches any number of characters \emph{not in} the set.
-Non-matching characters are read into the C input-string and null terminated.
+\Indexc{excl}( scanset, $wdi\ manipulator$ )\index{manipulator!excl@©excl©}
+consumes the \emph{not} scanset, which reads all the scanned characters into the string variable (null terminated).
 \begin{cfa}[belowskip=0pt]
-char s[10];
-sin | excl( "abc", s );
+char cs[10];
+sin | excl( "abc", cs );
 \end{cfa}
 \begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
@@ -5047,12 +5112,17 @@
 \end{cfa}
 
-\Indexc{quoted}( char delimit, wdi-input-string )\index{manipulator!quoted@©quoted©}
-Is an ©excl© with scanset ©"delimit"©, which consumes all characters up to the delimit character.
-If the delimit character is omitted, it defaults to ©'\n'© (newline).
-
-\item
-\Indexc{getline}( char delimit, wdi-input-string )\index{manipulator!getline@©getline©}
-Is an ©excl© with scanset ©"delimit"©, which consumes all characters up to the delimit character.
-If the delimit character is omitted, it defaults to ©'\n'© (newline).
+\item
+\Indexc{ignore}( ©T & v© or ©const char cs[]© or $string\ manipulator$ )\index{manipulator!ignore@©ignore©}
+consumes the appropriate characters for the type and ignores them, so the input variable is unchanged.
+\begin{cfa}
+double d;
+char cs[10];
+sin | ignore( d );						§\C{// d is unchanged}§
+sin | ignore( cs );						§\C{// cs is unchanged, no wdi required}§
+sin | ignore( quoted( wdi( sizeof(cs), cs ) ) ); §\C{// cs is unchanged}§
+\end{cfa}
+\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
+®  -75.35e-4 25 "abc"®
+\end{cfa}
 \end{enumerate}
 
Index: libcfa/src/Exception.hfa
===================================================================
--- libcfa/src/Exception.hfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ libcfa/src/Exception.hfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -2,4 +2,6 @@
 
 // TEMPORARY
-#define ExceptionDecl( name, fields... ) exception name{ fields }; __attribute__(( cfa_linkonce )) vtable( name ) name ## _vt
-#define ExceptionInst( name, values... ) (name){ &name ## _vt, values }
+#define ExceptionDecl( name, fields... ) exception name{ fields }; \
+	__attribute__(( cfa_linkonce )) vtable( name ) name ## _vt
+#define ExceptionArgs( name, args... ) &name ## _vt, args
+#define ExceptionInst( name, args... ) (name){ ExceptionArgs( name, args ) }
Index: libcfa/src/bits/signal.hfa
===================================================================
--- libcfa/src/bits/signal.hfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ libcfa/src/bits/signal.hfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -34,5 +34,5 @@
 	act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
 	sigemptyset( &act.sa_mask );
-	sigaddset( &act.sa_mask, SIGALRM );		// disabled during signal handler
+	sigaddset( &act.sa_mask, SIGALRM );					// disabled during signal handler
 	sigaddset( &act.sa_mask, SIGUSR1 );
 	sigaddset( &act.sa_mask, SIGSEGV );
@@ -40,5 +40,5 @@
 	sigaddset( &act.sa_mask, SIGILL );
 	sigaddset( &act.sa_mask, SIGFPE );
-	sigaddset( &act.sa_mask, SIGHUP );		// revert to default on second delivery
+	sigaddset( &act.sa_mask, SIGHUP );					// revert to default on second delivery
 	sigaddset( &act.sa_mask, SIGTERM );
 	sigaddset( &act.sa_mask, SIGINT );
Index: libcfa/src/collections/string.cfa
===================================================================
--- libcfa/src/collections/string.cfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ libcfa/src/collections/string.cfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,6 @@
 // Created On       : Fri Sep 03 11:00:00 2021
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Jan 14 12:03:47 2024
-// Update Count     : 240
+// Last Modified On : Wed Feb  7 21:17:06 2024
+// Update Count     : 259
 //
 
@@ -210,16 +210,14 @@
 }
 
-void ?|?( ifstream & in, string & s ) {
-    in | (*s.inner);
-}
+ifstream & ?|?( ifstream & is, _Istream_Squoted f ) {
+	_Istream_Rquoted f2 = { { f.sstr.s.inner, (_Istream_str_base)f.sstr } };
+    return is | f2;
+} // ?|?
 
 ifstream & ?|?( ifstream & is, _Istream_Sstr f ) {
+// 	_Istream_Rstr f2 = {f.sstr.s.inner, (_Istream_str_base)f.sstr};
  	_Istream_Rstr f2 = {f.s.inner, (_Istream_str_base)f};
     return is | f2;
 } // ?|?
-
-void ?|?( ifstream & in, _Istream_Sstr f ) {
-    (ifstream &)(in | f);
-}
 
 ////////////////////////////////////////////////////////
Index: libcfa/src/collections/string.hfa
===================================================================
--- libcfa/src/collections/string.hfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ libcfa/src/collections/string.hfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,6 @@
 // Created On       : Fri Sep 03 11:00:00 2021
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Jan 14 12:03:46 2024
-// Update Count     : 81
+// Last Modified On : Tue Feb  6 20:59:18 2024
+// Update Count     : 118
 //
 
@@ -80,5 +80,4 @@
 void ?|?(ofstream & out, const string & s);
 ifstream & ?|?(ifstream & in, string & s);
-void ?|?( ifstream & in, string & s );
 
 static inline {
@@ -96,27 +95,52 @@
 void ?|?( ofstream & os, _Ostream_Manip(string) );
 
+struct _Istream_Swidth {
+	string & s;
+	inline _Istream_str_base;
+}; // _Istream_Swidth
+
+struct _Istream_Squoted {
+	_Istream_Swidth sstr;
+}; // _Istream_Squoted
+
 struct _Istream_Sstr {
 	string & s;
 	inline _Istream_str_base;
+//	_Istream_Swidth sstr;
 }; // _Istream_Sstr
 
 static inline {
 	// read width does not include null terminator
-	_Istream_Sstr wdi( unsigned int rwd, string & s ) { return (_Istream_Sstr)@{ s, {{0p}, rwd, {.flags.rwd : true}} }; }
+	_Istream_Swidth wdi( unsigned int rwd, string & s ) { return (_Istream_Swidth)@{ .s : s, { {.scanset : 0p}, .wd : rwd, {.flags.rwd : true} } }; }
 	_Istream_Sstr getline( string & s, const char delimiter = '\n' ) {
-		return (_Istream_Sstr)@{ s, {{.delimiters : { delimiter, '\0' } }, -1, {.flags.delimiter : true, .flags.inex : true}} };
-	}
-	_Istream_Sstr & getline( _Istream_Sstr & fmt, const char delimiter = '\n' ) {
-		fmt.delimiters[0] = delimiter; fmt.delimiters[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt;
-	}
-	_Istream_Sstr incl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ s, {{scanset}, -1, {.flags.inex : false}} }; }
-	_Istream_Sstr & incl( const char scanset[], _Istream_Sstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
-	_Istream_Sstr excl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ s, {{scanset}, -1, {.flags.inex : true}} }; }
-	_Istream_Sstr & excl( const char scanset[], _Istream_Sstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
-	_Istream_Sstr ignore( string & s ) { return (_Istream_Sstr)@{ s, {{0p}, -1, {.flags.ignore : true}} }; }
-	_Istream_Sstr & ignore( _Istream_Sstr & fmt ) { fmt.flags.ignore = true; return fmt; }
+//		return (_Istream_Sstr)@{ { .s : s, { {.delimiters : { delimiter, '\0' } }, .wd : -1, {.flags.delimiter : true} } } };
+		return (_Istream_Sstr)@{ .s : s, { {.delimiters : { delimiter, '\0' } }, .wd : -1, {.flags.delimiter : true} } };
+	}
+	_Istream_Sstr & getline( _Istream_Swidth & f, const char delimiter = '\n' ) {
+		f.delimiters[0] = delimiter; f.delimiters[1] = '\0'; f.flags.delimiter = true; return (_Istream_Sstr &)f;
+	}
+	_Istream_Squoted quoted( string & s, const char Ldelimiter = '\"', const char Rdelimiter = '\0' ) {
+		return (_Istream_Squoted)@{ { .s : s, { {.delimiters : { Ldelimiter, Rdelimiter, '\0' }}, .wd : -1, {.flags.rwd : true} } } };
+	}
+	_Istream_Squoted & quoted( _Istream_Swidth & f, const char Ldelimiter = '"', const char Rdelimiter = '\0' ) {
+		f.delimiters[0] = Ldelimiter;  f.delimiters[1] = Rdelimiter;  f.delimiters[2] = '\0';
+		return (_Istream_Squoted &)f;
+	}
+//	_Istream_Sstr incl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ { .s : s, { {.scanset : scanset}, .wd : -1, {.flags.inex : false} } } }; }
+	_Istream_Sstr incl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ .s : s, { {.scanset : scanset}, .wd : -1, {.flags.inex : false} } }; }
+	_Istream_Sstr & incl( const char scanset[], _Istream_Swidth & f ) { f.scanset = scanset; f.flags.inex = false; return (_Istream_Sstr &)f; }
+//	_Istream_Sstr excl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ { .s : s, { {.scanset : scanset}, .wd : -1, {.flags.inex : true} } } }; }
+	_Istream_Sstr excl( const char scanset[], string & s ) { return (_Istream_Sstr)@{ .s : s, { {.scanset : scanset}, .wd : -1, {.flags.inex : true} } }; }
+	_Istream_Sstr & excl( const char scanset[], _Istream_Swidth & f ) { f.scanset = scanset; f.flags.inex = true; return (_Istream_Sstr &)f; }
+//	_Istream_Sstr ignore( string & s ) { return (_Istream_Sstr)@{ { .s : s, { {.scanset : 0p}, .wd : -1, {.flags.ignore : true} } } }; }
+	_Istream_Sstr ignore( string & s ) { return (_Istream_Sstr)@{ .s : s, { {.scanset : 0p}, .wd : -1, {.flags.ignore : true} } }; }
+	_Istream_Sstr & ignore( _Istream_Swidth & f ) { f.flags.ignore = true; return (_Istream_Sstr &)f; }
+	_Istream_Squoted & ignore( _Istream_Squoted & f ) { f.sstr.flags.ignore = true; return (_Istream_Squoted &)f; }
+//	_Istream_Sstr & ignore( _Istream_Sstr & f ) { f.sstr.flags.ignore = true; return (_Istream_Sstr &)f; }
+	_Istream_Sstr & ignore( _Istream_Sstr & f ) { f.flags.ignore = true; return (_Istream_Sstr &)f; }
 } // distribution
+ifstream & ?|?( ifstream & is, _Istream_Squoted f );
 ifstream & ?|?( ifstream & is, _Istream_Sstr f );
-void ?|?( ifstream & is, _Istream_Sstr t );
+static inline ifstream & ?|?( ifstream & is, _Istream_Swidth f ) { return is | *(_Istream_Sstr *)&f; }
 
 // Concatenation
Index: libcfa/src/collections/string_res.cfa
===================================================================
--- libcfa/src/collections/string_res.cfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ libcfa/src/collections/string_res.cfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,6 @@
 // Created On       : Fri Sep 03 11:00:00 2021
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Jan 22 23:12:42 2024
-// Update Count     : 43
+// Last Modified On : Sat Feb 10 17:47:22 2024
+// Update Count     : 83
 //
 
@@ -25,5 +25,5 @@
 
 #include <assert.h>
-#include <complex.h>                           // creal, cimag
+#include <complex.h>						   // creal, cimag
 
 //######################### VbyteHeap "header" #########################
@@ -34,27 +34,27 @@
 
 struct VbyteHeap {
-    int NoOfCompactions;						// number of compactions of the byte area
-    int NoOfExtensions;							// number of extensions in the size of the byte area
-    int NoOfReductions;							// number of reductions in the size of the byte area
-    
-    int InitSize;								// initial number of bytes in the byte-string area
-    int CurrSize;								// current number of bytes in the byte-string area
-    char *StartVbyte;							// pointer to the `st byte of the start of the byte-string area
-    char *EndVbyte;								// pointer to the next byte after the end of the currently used portion of byte-string area
-    void *ExtVbyte;								// pointer to the next byte after the end of the byte-string area
-
-    HandleNode Header;							// header node for handle list
+	int NoOfCompactions;								// number of compactions of the byte area
+	int NoOfExtensions;									// number of extensions in the size of the byte area
+	int NoOfReductions;									// number of reductions in the size of the byte area
+	
+	int InitSize;										// initial number of bytes in the byte-string area
+	int CurrSize;										// current number of bytes in the byte-string area
+	char *StartVbyte;									// pointer to the `st byte of the start of the byte-string area
+	char *EndVbyte;										// pointer to the next byte after the end of the currently used portion of byte-string area
+	void *ExtVbyte;										// pointer to the next byte after the end of the byte-string area
+
+	HandleNode Header;									// header node for handle list
 }; // VbyteHeap
 
-    
-static void compaction( VbyteHeap & );			// compaction of the byte area
-static void garbage( VbyteHeap &, int );		// garbage collect the byte area
-static void extend( VbyteHeap &, int );			// extend the size of the byte area
-static void reduce( VbyteHeap &, int );			// reduce the size of the byte area
+
+static void compaction( VbyteHeap & );					// compaction of the byte area
+static void garbage( VbyteHeap &, int );				// garbage collect the byte area
+static void extend( VbyteHeap &, int );					// extend the size of the byte area
+static void reduce( VbyteHeap &, int );					// reduce the size of the byte area
 
 static void ?{}( VbyteHeap &, size_t = 1000 );
 static void ^?{}( VbyteHeap & );
 
-static int ByteCmp( char *, int, int, char *, int, int );	// compare 2 blocks of bytes
+static int ByteCmp( char *, int, int, char *, int, int ); // compare 2 blocks of bytes
 static char *VbyteAlloc( VbyteHeap &, int );			// allocate a block bytes in the heap
 static char *VbyteTryAdjustLast( VbyteHeap &, int );
@@ -62,5 +62,5 @@
 static void AddThisAfter( HandleNode &, HandleNode & );
 static void DeleteNode( HandleNode & );
-static void MoveThisAfter( HandleNode &, const HandleNode & );		// move current handle after parameter handle
+static void MoveThisAfter( HandleNode &, const HandleNode & ); // move current handle after parameter handle
 
 
@@ -69,15 +69,15 @@
 static void ?{}( VbyteHeap & s, size_t Size ) with(s) {
 #ifdef VbyteDebug
-    serr | "enter:VbyteHeap::VbyteHeap, s:" | &s | " Size:" | Size;
-#endif // VbyteDebug
-    NoOfCompactions = NoOfExtensions = NoOfReductions = 0;
-    InitSize = CurrSize = Size;
-    StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
-    ExtVbyte = (void *)( StartVbyte + CurrSize );
-    Header.flink = Header.blink = &Header;
-    Header.ulink = &s;
-#ifdef VbyteDebug
-    HeaderPtr = &Header;
-    serr | "exit:VbyteHeap::VbyteHeap, s:" | &s;
+	serr | "enter:VbyteHeap::VbyteHeap, s:" | &s | " Size:" | Size;
+#endif // VbyteDebug
+	NoOfCompactions = NoOfExtensions = NoOfReductions = 0;
+	InitSize = CurrSize = Size;
+	StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
+	ExtVbyte = (void *)( StartVbyte + CurrSize );
+	Header.flink = Header.blink = &Header;
+	Header.ulink = &s;
+#ifdef VbyteDebug
+	HeaderPtr = &Header;
+	serr | "exit:VbyteHeap::VbyteHeap, s:" | &s;
 #endif // VbyteDebug
 } // VbyteHeap
@@ -87,5 +87,5 @@
 
 static void ^?{}( VbyteHeap & s ) with(s) {
-    free( StartVbyte );
+	free( StartVbyte );
 } // ~VbyteHeap
 
@@ -99,10 +99,10 @@
 static void ?{}( HandleNode & s ) with(s) {
 #ifdef VbyteDebug
-    serr | "enter:HandleNode::HandleNode, s:" | &s;
-#endif // VbyteDebug
-    s = 0;
-    lnth = 0;
-#ifdef VbyteDebug
-    serr | "exit:HandleNode::HandleNode, s:" | &s;
+	serr | "enter:HandleNode::HandleNode, s:" | &s;
+#endif // VbyteDebug
+	s = 0;
+	lnth = 0;
+#ifdef VbyteDebug
+	serr | "exit:HandleNode::HandleNode, s:" | &s;
 #endif // VbyteDebug
 } // HandleNode
@@ -114,12 +114,12 @@
 static void ?{}( HandleNode & s, VbyteHeap & vh ) with(s) {
 #ifdef VbyteDebug
-    serr | "enter:HandleNode::HandleNode, s:" | &s;
-#endif // VbyteDebug
-    s = 0;
-    lnth = 0;
-    ulink = &vh;
-    AddThisAfter( s, *vh.Header.blink );
-#ifdef VbyteDebug
-    serr | "exit:HandleNode::HandleNode, s:" | &s;
+	serr | "enter:HandleNode::HandleNode, s:" | &s;
+#endif // VbyteDebug
+	s = 0;
+	lnth = 0;
+	ulink = &vh;
+	AddThisAfter( s, *vh.Header.blink );
+#ifdef VbyteDebug
+	serr | "exit:HandleNode::HandleNode, s:" | &s;
 #endif // VbyteDebug
 } // HandleNode
@@ -131,16 +131,16 @@
 static void ^?{}( HandleNode & s ) with(s) {
 #ifdef VbyteDebug
-    serr | "enter:HandleNode::~HandleNode, s:" | & s;
-    {
-	serr | nlOff;
-	serr | " lnth:" | lnth | " s:" | (void *)s | ",\"";
-	for ( i; lnth ) {
-	    serr | s[i];
-	} // for
-	serr | "\" flink:" | flink | " blink:" | blink | nl;
-	serr | nlOn;
-    }
-#endif // VbyteDebug
-    DeleteNode( s );
+	serr | "enter:HandleNode::~HandleNode, s:" | & s;
+	{
+		serr | nlOff;
+		serr | " lnth:" | lnth | " s:" | (void *)s | ",\"";
+		for ( i; lnth ) {
+			serr | s[i];
+		} // for
+		serr | "\" flink:" | flink | " blink:" | blink | nl;
+		serr | nlOn;
+	}
+#endif // VbyteDebug
+	DeleteNode( s );
 } // ~HandleNode
 
@@ -148,26 +148,26 @@
 //######################### String Sharing Context #########################
 
-static string_sharectx * ambient_string_sharectx;               // fickle top of stack
+static string_sharectx * ambient_string_sharectx;		// fickle top of stack
 static string_sharectx default_string_sharectx = {NEW_SHARING}; // stable bottom of stack
 
 void ?{}( string_sharectx & s, StringSharectx_Mode mode ) with( s ) {
-    (older){ ambient_string_sharectx };
-    if ( mode == NEW_SHARING ) {
-        (activeHeap){ new( (size_t) 1000 ) };
-    } else {
-        verify( mode == NO_SHARING );
-        (activeHeap){ 0p };
-    }
-    ambient_string_sharectx = & s;
+	(older){ ambient_string_sharectx };
+	if ( mode == NEW_SHARING ) {
+		(activeHeap){ new( (size_t) 1000 ) };
+	} else {
+		verify( mode == NO_SHARING );
+		(activeHeap){ 0p };
+	}
+	ambient_string_sharectx = & s;
 }
 
 void ^?{}( string_sharectx & s ) with( s ) {
-    if ( activeHeap ) delete( activeHeap );
-
-    // unlink s from older-list starting from ambient_string_sharectx
-    // usually, s==ambient_string_sharectx and the loop runs zero times
-    string_sharectx *& c = ambient_string_sharectx;
-    while ( c != &s ) &c = &c->older;              // find s
-    c = s.older;                                   // unlink
+	if ( activeHeap ) delete( activeHeap );
+
+	// unlink s from older-list starting from ambient_string_sharectx
+	// usually, s==ambient_string_sharectx and the loop runs zero times
+	string_sharectx *& c = ambient_string_sharectx;
+	while ( c != &s ) &c = &c->older;					// find s
+	c = s.older;										// unlink
 }
 
@@ -176,23 +176,23 @@
 
 VbyteHeap * DEBUG_string_heap() {
-    assert( ambient_string_sharectx->activeHeap && "No sharing context is active" );
-    return ambient_string_sharectx->activeHeap;
+	assert( ambient_string_sharectx->activeHeap && "No sharing context is active" );
+	return ambient_string_sharectx->activeHeap;
 }
 
 size_t DEBUG_string_bytes_avail_until_gc( VbyteHeap * heap ) {
-    return ((char *)heap->ExtVbyte) - heap->EndVbyte;
+	return ((char *)heap->ExtVbyte) - heap->EndVbyte;
 }
 
 size_t DEBUG_string_bytes_in_heap( VbyteHeap * heap ) {
-    return heap->CurrSize;
+	return heap->CurrSize;
 }
 
 const char * DEBUG_string_heap_start( VbyteHeap * heap ) {
-    return heap->StartVbyte;
+	return heap->StartVbyte;
 }
 
 // Returns the size of the string in bytes
 size_t size(const string_res & s) with(s) {
-    return Handle.lnth;
+	return Handle.lnth;
 }
 
@@ -201,5 +201,5 @@
 	// CFA string is NOT null terminated, so print exactly lnth characters in a minimum width of 0.
 	out | wd( 0, s.Handle.lnth, s.Handle.s ) | nonl;
-    return out;
+	return out;
 }
 
@@ -210,47 +210,68 @@
 // Input operator
 ifstream & ?|?(ifstream & in, string_res & s) {
-    // Reading into a temp before assigning to s is near zero overhead in typical cases because of sharing.
-    // If s is a substring of something larger, simple assignment takes care of that case correctly.
-    // But directly reading a variable amount of text into the middle of a larger context is not practical.
-    string_res temp;
-
-    // Read in chunks.  Often, one chunk is enough.  Keep the string that accumulates chunks last in the heap,
-    // so available room is rest of heap.  When a chunk fills the heap, force growth then take the next chunk.
-    for (bool cont = true; cont; ) {
-        cont = false;
-
-        // Append dummy content to temp, forcing expansion when applicable (occurs always on subsequent loops)
-        // length 2 ensures room for at least one real char, plus scanf/pipe-cstr's null terminator
-        temp += "--";
-        assert( temp.Handle.ulink->EndVbyte == temp.Handle.s + temp.Handle.lnth );    // last in heap
-
-        // reset, to overwrite the appended "--"
-        temp.Handle.lnth -= 2;
-        temp.Handle.ulink->EndVbyte -= 2;
-
-        // rest of heap is available to read into
-        int lenReadable = (char *)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte;
-        assert (lenReadable >= 2);
-
-        // get bytes
-        try {
+	// Reading into a temp before assigning to s is near zero overhead in typical cases because of sharing.
+	// If s is a substring of something larger, simple assignment takes care of that case correctly.
+	// But directly reading a variable amount of text into the middle of a larger context is not practical.
+	string_res temp;
+
+	// Read in chunks.  Often, one chunk is enough.  Keep the string that accumulates chunks last in the heap,
+	// so available room is rest of heap.  When a chunk fills the heap, force growth then take the next chunk.
+	for (bool cont = true; cont; ) {
+		cont = false;
+
+		// Append dummy content to temp, forcing expansion when applicable (occurs always on subsequent loops)
+		// length 2 ensures room for at least one real char, plus scanf/pipe-cstr's null terminator
+		temp += "--";
+		assert( temp.Handle.ulink->EndVbyte == temp.Handle.s + temp.Handle.lnth );	// last in heap
+
+		// reset, to overwrite the appended "--"
+		temp.Handle.lnth -= 2;
+		temp.Handle.ulink->EndVbyte -= 2;
+
+		// rest of heap is available to read into
+		int lenReadable = (char *)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte;
+		assert (lenReadable >= 2);
+
+		// get bytes
+		try {
 			*(temp.Handle.ulink->EndVbyte) = '\0';   // pre-assign empty cstring
-            in | wdi( lenReadable, temp.Handle.ulink->EndVbyte );
-        } catch (cstring_length *) {
-            cont = true;
-        }
-        int lenWasRead = strlen(temp.Handle.ulink->EndVbyte);
-
-        // update metadata
-        temp.Handle.lnth += lenWasRead;
-        temp.Handle.ulink->EndVbyte += lenWasRead;
-    }
+			in | wdi( lenReadable, temp.Handle.ulink->EndVbyte );
+		} catch (cstring_length *) {
+			cont = true;
+		}
+		int lenWasRead = strlen(temp.Handle.ulink->EndVbyte);
+
+		// update metadata
+		temp.Handle.lnth += lenWasRead;
+		temp.Handle.ulink->EndVbyte += lenWasRead;
+	}
 
 	if ( temp.Handle.lnth > 0 ) s = temp;
-    return in;
-}
-
-void ?|?( ifstream & in, string_res & s ) {
-    (ifstream &)(in | s);
+	return in;
+}
+
+ifstream & ?|?( ifstream & is, _Istream_Rquoted f ) with( f.rstr ) {
+	if ( eof( is ) ) throwResume ExceptionInst( missing_data );
+	int args;
+  fini: {
+		char rfmt[5] = { ' ', delimiters[0], '%', 'n', '\0' };
+		int len = -1;									// may not be set in fmt
+		args = fmt( is, rfmt, &len );					// remove leading whitespace and quote
+	  if ( eof( is ) || len == -1 ) break fini;
+
+		// Change the remainder of the read into a getline by reseting the closing delimiter.
+		if ( delimiters[1] != '\0' ) {
+			delimiters[0] = delimiters[1];
+			delimiters[1] = '\0';
+		} // if
+		flags.delimiter = true;
+		return is | *(_Istream_Rstr *)&f;
+	} // fini
+	// read failed => no pattern match => set string to null
+	if ( ! flags.ignore && s != 0p && args == 0 ) s[0] = '\0';
+	if ( args == 1 && eof( is ) ) {						// data but scan ended at EOF
+		clear( is );									// => reset EOF => detect again on next read
+	} // if
+	return is;
 }
 
@@ -295,91 +316,86 @@
 } // ?|?
 
-void ?|?( ifstream & in, _Istream_Rstr f ) {
-    (ifstream &)(in | f);
-}
-
-
 // Empty constructor
 void ?{}(string_res & s) with(s) {
-    if( ambient_string_sharectx->activeHeap ) {
-        (Handle){ * ambient_string_sharectx->activeHeap };
-        (shareEditSet_owns_ulink){ false };
-        verify( Handle.s == 0p && Handle.lnth == 0 );
-    } else {
-        (Handle){ * new( (size_t) 10 ) };  // TODO: can I lazily avoid allocating for empty string
-        (shareEditSet_owns_ulink){ true };
-        Handle.s = Handle.ulink->StartVbyte;
-        verify( Handle.lnth == 0 );
-    }
-    s.shareEditSet_prev = &s;
-    s.shareEditSet_next = &s;
-}
+	if( ambient_string_sharectx->activeHeap ) {
+		(Handle){ * ambient_string_sharectx->activeHeap };
+		(shareEditSet_owns_ulink){ false };
+		verify( Handle.s == 0p && Handle.lnth == 0 );
+	} else {
+		(Handle){ * new( (size_t) 10 ) };  // TODO: can I lazily avoid allocating for empty string
+		(shareEditSet_owns_ulink){ true };
+		Handle.s = Handle.ulink->StartVbyte;
+		verify( Handle.lnth == 0 );
+	}
+	s.shareEditSet_prev = &s;
+	s.shareEditSet_next = &s;
+		}
 
 static void eagerCopyCtorHelper(string_res & s, const char * rhs, size_t rhslnth) with(s) {
-    if( ambient_string_sharectx->activeHeap ) {
-        (Handle){ * ambient_string_sharectx->activeHeap };
-        (shareEditSet_owns_ulink){ false };
-    } else {
-        (Handle){ * new( rhslnth ) };
-        (shareEditSet_owns_ulink){ true };
-    }
-    Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
-    Handle.lnth = rhslnth;
-    memmove( Handle.s, rhs, rhslnth );
-    s.shareEditSet_prev = &s;
-    s.shareEditSet_next = &s;
+	if( ambient_string_sharectx->activeHeap ) {
+		(Handle){ * ambient_string_sharectx->activeHeap };
+		(shareEditSet_owns_ulink){ false };
+	} else {
+		(Handle){ * new( rhslnth ) };
+		(shareEditSet_owns_ulink){ true };
+	}
+	Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
+	Handle.lnth = rhslnth;
+	memmove( Handle.s, rhs, rhslnth );
+	s.shareEditSet_prev = &s;
+	s.shareEditSet_next = &s;
 }
 
 // Constructor from a raw buffer and size
 void ?{}(string_res & s, const char * rhs, size_t rhslnth) with(s) {
-    eagerCopyCtorHelper(s, rhs, rhslnth);
+	eagerCopyCtorHelper(s, rhs, rhslnth);
 }
 
 void ?{}( string_res & s, ssize_t rhs ) {
-    char buf[64];
-    int len;
-    snprintf( buf, sizeof(buf)-1, "%zd%n", rhs, &len );
-    ( s ){ buf, len };
+	char buf[64];
+	int len;
+	snprintf( buf, sizeof(buf)-1, "%zd%n", rhs, &len );
+	( s ){ buf, len };
 }
 void ?{}( string_res & s, size_t rhs ) {
-    char buf[64];
-    int len;
-    snprintf( buf, sizeof(buf)-1, "%zu%n", rhs, &len );
-    ( s ){ buf, len };
+	char buf[64];
+	int len;
+	snprintf( buf, sizeof(buf)-1, "%zu%n", rhs, &len );
+	( s ){ buf, len };
 }
 void ?{}( string_res & s, double rhs ) {
-    char buf[64];
-    int len;
-    snprintf( buf, sizeof(buf)-1, "%g%n", rhs, &len );
-    ( s ){ buf, len };
+	char buf[64];
+	int len;
+	snprintf( buf, sizeof(buf)-1, "%g%n", rhs, &len );
+	( s ){ buf, len };
 }
 void ?{}( string_res & s, long double rhs ) {
-    char buf[64];
-    int len;
-    snprintf( buf, sizeof(buf)-1, "%Lg%n", rhs, &len );
-    ( s ){ buf, len };
+	char buf[64];
+	int len;
+	snprintf( buf, sizeof(buf)-1, "%Lg%n", rhs, &len );
+	( s ){ buf, len };
 }
 void ?{}( string_res & s, double _Complex rhs ) {
-    char buf[64];
-    int len;
-    snprintf( buf, sizeof(buf)-1, "%g+%gi%n", creal( rhs ), cimag( rhs ), &len );
-    ( s ){ buf, len };
+	char buf[64];
+	int len;
+	snprintf( buf, sizeof(buf)-1, "%g+%gi%n", creal( rhs ), cimag( rhs ), &len );
+	( s ){ buf, len };
 }
 void ?{}( string_res & s, long double _Complex rhs ) {
-    char buf[64];
-    int len;
-    snprintf( buf, sizeof(buf)-1, "%Lg+%Lgi%n", creall( rhs ), cimagl( rhs ), &len );
-    ( s ){ buf, len };
+	char buf[64];
+	int len;
+	snprintf( buf, sizeof(buf)-1, "%Lg+%Lgi%n", creall( rhs ), cimagl( rhs ), &len );
+	( s ){ buf, len };
 }
 
 // private ctor (not in header): use specified heap (ignore ambient) and copy chars in
 void ?{}( string_res & s, VbyteHeap & heap, const char * rhs, size_t rhslnth ) with(s) {
-    (Handle){ heap };
-    Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
-    Handle.lnth = rhslnth;
-    (s.shareEditSet_owns_ulink){ false };
-    memmove( Handle.s, rhs, rhslnth );
-    s.shareEditSet_prev = &s;
-    s.shareEditSet_next = &s;
+	(Handle){ heap };
+	Handle.s = VbyteAlloc(*Handle.ulink, rhslnth);
+	Handle.lnth = rhslnth;
+	(s.shareEditSet_owns_ulink){ false };
+	memmove( Handle.s, rhs, rhslnth );
+	s.shareEditSet_prev = &s;
+	s.shareEditSet_next = &s;
 }
 
@@ -387,271 +403,269 @@
 // General copy constructor
 void ?{}(string_res & s, const string_res & s2, StrResInitMode mode, size_t start, size_t len ) {
-
-    size_t end = start + len;
-    verify( start <= end && end <= s2.Handle.lnth );
-
-    if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) {
-        // crossing heaps (including private): copy eagerly
-        eagerCopyCtorHelper(s, s2.Handle.s + start, end - start);
-        verify(s.shareEditSet_prev == &s);
-        verify(s.shareEditSet_next == &s);
-    } else {
-        (s.Handle){};
-        s.Handle.s = s2.Handle.s + start;
-        s.Handle.lnth = end - start;
-        s.Handle.ulink = s2.Handle.ulink;
-
-        AddThisAfter(s.Handle, s2.Handle );			// insert this handle after rhs handle
-        // ^ bug?  skip others at early point in string
-
-        if (mode == COPY_VALUE) {
-            verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap);
-            // requested logical copy in same heap: defer copy until write
-
-            (s.shareEditSet_owns_ulink){ false };
-
-            // make s alone in its shareEditSet
-            s.shareEditSet_prev = &s;
-            s.shareEditSet_next = &s;
-        } else {
-            verify( mode == SHARE_EDITS );
-            // sharing edits with source forces same heap as source (ignore context)
-
-            (s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink };
-
-            // s2 is logically const but not implementation const
-            string_res & s2mod = (string_res &) s2;
-
-            // insert s after s2 on shareEditSet
-            s.shareEditSet_next = s2mod.shareEditSet_next;
-            s.shareEditSet_prev = &s2mod;
-            s.shareEditSet_next->shareEditSet_prev = &s;
-            s.shareEditSet_prev->shareEditSet_next = &s;
-        }
-    }
+	size_t end = start + len;
+	verify( start <= end && end <= s2.Handle.lnth );
+
+	if (s2.Handle.ulink != ambient_string_sharectx->activeHeap && mode == COPY_VALUE) {
+		// crossing heaps (including private): copy eagerly
+		eagerCopyCtorHelper(s, s2.Handle.s + start, end - start);
+		verify(s.shareEditSet_prev == &s);
+		verify(s.shareEditSet_next == &s);
+	} else {
+		(s.Handle){};
+		s.Handle.s = s2.Handle.s + start;
+		s.Handle.lnth = end - start;
+		s.Handle.ulink = s2.Handle.ulink;
+
+		AddThisAfter(s.Handle, s2.Handle );			// insert this handle after rhs handle
+		// ^ bug?  skip others at early point in string
+
+		if (mode == COPY_VALUE) {
+			verify(s2.Handle.ulink == ambient_string_sharectx->activeHeap);
+			// requested logical copy in same heap: defer copy until write
+
+			(s.shareEditSet_owns_ulink){ false };
+
+			// make s alone in its shareEditSet
+			s.shareEditSet_prev = &s;
+			s.shareEditSet_next = &s;
+		} else {
+			verify( mode == SHARE_EDITS );
+			// sharing edits with source forces same heap as source (ignore context)
+
+			(s.shareEditSet_owns_ulink){ s2.shareEditSet_owns_ulink };
+
+			// s2 is logically const but not implementation const
+			string_res & s2mod = (string_res &) s2;
+
+			// insert s after s2 on shareEditSet
+			s.shareEditSet_next = s2mod.shareEditSet_next;
+			s.shareEditSet_prev = &s2mod;
+			s.shareEditSet_next->shareEditSet_prev = &s;
+			s.shareEditSet_prev->shareEditSet_next = &s;
+		}
+	}
 }
 
 static void assignEditSet(string_res & s, string_res * shareEditSetStartPeer, string_res * shareEditSetEndPeer,
-    char * resultSesStart,
-    size_t resultSesLnth,
-    HandleNode * resultPadPosition, size_t bsize ) {
-
-    char * beforeBegin = shareEditSetStartPeer->Handle.s;
-    size_t beforeLen = s.Handle.s - beforeBegin;
-
-    char * afterBegin = s.Handle.s + s.Handle.lnth;
-    size_t afterLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - afterBegin;
-
-    size_t oldLnth = s.Handle.lnth;
-
-    s.Handle.s = resultSesStart + beforeLen;
-    s.Handle.lnth = bsize;
-    if (resultPadPosition)
-        MoveThisAfter( s.Handle, *resultPadPosition );
-
-    // adjust all substring string and handle locations, and check if any substring strings are outside the new base string
-    char *limit = resultSesStart + resultSesLnth;
-    for ( string_res * p = s.shareEditSet_next; p != &s; p = p->shareEditSet_next ) {
-        verify (p->Handle.s >= beforeBegin);
-        if ( p->Handle.s >= afterBegin ) {
-            verify ( p->Handle.s <= afterBegin + afterLen );
-            verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
-            // p starts after the edit
-            // take start and end as end-anchored
-            size_t startOffsetFromEnd = afterBegin + afterLen - p->Handle.s;
-            p->Handle.s = limit - startOffsetFromEnd;
-            // p->Handle.lnth unaffected
-        } else if ( p->Handle.s <= beforeBegin + beforeLen ) {
-            // p starts before, or at the start of, the edit
-            if ( p->Handle.s + p->Handle.lnth <= beforeBegin + beforeLen ) {
-                // p ends before the edit
-                // take end as start-anchored too
-                // p->Handle.lnth unaffected
-            } else if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
-                // p ends during the edit; p does not include the last character replaced
-                // clip end of p to end at start of edit
-                p->Handle.lnth = beforeLen - ( p->Handle.s - beforeBegin );
-            } else {
-                // p ends after the edit
-                verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
-                // take end as end-anchored
-                // stretch-shrink p according to the edit
-                p->Handle.lnth += s.Handle.lnth;
-                p->Handle.lnth -= oldLnth;
-            }
-            // take start as start-anchored
-            size_t startOffsetFromStart = p->Handle.s - beforeBegin;
-            p->Handle.s = resultSesStart + startOffsetFromStart;
-        } else {
-            verify ( p->Handle.s < afterBegin );
-            // p starts during the edit
-            verify( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );
-            if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
-                // p ends during the edit; p does not include the last character replaced
-                // set p to empty string at start of edit
-                p->Handle.s = s.Handle.s;
-                p->Handle.lnth = 0;
-            } else {
-                // p includes the end of the edit
-                // clip start of p to start at end of edit
-                int charsToClip = afterBegin - p->Handle.s;
-                p->Handle.s = s.Handle.s + s.Handle.lnth;
-                p->Handle.lnth -= charsToClip;
-            }
-        }
-        if (resultPadPosition)
-            MoveThisAfter( p->Handle, *resultPadPosition );	// move substring handle to maintain sorted order by string position
-    }
+						  char * resultSesStart,
+						  size_t resultSesLnth,
+						  HandleNode * resultPadPosition, size_t bsize ) {
+
+	char * beforeBegin = shareEditSetStartPeer->Handle.s;
+	size_t beforeLen = s.Handle.s - beforeBegin;
+
+	char * afterBegin = s.Handle.s + s.Handle.lnth;
+	size_t afterLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - afterBegin;
+
+	size_t oldLnth = s.Handle.lnth;
+
+	s.Handle.s = resultSesStart + beforeLen;
+	s.Handle.lnth = bsize;
+	if (resultPadPosition)
+		MoveThisAfter( s.Handle, *resultPadPosition );
+
+	// adjust all substring string and handle locations, and check if any substring strings are outside the new base string
+	char *limit = resultSesStart + resultSesLnth;
+	for ( string_res * p = s.shareEditSet_next; p != &s; p = p->shareEditSet_next ) {
+		verify (p->Handle.s >= beforeBegin);
+		if ( p->Handle.s >= afterBegin ) {
+			verify ( p->Handle.s <= afterBegin + afterLen );
+			verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
+			// p starts after the edit
+			// take start and end as end-anchored
+			size_t startOffsetFromEnd = afterBegin + afterLen - p->Handle.s;
+			p->Handle.s = limit - startOffsetFromEnd;
+			// p->Handle.lnth unaffected
+		} else if ( p->Handle.s <= beforeBegin + beforeLen ) {
+			// p starts before, or at the start of, the edit
+			if ( p->Handle.s + p->Handle.lnth <= beforeBegin + beforeLen ) {
+				// p ends before the edit
+				// take end as start-anchored too
+				// p->Handle.lnth unaffected
+			} else if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
+				// p ends during the edit; p does not include the last character replaced
+				// clip end of p to end at start of edit
+				p->Handle.lnth = beforeLen - ( p->Handle.s - beforeBegin );
+			} else {
+				// p ends after the edit
+				verify ( p->Handle.s + p->Handle.lnth <= afterBegin + afterLen );
+				// take end as end-anchored
+				// stretch-shrink p according to the edit
+				p->Handle.lnth += s.Handle.lnth;
+				p->Handle.lnth -= oldLnth;
+			}
+			// take start as start-anchored
+			size_t startOffsetFromStart = p->Handle.s - beforeBegin;
+			p->Handle.s = resultSesStart + startOffsetFromStart;
+		} else {
+			verify ( p->Handle.s < afterBegin );
+			// p starts during the edit
+			verify( p->Handle.s + p->Handle.lnth >= beforeBegin + beforeLen );
+			if ( p->Handle.s + p->Handle.lnth < afterBegin ) {
+				// p ends during the edit; p does not include the last character replaced
+				// set p to empty string at start of edit
+				p->Handle.s = s.Handle.s;
+				p->Handle.lnth = 0;
+			} else {
+				// p includes the end of the edit
+				// clip start of p to start at end of edit
+				int charsToClip = afterBegin - p->Handle.s;
+				p->Handle.s = s.Handle.s + s.Handle.lnth;
+				p->Handle.lnth -= charsToClip;
+			}
+		}
+		if (resultPadPosition)
+			MoveThisAfter( p->Handle, *resultPadPosition );	// move substring handle to maintain sorted order by string position
+	}
 }
 
 // traverse the share-edit set (SES) to recover the range of a base string to which `s` belongs
 static void locateInShareEditSet( string_res & s, string_res *& shareEditSetStartPeer, string_res *& shareEditSetEndPeer ) {
-    shareEditSetStartPeer = & s;
-    shareEditSetEndPeer = & s;
-    for (string_res * editPeer = s.shareEditSet_next; editPeer != &s; editPeer = editPeer->shareEditSet_next) {
-        if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
-            shareEditSetStartPeer = editPeer;
-        }
-        if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) {
-            shareEditSetEndPeer = editPeer;
-        }
-    }
+	shareEditSetStartPeer = & s;
+	shareEditSetEndPeer = & s;
+	for (string_res * editPeer = s.shareEditSet_next; editPeer != &s; editPeer = editPeer->shareEditSet_next) {
+		if ( editPeer->Handle.s < shareEditSetStartPeer->Handle.s ) {
+			shareEditSetStartPeer = editPeer;
+		}
+		if ( shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth < editPeer->Handle.s + editPeer->Handle.lnth) {
+			shareEditSetEndPeer = editPeer;
+		}
+	}
 }
 
 static string_res & assign_(string_res & s, const char * buffer, size_t bsize, const string_res & valSrc) {
-
-    string_res * shareEditSetStartPeer;
-    string_res * shareEditSetEndPeer;
-    locateInShareEditSet( s, shareEditSetStartPeer, shareEditSetEndPeer );
-
-    verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s );
-    size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s;
-    verify( origEditSetLength >= s.Handle.lnth );
-
-    if ( s.shareEditSet_owns_ulink ) {                 // assigning to private context
-        // ok to overwrite old value within LHS
-        char * prefixStartOrig = shareEditSetStartPeer->Handle.s;
-        int prefixLen = s.Handle.s - prefixStartOrig;
-        char * suffixStartOrig = s.Handle.s + s.Handle.lnth;
-        int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig;
-
-        int delta = bsize - s.Handle.lnth;
-        if ( char * oldBytes = VbyteTryAdjustLast( *s.Handle.ulink, delta ) ) {
-            // growing: copy from old to new
-            char * dest = VbyteAlloc( *s.Handle.ulink, origEditSetLength + delta );
-            char *destCursor = dest;  memcpy(destCursor, prefixStartOrig, prefixLen);
-            destCursor += prefixLen;  memcpy(destCursor, buffer         , bsize    );
-            destCursor += bsize;      memcpy(destCursor, suffixStartOrig, suffixLen);
-            assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
-                dest,
-                origEditSetLength + delta,
-                0p, bsize);
-            free( oldBytes );
-        } else {
-            // room is already allocated in-place: bubble suffix and overwite middle
-            memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen );
-            memcpy( s.Handle.s, buffer, bsize );
-
-            assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
-                shareEditSetStartPeer->Handle.s,
-                origEditSetLength + delta,
-                0p, bsize);
-        }
-
-    } else if (                                           // assigning to shared context
-        s.Handle.lnth == origEditSetLength &&          // overwriting entire run of SES
-        & valSrc &&                                       // sourcing from a managed string
-        valSrc.Handle.ulink == s.Handle.ulink  ) {     // sourcing from same heap
-
-        // SES's result will only use characters from the source string => reuse source
-        assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
-            valSrc.Handle.s,
-            valSrc.Handle.lnth,
-            &((string_res&)valSrc).Handle, bsize);
-        
-    } else {
-        // overwriting a proper substring of some string: mash characters from old and new together (copy on write)
-        // OR we are importing characters: need to copy eagerly (can't refer to source)
-
-        // full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
-        // `s` occurs in the middle of it, to be replaced
-        // build up the new text in `pasting`
-
-        string_res pasting = {
-            * s.Handle.ulink,                               // maintain same heap, regardless of context
-            shareEditSetStartPeer->Handle.s,                   // start of SES
-            s.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before s
-        append( pasting,
-            buffer,                                            // start of replacement for s
-            bsize );                                           // length of replacement for s
-        append( pasting,
-            s.Handle.s + s.Handle.lnth,                  // start of SES after s
-            shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
-            (s.Handle.s + s.Handle.lnth) );              // length of SES, after s
-
-        // The above string building can trigger compaction.
-        // The reference points (that are arguments of the string building) may move during that building.
-        // From s point on, they are stable.
-
-        assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
-            pasting.Handle.s,
-            pasting.Handle.lnth,
-            &pasting.Handle, bsize);
-    }
-
-    return s;
+	string_res * shareEditSetStartPeer;
+	string_res * shareEditSetEndPeer;
+	locateInShareEditSet( s, shareEditSetStartPeer, shareEditSetEndPeer );
+
+	verify( shareEditSetEndPeer->Handle.s >= shareEditSetStartPeer->Handle.s );
+	size_t origEditSetLength = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - shareEditSetStartPeer->Handle.s;
+	verify( origEditSetLength >= s.Handle.lnth );
+
+	if ( s.shareEditSet_owns_ulink ) {				 // assigning to private context
+		// ok to overwrite old value within LHS
+		char * prefixStartOrig = shareEditSetStartPeer->Handle.s;
+		int prefixLen = s.Handle.s - prefixStartOrig;
+		char * suffixStartOrig = s.Handle.s + s.Handle.lnth;
+		int suffixLen = shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth - suffixStartOrig;
+
+		int delta = bsize - s.Handle.lnth;
+		if ( char * oldBytes = VbyteTryAdjustLast( *s.Handle.ulink, delta ) ) {
+			// growing: copy from old to new
+			char * dest = VbyteAlloc( *s.Handle.ulink, origEditSetLength + delta );
+			char *destCursor = dest;  memcpy(destCursor, prefixStartOrig, prefixLen);
+			destCursor += prefixLen;  memcpy(destCursor, buffer		 , bsize	);
+			destCursor += bsize;	  memcpy(destCursor, suffixStartOrig, suffixLen);
+			assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
+						  dest,
+						  origEditSetLength + delta,
+						  0p, bsize);
+			free( oldBytes );
+		} else {
+			// room is already allocated in-place: bubble suffix and overwite middle
+			memmove( suffixStartOrig + delta, suffixStartOrig, suffixLen );
+			memcpy( s.Handle.s, buffer, bsize );
+
+			assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
+						  shareEditSetStartPeer->Handle.s,
+						  origEditSetLength + delta,
+						  0p, bsize);
+		}
+
+	} else if (										   // assigning to shared context
+		s.Handle.lnth == origEditSetLength &&		  // overwriting entire run of SES
+		& valSrc &&									   // sourcing from a managed string
+		valSrc.Handle.ulink == s.Handle.ulink  ) {	 // sourcing from same heap
+
+		// SES's result will only use characters from the source string => reuse source
+		assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
+					  valSrc.Handle.s,
+					  valSrc.Handle.lnth,
+					  &((string_res&)valSrc).Handle, bsize);
+		
+	} else {
+		// overwriting a proper substring of some string: mash characters from old and new together (copy on write)
+		// OR we are importing characters: need to copy eagerly (can't refer to source)
+
+		// full string is from start of shareEditSetStartPeer thru end of shareEditSetEndPeer
+		// `s` occurs in the middle of it, to be replaced
+		// build up the new text in `pasting`
+
+		string_res pasting = {
+			* s.Handle.ulink,							   // maintain same heap, regardless of context
+			shareEditSetStartPeer->Handle.s,				   // start of SES
+			s.Handle.s - shareEditSetStartPeer->Handle.s }; // length of SES, before s
+		append( pasting,
+				buffer,											// start of replacement for s
+				bsize );										   // length of replacement for s
+		append( pasting,
+				s.Handle.s + s.Handle.lnth,				  // start of SES after s
+				shareEditSetEndPeer->Handle.s + shareEditSetEndPeer->Handle.lnth -
+				(s.Handle.s + s.Handle.lnth) );			  // length of SES, after s
+
+		// The above string building can trigger compaction.
+		// The reference points (that are arguments of the string building) may move during that building.
+		// From s point on, they are stable.
+
+		assignEditSet(s, shareEditSetStartPeer, shareEditSetEndPeer, 
+					  pasting.Handle.s,
+					  pasting.Handle.lnth,
+					  &pasting.Handle, bsize);
+	}
+
+	return s;
 }
 
 string_res & assign(string_res & s, const string_res & src, size_t maxlen) {
-    return assign_(s, src.Handle.s, min(src.Handle.lnth, maxlen), *0p);
+	return assign_(s, src.Handle.s, min(src.Handle.lnth, maxlen), *0p);
 }
 
 string_res & assign(string_res & s, const char * buffer, size_t bsize) {
-    return assign_(s, buffer, bsize, *0p);
+	return assign_(s, buffer, bsize, *0p);
 }
 
 string_res & ?=?(string_res & s, char c) {
-    return assign(s, &c, 1);
+	return assign(s, &c, 1);
 }
 
 string_res & ?=?( string_res & s, ssize_t rhs ) {
-    string_res rhs2 = rhs;
-    s = rhs2;
-    return s;
+	string_res rhs2 = rhs;
+	s = rhs2;
+	return s;
 }
 string_res & ?=?( string_res & s, size_t rhs ) {
-    string_res rhs2 = rhs;
-    s = rhs2;
-    return s;
+	string_res rhs2 = rhs;
+	s = rhs2;
+	return s;
 }
 string_res & ?=?( string_res & s, double rhs ) {
-    string_res rhs2 = rhs;
-    s = rhs2;
-    return s;
+	string_res rhs2 = rhs;
+	s = rhs2;
+	return s;
 }
 string_res & ?=?( string_res & s, long double rhs ) {
-    string_res rhs2 = rhs;
-    s = rhs2;
-    return s;
+	string_res rhs2 = rhs;
+	s = rhs2;
+	return s;
 }
 string_res & ?=?( string_res & s, double _Complex rhs ) {
-    string_res rhs2 = rhs;
-    s = rhs2;
-    return s;
+	string_res rhs2 = rhs;
+	s = rhs2;
+	return s;
 }
 string_res & ?=?( string_res & s, long double _Complex rhs ) {
-    string_res rhs2 = rhs;
-    s = rhs2;
-    return s;
+	string_res rhs2 = rhs;
+	s = rhs2;
+	return s;
 }
 
 // Copy assignment operator
 string_res & ?=?(string_res & s, const string_res & rhs) with( s ) {
-    return assign_(s, rhs.Handle.s, rhs.Handle.lnth, rhs);
+	return assign_(s, rhs.Handle.s, rhs.Handle.lnth, rhs);
 }
 
 string_res & ?=?(string_res & s, string_res & rhs) with( s ) {
-    const string_res & rhs2 = rhs;
-    return s = rhs2;
+	const string_res & rhs2 = rhs;
+	return s = rhs2;
 }
 
@@ -659,15 +673,15 @@
 // Destructor
 void ^?{}(string_res & s) with(s) {
-    // much delegated to implied ^VbyteSM
-
-    // sever s from its share-edit peers, if any (four no-ops when already solo)
-    s.shareEditSet_prev->shareEditSet_next = s.shareEditSet_next;
-    s.shareEditSet_next->shareEditSet_prev = s.shareEditSet_prev;
-    // s.shareEditSet_next = &s;
-    // s.shareEditSet_prev = &s;
-
-    if (shareEditSet_owns_ulink && s.shareEditSet_next == &s) { // last one out
-        delete( s.Handle.ulink );
-    }
+	// much delegated to implied ^VbyteSM
+
+	// sever s from its share-edit peers, if any (four no-ops when already solo)
+	s.shareEditSet_prev->shareEditSet_next = s.shareEditSet_next;
+	s.shareEditSet_next->shareEditSet_prev = s.shareEditSet_prev;
+	// s.shareEditSet_next = &s;
+	// s.shareEditSet_prev = &s;
+
+	if (shareEditSet_owns_ulink && s.shareEditSet_next == &s) { // last one out
+		delete( s.Handle.ulink );
+	}
 }
 
@@ -677,14 +691,14 @@
 // offset from the start of the string.
 char ?[?](const string_res & s, size_t index) with(s) {
-    //TODO: Check if index is valid (no exceptions yet)
-    return Handle.s[index];
+	//TODO: Check if index is valid (no exceptions yet)
+	return Handle.s[index];
 }
 
 void assignAt(const string_res & s, size_t index, char val) {
-    // caution: not tested (not reachable by string-api-coverage interface)
-    // equivalent form at string level is `s[index] = val`,
-    // which uses the overload that returns a length-1 string
-    string_res editZone = { s, SHARE_EDITS, index, 1 };
-    assign(editZone, &val, 1);
+	// caution: not tested (not reachable by string-api-coverage interface)
+	// equivalent form at string level is `s[index] = val`,
+	// which uses the overload that returns a length-1 string
+	string_res editZone = { s, SHARE_EDITS, index, 1 };
+	assign(editZone, &val, 1);
 }
 
@@ -694,34 +708,34 @@
 
 void append(string_res & str1, const char * buffer, size_t bsize) {
-    size_t clnth = str1.Handle.lnth + bsize;
-    if ( str1.Handle.s + str1.Handle.lnth == buffer ) { // already juxtapose ?
-        // no-op
-    } else {						// must copy some text
-        if ( str1.Handle.s + str1.Handle.lnth == VbyteAlloc(*str1.Handle.ulink, 0) ) { // str1 at end of string area ?
-            VbyteAlloc( *str1.Handle.ulink, bsize ); // create room for 2nd part at the end of string area
-        } else {					// copy the two parts
-            char * str1newBuf = VbyteAlloc( *str1.Handle.ulink, clnth );
-            char * str1oldBuf = str1.Handle.s;  // must read after VbyteAlloc call in case it gs's
-            str1.Handle.s = str1newBuf;
-            memcpy( str1.Handle.s, str1oldBuf,  str1.Handle.lnth );
-        } // if
-        memcpy( str1.Handle.s + str1.Handle.lnth, buffer, bsize );
-    } // if
-    str1.Handle.lnth = clnth;
+	size_t clnth = str1.Handle.lnth + bsize;
+	if ( str1.Handle.s + str1.Handle.lnth == buffer ) { // already juxtapose ?
+		// no-op
+	} else {											// must copy some text
+		if ( str1.Handle.s + str1.Handle.lnth == VbyteAlloc(*str1.Handle.ulink, 0) ) { // str1 at end of string area ?
+			VbyteAlloc( *str1.Handle.ulink, bsize );	// create room for 2nd part at the end of string area
+		} else {										// copy the two parts
+			char * str1newBuf = VbyteAlloc( *str1.Handle.ulink, clnth );
+			char * str1oldBuf = str1.Handle.s;			// must read after VbyteAlloc call in case it gs's
+			str1.Handle.s = str1newBuf;
+			memcpy( str1.Handle.s, str1oldBuf,  str1.Handle.lnth );
+		} // if
+		memcpy( str1.Handle.s + str1.Handle.lnth, buffer, bsize );
+	} // if
+	str1.Handle.lnth = clnth;
 }
 
 void ?+=?(string_res & str1, const string_res & str2) {
-    append( str1, str2.Handle.s, str2.Handle.lnth );
+	append( str1, str2.Handle.s, str2.Handle.lnth );
 }
 
 void append(string_res & str1, const string_res & str2, size_t maxlen) {
-    append( str1, str2.Handle.s, min(str2.Handle.lnth, maxlen) );
+	append( str1, str2.Handle.s, min(str2.Handle.lnth, maxlen) );
 }
 
 void ?+=?(string_res & s, char c) {
-    append( s, & c, 1 );
+	append( s, & c, 1 );
 }
 void ?+=?(string_res & s, const char * c) {
-    append( s, c, strlen(c) );
+	append( s, c, strlen(c) );
 }
 
@@ -730,7 +744,7 @@
 
 void ?*=?(string_res & s, size_t factor) {
-    string_res s2 = { s, COPY_VALUE };
-    s = "";
-    for (factor) s += s2;
+	string_res s2 = { s, COPY_VALUE };
+	s = "";
+	for (factor) s += s2;
 }
 
@@ -739,8 +753,8 @@
 
 int strcmp(const string_res & s1, const string_res & s2) {
-    // return 0;
-    int ans1 = memcmp(s1.Handle.s, s2.Handle.s, min(s1.Handle.lnth, s2.Handle.lnth));
-    if (ans1 != 0) return ans1;
-    return s1.Handle.lnth - s2.Handle.lnth;
+	// return 0;
+	int ans1 = memcmp(s1.Handle.s, s2.Handle.s, min(s1.Handle.lnth, s2.Handle.lnth));
+	if (ans1 != 0) return ans1;
+	return s1.Handle.lnth - s2.Handle.lnth;
 }
 
@@ -753,6 +767,6 @@
 
 int strcmp (const string_res & s1, const char * s2) {
-    string_res s2x = s2;
-    return strcmp(s1, s2x);
+	string_res s2x = s2;
+	return strcmp(s1, s2x);
 }
 
@@ -765,6 +779,6 @@
 
 int strcmp (const char * s1, const string_res & s2) {
-    string_res s1x = s1;
-    return strcmp(s1x, s2);
+	string_res s1x = s1;
+	return strcmp(s1x, s2);
 }
 
@@ -777,133 +791,128 @@
 
 
-
 //////////////////////////////////////////////////////////
 // Search
 
 bool contains(const string_res & s, char ch) {
-    for ( i; size(s) ) {
-        if (s[i] == ch) return true;
-    }
-    return false;
+	for ( i; size(s) ) {
+		if (s[i] == ch) return true;
+	}
+	return false;
 }
 
 int find(const string_res & s, char search) {
-    return findFrom(s, 0, search);
+	return findFrom(s, 0, search);
 }
 
 int findFrom(const string_res & s, size_t fromPos, char search) {
-    // FIXME: This paricular overload (find of single char) is optimized to use memchr.
-    // The general overload (find of string, memchr applying to its first character) and `contains` should be adjusted to match.
-    char * searchFrom = s.Handle.s + fromPos;
-    size_t searchLnth = s.Handle.lnth - fromPos;
-    int searchVal = search;
-    char * foundAt = (char *) memchr(searchFrom, searchVal, searchLnth);
-    if (foundAt == 0p) return s.Handle.lnth;
-    else return foundAt - s.Handle.s;
+	// FIXME: This paricular overload (find of single char) is optimized to use memchr.
+	// The general overload (find of string, memchr applying to its first character) and `contains` should be adjusted to match.
+	char * searchFrom = s.Handle.s + fromPos;
+	size_t searchLnth = s.Handle.lnth - fromPos;
+	int searchVal = search;
+	char * foundAt = (char *) memchr(searchFrom, searchVal, searchLnth);
+	if (foundAt == 0p) return s.Handle.lnth;
+	else return foundAt - s.Handle.s;
 }
 
 int find(const string_res & s, const string_res & search) {
-    return findFrom(s, 0, search);
+	return findFrom(s, 0, search);
 }
 
 int findFrom(const string_res & s, size_t fromPos, const string_res & search) {
-    return findFrom(s, fromPos, search.Handle.s, search.Handle.lnth);
+	return findFrom(s, fromPos, search.Handle.s, search.Handle.lnth);
 }
 
 int find(const string_res & s, const char * search) {
-    return findFrom(s, 0, search);
+	return findFrom(s, 0, search);
 }
 int findFrom(const string_res & s, size_t fromPos, const char * search) {
-    return findFrom(s, fromPos, search, strlen(search));
+	return findFrom(s, fromPos, search, strlen(search));
 }
 
 int find(const string_res & s, const char * search, size_t searchsize) {
-    return findFrom(s, 0, search, searchsize);
+	return findFrom(s, 0, search, searchsize);
 }
 
 int findFrom(const string_res & s, size_t fromPos, const char * search, size_t searchsize) {
-
-    /* Remaining implementations essentially ported from Sunjay's work */
-
-
-    // FIXME: This is a naive algorithm. We probably want to switch to someting
-    // like Boyer-Moore in the future.
-    // https://en.wikipedia.org/wiki/String_searching_algorithm
-
-    // Always find the empty string
-    if (searchsize == 0) {
-        return 0;
-    }
-
-    for ( i; fromPos ~ s.Handle.lnth ) {
-        size_t remaining = s.Handle.lnth - i;
-        // Never going to find the search string if the remaining string is
-        // smaller than search
-        if (remaining < searchsize) {
-            break;
-        }
-
-        bool matched = true;
-        for ( j; searchsize ) {
-            if (search[j] != s.Handle.s[i + j]) {
-                matched = false;
-                break;
-            }
-        }
-        if (matched) {
-            return i;
-        }
-    }
-
-    return s.Handle.lnth;
+	/* Remaining implementations essentially ported from Sunjay's work */
+
+	// FIXME: This is a naive algorithm. We probably want to switch to someting
+	// like Boyer-Moore in the future.
+	// https://en.wikipedia.org/wiki/String_searching_algorithm
+
+	// Always find the empty string
+	if (searchsize == 0) {
+		return 0;
+	}
+
+	for ( i; fromPos ~ s.Handle.lnth ) {
+		size_t remaining = s.Handle.lnth - i;
+		// Never going to find the search string if the remaining string is
+		// smaller than search
+		if (remaining < searchsize) {
+			break;
+		}
+
+		bool matched = true;
+		for ( j; searchsize ) {
+			if (search[j] != s.Handle.s[i + j]) {
+				matched = false;
+				break;
+			}
+		}
+		if (matched) {
+			return i;
+		}
+	}
+	return s.Handle.lnth;
 }
 
 bool includes(const string_res & s, const string_res & search) {
-    return includes(s, search.Handle.s, search.Handle.lnth);
+	return includes(s, search.Handle.s, search.Handle.lnth);
 }
 
 bool includes(const string_res & s, const char * search) {
-    return includes(s, search, strlen(search));
+	return includes(s, search, strlen(search));
 }
 
 bool includes(const string_res & s, const char * search, size_t searchsize) {
-    return find(s, search, searchsize) < s.Handle.lnth;
+	return find(s, search, searchsize) < s.Handle.lnth;
 }
 
 bool startsWith(const string_res & s, const string_res & prefix) {
-    return startsWith(s, prefix.Handle.s, prefix.Handle.lnth);
+	return startsWith(s, prefix.Handle.s, prefix.Handle.lnth);
 }
 
 bool startsWith(const string_res & s, const char * prefix) {
-    return startsWith(s, prefix, strlen(prefix));
+	return startsWith(s, prefix, strlen(prefix));
 }
 
 bool startsWith(const string_res & s, const char * prefix, size_t prefixsize) {
-    if (s.Handle.lnth < prefixsize) {
-        return false;
-    }
-    return memcmp(s.Handle.s, prefix, prefixsize) == 0;
+	if (s.Handle.lnth < prefixsize) {
+		return false;
+	}
+	return memcmp(s.Handle.s, prefix, prefixsize) == 0;
 }
 
 bool endsWith(const string_res & s, const string_res & suffix) {
-    return endsWith(s, suffix.Handle.s, suffix.Handle.lnth);
+	return endsWith(s, suffix.Handle.s, suffix.Handle.lnth);
 }
 
 bool endsWith(const string_res & s, const char * suffix) {
-    return endsWith(s, suffix, strlen(suffix));
+	return endsWith(s, suffix, strlen(suffix));
 }
 
 bool endsWith(const string_res & s, const char * suffix, size_t suffixsize) {
-    if (s.Handle.lnth < suffixsize) {
-        return false;
-    }
-    // Amount to offset the bytes pointer so that we are comparing the end of s
-    // to suffix. s.bytes + offset should be the first byte to compare against suffix
-    size_t offset = s.Handle.lnth - suffixsize;
-    return memcmp(s.Handle.s + offset, suffix, suffixsize) == 0;
-}
-
-    /* Back to Mike's work */
-
+	if (s.Handle.lnth < suffixsize) {
+		return false;
+	}
+	// Amount to offset the bytes pointer so that we are comparing the end of s
+	// to suffix. s.bytes + offset should be the first byte to compare against suffix
+	size_t offset = s.Handle.lnth - suffixsize;
+	return memcmp(s.Handle.s + offset, suffix, suffixsize) == 0;
+}
+
+/* Back to Mike's work */
 
 ///////////////////////////////////////////////////////////////////////////
@@ -911,37 +920,37 @@
 
 void ?{}( charclass_res & s, const string_res & chars) {
-    (s){ chars.Handle.s, chars.Handle.lnth };
+	(s){ chars.Handle.s, chars.Handle.lnth };
 }
 
 void ?{}( charclass_res & s, const char * chars ) {
-    (s){ chars, strlen(chars) };
+	(s){ chars, strlen(chars) };
 }
 
 void ?{}( charclass_res & s, const char * chars, size_t charssize ) {
-    (s.chars){ chars, charssize };
-    // now sort it ?
+	(s.chars){ chars, charssize };
+	// now sort it ?
 }
 
 void ^?{}( charclass_res & s ) {
-    ^(s.chars){};
+	^(s.chars){};
 }
 
 static bool test( const charclass_res & mask, char c ) {
-    // instead, use sorted char list?
-    return contains( mask.chars, c );
+	// instead, use sorted char list?
+	return contains( mask.chars, c );
 }
 
 int exclude(const string_res & s, const charclass_res & mask) {
-    for ( i; size(s) ) {
-        if ( test(mask, s[i]) ) return i;
-    }
-    return size(s);
+	for ( i; size(s) ) {
+		if ( test(mask, s[i]) ) return i;
+	}
+	return size(s);
 }
 
 int include(const string_res & s, const charclass_res & mask) {
-    for ( i; size(s) ) {
-        if ( ! test(mask, s[i]) ) return i;
-    }
-    return size(s);
+	for ( i; size(s) ) {
+		if ( ! test(mask, s[i]) ) return i;
+	}
+	return size(s);
 }
 
@@ -953,15 +962,15 @@
 static void AddThisAfter( HandleNode & s, HandleNode & n ) with(s) {
 #ifdef VbyteDebug
-    serr | "enter:AddThisAfter, s:" | &s | " n:" | &n;
-#endif // VbyteDebug
-    // Performance note: we are on the critical path here. MB has ensured that the verifies don't contribute to runtime (are compiled away, like they're supposed to be).
-    verify( n.ulink != 0p );
-    verify( s.ulink == n.ulink );
-    flink = n.flink;
-    blink = &n;
-    n.flink->blink = &s;
-    n.flink = &s;
-#ifdef VbyteDebug
-    {
+	serr | "enter:AddThisAfter, s:" | &s | " n:" | &n;
+#endif // VbyteDebug
+	// Performance note: we are on the critical path here. MB has ensured that the verifies don't contribute to runtime (are compiled away, like they're supposed to be).
+	verify( n.ulink != 0p );
+	verify( s.ulink == n.ulink );
+	flink = n.flink;
+	blink = &n;
+	n.flink->blink = &s;
+	n.flink = &s;
+#ifdef VbyteDebug
+	{
 		serr | "HandleList:";
 		serr | nlOff;
@@ -974,6 +983,6 @@
 		} // for
 		serr | nlOn;
-    }
-    serr | "exit:AddThisAfter";
+	}
+	serr | "exit:AddThisAfter";
 #endif // VbyteDebug
 } // AddThisAfter
@@ -984,10 +993,10 @@
 static void DeleteNode( HandleNode & s ) with(s) {
 #ifdef VbyteDebug
-    serr | "enter:DeleteNode, s:" | &s;
-#endif // VbyteDebug
-    flink->blink = blink;
-    blink->flink = flink;
-#ifdef VbyteDebug
-    serr | "exit:DeleteNode";
+	serr | "enter:DeleteNode, s:" | &s;
+#endif // VbyteDebug
+	flink->blink = blink;
+	blink->flink = flink;
+#ifdef VbyteDebug
+	serr | "exit:DeleteNode";
 #endif // VbyteDebug
 } //  DeleteNode
@@ -999,20 +1008,20 @@
 static char * VbyteAlloc( VbyteHeap & s, int size ) with(s) {
 #ifdef VbyteDebug
-    serr | "enter:VbyteAlloc, size:" | size;
-#endif // VbyteDebug
-    uintptr_t NoBytes;
-    char *r;
-
-    NoBytes = ( uintptr_t )EndVbyte + size;
-    if ( NoBytes > ( uintptr_t )ExtVbyte ) {			// enough room for new byte-string ?
+	serr | "enter:VbyteAlloc, size:" | size;
+#endif // VbyteDebug
+	uintptr_t NoBytes;
+	char *r;
+
+	NoBytes = ( uintptr_t )EndVbyte + size;
+	if ( NoBytes > ( uintptr_t )ExtVbyte ) {			// enough room for new byte-string ?
 		garbage( s, size );								// firer up the garbage collector
 		verify( (( uintptr_t )EndVbyte + size) <= ( uintptr_t )ExtVbyte  && "garbage run did not free up required space" );
-    } // if
-    r = EndVbyte;
-    EndVbyte += size;
-#ifdef VbyteDebug
-    serr | "exit:VbyteAlloc, r:" | (void *)r | " EndVbyte:" | (void *)EndVbyte | " ExtVbyte:" | ExtVbyte;
-#endif // VbyteDebug
-    return r;
+	} // if
+	r = EndVbyte;
+	EndVbyte += size;
+#ifdef VbyteDebug
+	serr | "exit:VbyteAlloc, r:" | (void *)r | " EndVbyte:" | (void *)EndVbyte | " ExtVbyte:" | ExtVbyte;
+#endif // VbyteDebug
+	return r;
 } // VbyteAlloc
 
@@ -1027,18 +1036,18 @@
 
 static char * VbyteTryAdjustLast( VbyteHeap & s, int delta ) with(s) {
-    if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) {
-        // room available
-        EndVbyte += delta;
-        return 0p;
-    }
-
-    char *oldBytes = StartVbyte;
-
-    NoOfExtensions += 1;
-    CurrSize *= 2;
-    StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
-    ExtVbyte = StartVbyte + CurrSize;
-
-    return oldBytes;
+	if ( ( uintptr_t )EndVbyte + delta <= ( uintptr_t )ExtVbyte ) {
+		// room available
+		EndVbyte += delta;
+		return 0p;
+	}
+
+	char *oldBytes = StartVbyte;
+
+	NoOfExtensions += 1;
+	CurrSize *= 2;
+	StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
+	ExtVbyte = StartVbyte + CurrSize;
+
+	return oldBytes;
 }
 
@@ -1049,40 +1058,37 @@
 static void MoveThisAfter( HandleNode & s, const HandleNode  & h ) with(s) {
 #ifdef VbyteDebug
-    serr | "enter:MoveThisAfter, s:" | & s | " h:" | & h;
-#endif // VbyteDebug
-    verify( h.ulink != 0p );
-    verify( s.ulink == h.ulink );
-    if ( s < h.s ) {					// check argument values
+	serr | "enter:MoveThisAfter, s:" | & s | " h:" | & h;
+#endif // VbyteDebug
+	verify( h.ulink != 0p );
+	verify( s.ulink == h.ulink );
+	if ( s < h.s ) {					// check argument values
 		// serr | "VbyteSM: Error - Cannot move byte string starting at:" | s | " after byte string starting at:"
-		//      | ( h->s ) | " and keep handles in ascending order";
+		//	  | ( h->s ) | " and keep handles in ascending order";
 		// exit(-1 );
 		verify( 0 && "VbyteSM: Error - Cannot move byte strings as requested and keep handles in ascending order");
-    } // if
-
-    HandleNode *i;
-    for ( i = h.flink; i->s != 0 && s > ( i->s ); i = i->flink ); // find the position for this node after h
-    if ( & s != i->blink ) {
+	} // if
+
+	HandleNode *i;
+	for ( i = h.flink; i->s != 0 && s > ( i->s ); i = i->flink ); // find the position for this node after h
+	if ( & s != i->blink ) {
 		DeleteNode( s );
 		AddThisAfter( s, *i->blink );
-    } // if
-#ifdef VbyteDebug
-    {
-	serr | "HandleList:";
-	serr | nlOff;
-	for ( HandleNode *n = HeaderPtr->flink; n != HeaderPtr; n = n->flink ) {
-	    serr | "\tnode:" | n | " lnth:" | n->lnth | " s:" | (void *)n->s | ",\"";
-	    for ( i; n->lnth ) {
-			serr | n->s[i];
-	    } // for
-	    serr | "\" flink:" | n->flink | " blink:" | n->blink | nl;
-	} // for
-	serr | nlOn;
-    }
-    serr | "exit:MoveThisAfter";
+	} // if
+#ifdef VbyteDebug
+	{
+		serr | "HandleList:";
+		serr | nlOff;
+		for ( HandleNode *n = HeaderPtr->flink; n != HeaderPtr; n = n->flink ) {
+			serr | "\tnode:" | n | " lnth:" | n->lnth | " s:" | (void *)n->s | ",\"";
+			for ( i; n->lnth ) {
+				serr | n->s[i];
+			} // for
+			serr | "\" flink:" | n->flink | " blink:" | n->blink | nl;
+		} // for
+		serr | nlOn;
+	}
+	serr | "exit:MoveThisAfter";
 #endif // VbyteDebug
 } // MoveThisAfter
-
-
-
 
 
@@ -1097,43 +1103,43 @@
 int ByteCmp( char *Src1, int Src1Start, int Src1Lnth, char *Src2, int Src2Start, int Src2Lnth )  {
 #ifdef VbyteDebug
-    serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth;
-#endif // VbyteDebug
-    int cmp;
-
-    CharZip: for ( int i = 0; ; i += 1 ) {
-	if ( i == Src2Lnth - 1 ) {
-	    for ( ; ; i += 1 ) {
+	serr | "enter:ByteCmp, Src1Start:" | Src1Start | " Src1Lnth:" | Src1Lnth | " Src2Start:" | Src2Start | " Src2Lnth:" | Src2Lnth;
+#endif // VbyteDebug
+	int cmp;
+
+  CharZip: for ( int i = 0; ; i += 1 ) {
+		if ( i == Src2Lnth - 1 ) {
+			for ( ; ; i += 1 ) {
+				if ( i == Src1Lnth - 1 ) {
+					cmp = 0;
+					break CharZip;
+				} // exit
+				if ( Src1[Src1Start + i] != ' ') {
+					// SUSPECTED BUG:  this could be be why Peter got the bug report about == " "  (why is this case here at all?)
+					cmp = 1;
+					break CharZip;
+				} // exit
+			} // for
+		} // exit
 		if ( i == Src1Lnth - 1 ) {
-		    cmp = 0;
-		    break CharZip;
+			for ( ; ; i += 1 ) {
+				if ( i == Src2Lnth - 1 ) {
+					cmp = 0;
+					break CharZip;
+				} // exit
+				if ( Src2[Src2Start + i] != ' ') {
+					cmp = -1;
+					break CharZip;
+				} // exit
+			} // for
 		} // exit
-		if ( Src1[Src1Start + i] != ' ') {
-			// SUSPECTED BUG:  this could be be why Peter got the bug report about == " "  (why is this case here at all?)
-		    cmp = 1;
-		    break CharZip;
+		if ( Src2[Src2Start + i] != Src1[Src1Start+ i]) {
+			cmp = Src1[Src1Start + i] > Src2[Src2Start + i] ? 1 : -1;
+			break CharZip;
 		} // exit
-	    } // for
-	} // exit
-	if ( i == Src1Lnth - 1 ) {
-	    for ( ; ; i += 1 ) {
-	    	if ( i == Src2Lnth - 1 ) {
-		    cmp = 0;
-		    break CharZip;
-		} // exit
-	    	if ( Src2[Src2Start + i] != ' ') {
-		    cmp = -1;
-		    break CharZip;
-		} // exit
-	    } // for
-	} // exit
-      if ( Src2[Src2Start + i] != Src1[Src1Start+ i]) {
-	    cmp = Src1[Src1Start + i] > Src2[Src2Start + i] ? 1 : -1;
-	    break CharZip;
-	} // exit
-    } // for
-#ifdef VbyteDebug
-    serr | "exit:ByteCmp, cmp:" | cmp;
-#endif // VbyteDebug
-    return cmp;
+	} // for
+#ifdef VbyteDebug
+	serr | "exit:ByteCmp, cmp:" | cmp;
+#endif // VbyteDebug
+	return cmp;
 } // ByteCmp
 
@@ -1145,11 +1151,11 @@
 
 void compaction(VbyteHeap & s) with(s) {
-    HandleNode *h;
-    char *obase, *nbase, *limit;
-    
-    NoOfCompactions += 1;
-    EndVbyte = StartVbyte;
-    h = Header.flink;					// ignore header node
-    for () {
+	HandleNode *h;
+	char *obase, *nbase, *limit;
+	
+	NoOfCompactions += 1;
+	EndVbyte = StartVbyte;
+	h = Header.flink;					// ignore header node
+	for () {
 		memmove( EndVbyte, h->s, h->lnth );
 		obase = h->s;
@@ -1169,13 +1175,13 @@
 		} // for
 		if ( h == &Header ) break;			// end of header list ?
-    } // for
+	} // for
 } // compaction
 
 
 static double heap_expansion_freespace_threshold = 0.1;  // default inherited from prior work: expand heap when less than 10% "free" (i.e. garbage)
-                                                         // probably an unreasonable default, but need to assess early-round tests on changing it
+														 // probably an unreasonable default, but need to assess early-round tests on changing it
 
 void TUNING_set_string_heap_liveness_threshold( double val ) {
-    heap_expansion_freespace_threshold = 1.0 - val;
+	heap_expansion_freespace_threshold = 1.0 - val;
 }
 
@@ -1186,6 +1192,6 @@
 void garbage(VbyteHeap & s, int minreq ) with(s) {
 #ifdef VbyteDebug
-    serr | "enter:garbage";
-    {
+	serr | "enter:garbage";
+	{
 		serr | "HandleList:";
 		for ( HandleNode *n = Header.flink; n != &Header; n = n->flink ) {
@@ -1198,29 +1204,29 @@
 			serr | "\" flink:" | n->flink | " blink:" | n->blink;
 		} // for
-    }
-#endif // VbyteDebug
-    int AmountUsed, AmountFree;
-
-    AmountUsed = 0;
-    for ( HandleNode *i = Header.flink; i != &Header; i = i->flink ) { // calculate amount of byte area used
+	}
+#endif // VbyteDebug
+	int AmountUsed, AmountFree;
+
+	AmountUsed = 0;
+	for ( HandleNode *i = Header.flink; i != &Header; i = i->flink ) { // calculate amount of byte area used
 		AmountUsed += i->lnth;
-    } // for
-    AmountFree = ( uintptr_t )ExtVbyte - ( uintptr_t )StartVbyte - AmountUsed;
-    
-    if ( ( double ) AmountFree < ( CurrSize * heap_expansion_freespace_threshold ) || AmountFree < minreq ) {	// free space less than threshold or not enough to serve cur request
+	} // for
+	AmountFree = ( uintptr_t )ExtVbyte - ( uintptr_t )StartVbyte - AmountUsed;
+	
+	if ( ( double ) AmountFree < ( CurrSize * heap_expansion_freespace_threshold ) || AmountFree < minreq ) {	// free space less than threshold or not enough to serve cur request
 
 		extend( s, max( CurrSize, minreq ) );				// extend the heap
 
-			//  Peter says, "This needs work before it should be used."
-			//  } else if ( AmountFree > CurrSize / 2 ) {		// free space greater than 3 times the initial allocation ? 
-			//		reduce(( AmountFree / CurrSize - 3 ) * CurrSize ); // reduce the memory
-
-        // `extend` implies a `compaction` during the copy
-
-    } else {
-        compaction(s);					// in-place
-    }// if
-#ifdef VbyteDebug
-    {
+		//  Peter says, "This needs work before it should be used."
+		//  } else if ( AmountFree > CurrSize / 2 ) {		// free space greater than 3 times the initial allocation ? 
+		//		reduce(( AmountFree / CurrSize - 3 ) * CurrSize ); // reduce the memory
+
+		// `extend` implies a `compaction` during the copy
+
+	} else {
+		compaction(s);					// in-place
+	}// if
+#ifdef VbyteDebug
+	{
 		serr | "HandleList:";
 		for ( HandleNode *n = Header.flink; n != &Header; n = n->flink ) {
@@ -1233,6 +1239,6 @@
 			serr | "\" flink:" | n->flink | " blink:" | n->blink;
 		} // for
-    }
-    serr | "exit:garbage";
+	}
+	serr | "exit:garbage";
 #endif // VbyteDebug
 } // garbage
@@ -1247,18 +1253,18 @@
 void extend( VbyteHeap & s, int size ) with (s) {
 #ifdef VbyteDebug
-    serr | "enter:extend, size:" | size;
-#endif // VbyteDebug
-    char *OldStartVbyte;
-
-    NoOfExtensions += 1;
-    OldStartVbyte = StartVbyte;				// save previous byte area
-    
-    CurrSize += size > InitSize ? size : InitSize;	// minimum extension, initial size
-    StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
-    ExtVbyte = (void *)( StartVbyte + CurrSize );
-    compaction(s);					// copy from old heap to new & adjust pointers to new heap
-    free( OldStartVbyte );				// release old heap
-#ifdef VbyteDebug
-    serr | "exit:extend, CurrSize:" | CurrSize;
+	serr | "enter:extend, size:" | size;
+#endif // VbyteDebug
+	char *OldStartVbyte;
+
+	NoOfExtensions += 1;
+	OldStartVbyte = StartVbyte;				// save previous byte area
+	
+	CurrSize += size > InitSize ? size : InitSize;	// minimum extension, initial size
+	StartVbyte = EndVbyte = TEMP_ALLOC(char, CurrSize);
+	ExtVbyte = (void *)( StartVbyte + CurrSize );
+	compaction(s);					// copy from old heap to new & adjust pointers to new heap
+	free( OldStartVbyte );				// release old heap
+#ifdef VbyteDebug
+	serr | "exit:extend, CurrSize:" | CurrSize;
 #endif // VbyteDebug
 } // extend
@@ -1272,18 +1278,18 @@
 void VbyteHeap::reduce( int size ) {
 #ifdef VbyteDebug
-    serr | "enter:reduce, size:" | size;
-#endif // VbyteDebug
-    char *OldStartVbyte;
-
-    NoOfReductions += 1;
-    OldStartVbyte = StartVbyte;				// save previous byte area
-    
-    CurrSize -= size;
-    StartVbyte = EndVbyte = new char[CurrSize];
-    ExtVbyte = (void *)( StartVbyte + CurrSize );
-    compaction();					// copy from old heap to new & adjust pointers to new heap
-    delete  OldStartVbyte;				// release old heap
-#ifdef VbyteDebug
-    serr | "exit:reduce, CurrSize:" | CurrSize;
+	serr | "enter:reduce, size:" | size;
+#endif // VbyteDebug
+	char *OldStartVbyte;
+
+	NoOfReductions += 1;
+	OldStartVbyte = StartVbyte;				// save previous byte area
+	
+	CurrSize -= size;
+	StartVbyte = EndVbyte = new char[CurrSize];
+	ExtVbyte = (void *)( StartVbyte + CurrSize );
+	compaction();					// copy from old heap to new & adjust pointers to new heap
+	delete  OldStartVbyte;				// release old heap
+#ifdef VbyteDebug
+	!serr | "exit:reduce, CurrSize:" | CurrSize;
 #endif // VbyteDebug
 } // reduce
Index: libcfa/src/collections/string_res.hfa
===================================================================
--- libcfa/src/collections/string_res.hfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ libcfa/src/collections/string_res.hfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,6 @@
 // Created On       : Fri Sep 03 11:00:00 2021
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Jan  4 11:28:06 2024
-// Update Count     : 27
+// Last Modified On : Wed Feb  7 21:24:40 2024
+// Update Count     : 59
 //
 
@@ -123,29 +123,51 @@
 void ?|?(ofstream & out, const string_res & s);
 ifstream & ?|?(ifstream & in, string_res & s);
-void ?|?( ifstream & in, string_res & s );
+
+struct _Istream_Rwidth {
+	string_res * s;
+	inline _Istream_str_base;
+}; // _Istream_Rwidth
+
+struct _Istream_Rquoted {
+	// string_res * s;
+	// inline _Istream_str_base;
+	_Istream_Rwidth rstr;
+}; // _Istream_Rquoted
 
 struct _Istream_Rstr {
 	string_res * s;
 	inline _Istream_str_base;
+//	_Istream_Rwidth rstr;
 }; // _Istream_Rstr
 
 static inline {
 	// read width does not include null terminator
-	_Istream_Rstr wdi( unsigned int rwd, string_res & s ) { return (_Istream_Rstr)@{ &s, {{0p}, rwd, {.flags.rwd : true}} }; }
+	_Istream_Rwidth wdi( unsigned int rwd, string_res & s ) { return (_Istream_Rwidth)@{ .s : &s, { {.scanset : 0p}, .wd : rwd, {.flags.rwd : true} } }; }
 	_Istream_Rstr getline( string_res & s, const char delimiter = '\n' ) {
-		return (_Istream_Rstr)@{ &s, {{.delimiters : { delimiter, '\0' } }, -1, {.flags.delimiter : true, .flags.inex : true}} };
-	}
-	_Istream_Rstr & getline( _Istream_Rstr & fmt, const char delimiter = '\n' ) {
-		fmt.delimiters[0] = delimiter; fmt.delimiters[1] = '\0'; fmt.flags.delimiter = true; fmt.flags.inex = true; return fmt;
-	}
-	_Istream_Rstr incl( const char scanset[], string_res & s ) { return (_Istream_Rstr)@{ &s, {{scanset}, -1, {.flags.inex : false}} }; }
-	_Istream_Rstr & incl( const char scanset[], _Istream_Rstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
-	_Istream_Rstr excl( const char scanset[], string_res & s ) { return (_Istream_Rstr)@{ &s, {{scanset}, -1, {.flags.inex : true}} }; }
-	_Istream_Rstr & excl( const char scanset[], _Istream_Rstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = true; return fmt; }
-	_Istream_Rstr ignore( string_res & s ) { return (_Istream_Rstr)@{ &s, {{0p}, -1, {.flags.ignore : true}} }; }
-	_Istream_Rstr & ignore( _Istream_Rstr & fmt ) { fmt.flags.ignore = true; return fmt; }
+//		return (_Istream_Rstr)@{ { .s : &s, { {.delimiters : { delimiter, '\0' } }, .wd : -1, {.flags.delimiter : true} } } };
+		return (_Istream_Rstr)@{ .s : &s, { {.delimiters : { delimiter, '\0' } }, .wd : -1, {.flags.delimiter : true} } };
+	}
+	_Istream_Rstr & getline( _Istream_Rwidth & f, const char delimiter = '\n' ) {
+		f.delimiters[0] = delimiter; f.delimiters[1] = '\0'; f.flags.delimiter = true; return (_Istream_Rstr &)f;
+	}
+	_Istream_Rquoted quoted( string_res & s, const char Ldelimiter = '\"', const char Rdelimiter = '\0' ) {
+		return (_Istream_Rquoted)@{ { .s : &s, { {.delimiters : { Ldelimiter, Rdelimiter, '\0' }}, .wd : -1, {.flags.rwd : true} } } };
+	}
+	_Istream_Rquoted & quoted( _Istream_Rwidth & f, const char Ldelimiter = '"', const char Rdelimiter = '\0' ) {
+		f.delimiters[0] = Ldelimiter;  f.delimiters[1] = Rdelimiter;  f.delimiters[2] = '\0';
+		return (_Istream_Rquoted &)f;
+	}
+	_Istream_Rstr incl( const char scanset[], string_res & s ) { return (_Istream_Rstr)@{ .s : &s, { {.scanset : scanset}, .wd : -1, {.flags.inex : false} } }; }
+	_Istream_Rstr & incl( const char scanset[], _Istream_Rwidth & f ) { f.scanset = scanset; f.flags.inex = false; return (_Istream_Rstr &)f; }
+	_Istream_Rstr excl( const char scanset[], string_res & s ) { return (_Istream_Rstr)@{ .s : &s, { {.scanset : scanset}, .wd : -1, {.flags.inex : true} } }; }
+	_Istream_Rstr & excl( const char scanset[], _Istream_Rwidth & f ) { f.scanset = scanset; f.flags.inex = true; return (_Istream_Rstr &)f; }
+	_Istream_Rstr ignore( string_res & s ) { return (_Istream_Rstr)@{ .s : &s, { {.scanset : 0p}, .wd : -1, {.flags.ignore : true} } }; }
+	_Istream_Rstr & ignore( _Istream_Rwidth & f ) { f.flags.ignore = true; return (_Istream_Rstr &)f; }
+	_Istream_Rquoted & ignore( _Istream_Rquoted & f ) { f.rstr.flags.ignore = true; return (_Istream_Rquoted &)f; }
+	_Istream_Rstr & ignore( _Istream_Rstr & f ) { f.flags.ignore = true; return (_Istream_Rstr &)f; }
 } // distribution
+ifstream & ?|?( ifstream & is, _Istream_Rquoted f );
 ifstream & ?|?( ifstream & is, _Istream_Rstr f );
-void ?|?( ifstream & is, _Istream_Rstr t );
+static inline ifstream & ?|?( ifstream & is, _Istream_Rwidth f ) { return is | *(_Istream_Rstr *)&f; }
 
 // Concatenation
Index: libcfa/src/fstream.cfa
===================================================================
--- libcfa/src/fstream.cfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ libcfa/src/fstream.cfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Jan 28 09:56:08 2024
-// Update Count     : 554
+// Last Modified On : Sun Feb 11 20:55:45 2024
+// Update Count     : 580
 //
 
@@ -121,5 +121,5 @@
     } // for
 	if ( file == 0p ) {
-		throw (open_failure){ os };
+		throwResume (open_failure){ os };
 		// abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno );
 	} // if
@@ -241,5 +241,5 @@
     } // for
 	if ( file == 0p ) {
-		throw (open_failure){ is };
+		throwResume (open_failure){ is };
 		// abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno );
 	} // if
@@ -295,9 +295,10 @@
 	va_start( args, format );
 
-	int nargs;
+	int nargs, tmperrno;
     for () {											// no check for EINTR limit waiting for keyboard input
-		errno = 0;
 		disable_interrupts();
+		errno = 0;
 		nargs = vfscanf( (FILE *)(is.file$), format, args );
+		tmperrno = errno;
 		enable_interrupts();
 	  if ( nargs != EOF || errno != EINTR ) break;		// timer interrupt ?
@@ -308,4 +309,5 @@
 		} // if
 	} // if
+	if ( tmperrno == ERANGE ) throwResume ExceptionInst( data_range );
 	va_end( args );
 	return nargs;
@@ -318,6 +320,4 @@
 // *********************************** exceptions ***********************************
 
-
-static vtable(open_failure) open_failure_vt;
 
 // exception I/O constructors
@@ -335,6 +335,4 @@
 
 
-static vtable(close_failure) close_failure_vt;
-
 // exception I/O constructors
 void ?{}( close_failure & ex, ofstream & ostream ) with( ex ) {
@@ -351,6 +349,4 @@
 
 
-static vtable(write_failure) write_failure_vt;
-
 // exception I/O constructors
 void ?{}( write_failure & ex, ofstream & ostream ) with( ex ) {
@@ -367,6 +363,4 @@
 
 
-static vtable(read_failure) read_failure_vt;
-
 // exception I/O constructors
 void ?{}( read_failure & ex, ofstream & ostream ) with( ex ) {
Index: libcfa/src/fstream.hfa
===================================================================
--- libcfa/src/fstream.hfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ libcfa/src/fstream.hfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Oct 18 20:30:12 2023
-// Update Count     : 261
+// Last Modified On : Sun Feb 11 20:35:00 2024
+// Update Count     : 274
 //
 
@@ -139,5 +139,5 @@
 
 
-exception open_failure {
+ExceptionDecl( open_failure,
 	union {
 		ofstream * ostream;
@@ -146,10 +146,10 @@
 	// TEMPORARY: need polymorphic exceptions
 	int tag;											// 1 => ostream; 0 => istream
-};
+);
 
 void ?{}( open_failure & this, ofstream & );
 void ?{}( open_failure & this, ifstream & );
 
-exception close_failure {
+ExceptionDecl( close_failure,
 	union {
 		ofstream * ostream;
@@ -158,10 +158,10 @@
 	// TEMPORARY: need polymorphic exceptions
 	int tag;											// 1 => ostream; 0 => istream
-};
+);
 
 void ?{}( close_failure & this, ofstream & );
 void ?{}( close_failure & this, ifstream & );
 
-exception write_failure {
+ExceptionDecl( write_failure,
 	union {
 		ofstream * ostream;
@@ -170,10 +170,10 @@
 	// TEMPORARY: need polymorphic exceptions
 	int tag;											// 1 => ostream; 0 => istream
-};
+);
 
 void ?{}( write_failure & this, ofstream & );
 void ?{}( write_failure & this, ifstream & );
 
-exception read_failure {
+ExceptionDecl( read_failure,
 	union {
 		ofstream * ostream;
@@ -182,5 +182,5 @@
 	// TEMPORARY: need polymorphic exceptions
 	int tag;											// 1 => ostream; 0 => istream
-};
+);
 
 void ?{}( read_failure & this, ofstream & );
Index: libcfa/src/iostream.cfa
===================================================================
--- libcfa/src/iostream.cfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ libcfa/src/iostream.cfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Jan 28 11:58:54 2024
-// Update Count     : 1917
+// Last Modified On : Mon Feb 12 09:26:05 2024
+// Update Count     : 1966
 //
 
@@ -774,7 +774,8 @@
 forall( istype & | basic_istream( istype ) ) {
 	istype & ?|?( istype & is, bool & b ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		char val[6];
 		int args = fmt( is, "%5s", val );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		if ( strcmp( val, "true" ) == 0 ) b = true;
 		else if ( strcmp( val, "false" ) == 0 ) b = false;
@@ -787,8 +788,9 @@
 
 	istype & ?|?( istype & is, char & c ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		char temp;
 		for () {
 			int args = fmt( is, "%c", &temp );
-			if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+			if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 			// do not overwrite parameter with newline unless appropriate
 			if ( temp != '\n' || getANL$( is ) ) { c = temp; break; }
@@ -799,60 +801,70 @@
 
 	istype & ?|?( istype & is, signed char & sc ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%hhi", &sc );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, unsigned char & usc ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%hhi", &usc );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, short int & si ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%hi", &si );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, unsigned short int & usi ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%hi", &usi );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, int & i ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%i", &i );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, unsigned int & ui ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%i", &ui );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, long int & li ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%li", &li );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, unsigned long int & ulli ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%li", &ulli );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, long long int & lli ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%lli", &lli );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, unsigned long long int & ulli ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%lli", &ulli );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
@@ -881,25 +893,29 @@
 
 	istype & ?|?( istype & is, float & f ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%f", &f );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, double & d ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%lf", &d );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, long double & ld ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args = fmt( is, "%Lf", &ld );
-		if ( args != -1 && args != 1 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
 
 	istype & ?|?( istype & is, float _Complex & fc ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		float re, im;
 		int args = fmt( is, "%f%fi", &re, &im );
-		if ( args != -1 && args != 2 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 2 ) throwResume ExceptionInst( missing_data );
 		fc = re + im * _Complex_I;
 		return is;
@@ -907,7 +923,8 @@
 
 	istype & ?|?( istype & is, double _Complex & dc ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		double re, im;
 		int args = fmt( is, "%lf%lfi", &re, &im );
-		if ( args != -1 && args != 2 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 2 ) throwResume ExceptionInst( missing_data );
 		dc = re + im * _Complex_I;
 		return is;
@@ -915,7 +932,8 @@
 
 	istype & ?|?( istype & is, long double _Complex & ldc ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		long double re, im;
 		int args = fmt( is, "%Lf%Lfi", &re, &im );
-		if ( args != -1 && args != 2 ) throwResume ExceptionInst( missing_data );
+		if ( ! eof( is ) && args != 2 ) throwResume ExceptionInst( missing_data );
 		ldc = re + im * _Complex_I;
 		return is;
@@ -923,11 +941,12 @@
 
 	istype & ?|?( istype & is, const char fmt[] ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		size_t len = strlen( fmt );
-		char fmt2[len + 16];
-		strcpy( fmt2, fmt );							// copy format and add %n
-		strcpy( &fmt2[len], "%n" );
+		char fmtstr[len + 16];
+		strcpy( fmtstr, fmt );							// copy format and add %n
+		strcpy( &fmtstr[len], "%n" );
 		int len2 = -1;
-		int args = fmt( is, fmt2, &len2 );
-		if ( args != -1 && len2 == -1 ) throwResume ExceptionInst( missing_data );
+		fmt( is, fmtstr, &len2 );
+		if ( ! eof( is ) && len2 == -1 ) throwResume ExceptionInst( missing_data );
 		return is;
 	} // ?|?
@@ -963,5 +982,5 @@
 forall( istype & | basic_istream( istype ) ) {
 	istype & ?|?( istype & is, _Istream_Cskip f ) {
-		// printf( "skip %s %d\n", f.scanset, f.wd );
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		if ( f.scanset ) {
 			int nscanset = strlen(f.scanset);
@@ -971,12 +990,10 @@
 			strcpy( &fmtstr[pos], f.scanset );  pos += nscanset;
 			strcpy( &fmtstr[pos], "]" );
-			fmt( is, fmtstr, "" );						// skip scanset
+			fmt( is, fmtstr, "" );						// skip scanset, zero or more
 		} else {
 			char ch;
-			// fprintf( stderr, "skip " );
 			for ( f.wd ) {								// skip N characters
-			  if ( eof( is ) ) break;
-				fmt( is, "%c", &ch );
-				// fprintf( stderr, "`%c' ", ch );
+				int args = fmt( is, "%c", &ch );
+				if ( args != 1 ) throwResume ExceptionInst( missing_data );
 			} // for
 		} // if
@@ -985,12 +1002,11 @@
 
 	istype & ?|?( istype & is, _Istream_Cquoted f ) with( f.cstr ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		int args;
 	  fini: {
-			args = fmt( is, "%*[ \f\n\r\t\v]" );		// remove leading whitespace
-			if ( eof( is ) ) break fini;
-			char rfmt[4] = { delimiters[0], '%', 'n', '\0' };
-			int len = 0;								// may not be set in fmt
-			args = fmt( is, rfmt, &len );				// remove leading quote
-			if ( len == 0 || eof( is ) ) break fini;
+			char rfmt[5] = { ' ', delimiters[0], '%', 'n', '\0' };
+			int len = -1;								// may not be set in fmt
+			args = fmt( is, rfmt, &len );				// remove leading whitespace and quote
+			if ( eof( is ) || len == -1 ) break fini;
 
 			// Change the remainder of the read into a getline by reseting the closing delimiter.
@@ -1011,4 +1027,5 @@
 
 	istype & ?|?( istype & is, _Istream_Cstr f ) with( f.cstr ) {
+		if ( eof( is ) ) throwResume ExceptionInst( missing_data );
 		const char * scanset;
 		size_t nscanset = 0;
@@ -1041,10 +1058,10 @@
 			if ( flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*'
 			else args = fmt( is, fmtstr, s, &len );
-			// fprintf( stderr, "cstr %s %d %d %d %s\n", fmtstr, args, len, wd, s );
+			// fprintf( stderr, "cstr %s %d %d %d\n", fmtstr, args, len, f.cstr.wd );
 			if ( check && len >= rwd && ! eof( is ) ) {	// might not fit
 				char peek;
 				fmt( is, "%c", &peek );					// check for whitespace terminator
 				// fprintf( stderr, "peek %d '%c'\n", args, peek );
-				if ( ! eof( is ) ) {
+				if ( ! eof( is ) ) {					// can only fail at eof
 					ungetc( is, peek );
 					if ( ! isspace( peek ) ) throwResume ExceptionInst( cstring_length );
@@ -1052,9 +1069,10 @@
 			} // if
 			// FIX ME: CFA strings need to be modified to NOT change the argument for this case, then this can be removed.
-			if ( ! flags.ignore && args == 0 ) s[0]= '\0'; // read failed => no pattern match => set string to null
+			//fprintf( stderr, "cstr %d %d %d %d '%s'\n", flags.ignore, args, len, eof( is ), s );
+			//if ( ! flags.ignore && args == 0 ) s[0]= '\0'; // read failed => no pattern match => set string to null
 		} else {
 			if ( flags.delimiter ) {					// getline
 				int len = 0;							// may not be set in fmt
-				if ( delimiters[2] != '\0' ) {			// read single character ?
+				if ( delimiters[2] != '\0' ) {			// (quoted) read single character ?
 					sprintf( &fmtstr[pos], "c%%n" );
 				} else {
@@ -1063,4 +1081,5 @@
 				if ( flags.ignore ) args = fmt( is, fmtstr, &len ); // no string argument for '*'
 				else args = fmt( is, fmtstr, s, &len );
+
 				if ( check && len == rwd && ! eof( is ) ) {	// might not fit
 					char peek;
@@ -1096,5 +1115,4 @@
 		} // if
 		if ( args == 1 && eof( is ) ) {					// data but scan ended at EOF
-			// fprintf( stderr, "clear\n" );
 			clear( is );								// => reset EOF => detect again on next read
 		} // if
Index: libcfa/src/iostream.hfa
===================================================================
--- libcfa/src/iostream.hfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ libcfa/src/iostream.hfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Jan 28 11:56:29 2024
-// Update Count     : 733
+// Last Modified On : Tue Feb  6 18:35:54 2024
+// Update Count     : 743
 //
 
@@ -370,6 +370,7 @@
 // *********************************** exceptions ***********************************
 
-ExceptionDecl( cstring_length );
-ExceptionDecl( missing_data );
+ExceptionDecl( missing_data );							// read finds no appropriate data
+ExceptionDecl( cstring_length );						// character string size exceeded
+ExceptionDecl( data_range );							// value too large for numerical type
 
 // *********************************** manipulators ***********************************
@@ -406,7 +407,11 @@
 	char * s;
 	inline _Istream_str_base;
-}; // _Istream_Cstr
+}; // _Istream_Cwidth
 
 // Restrict nesting of input manipulators to those combinations that make sense.
+
+struct _Istream_Cquoted {
+	_Istream_Cwidth cstr;
+}; // _Istream_Cquoted
 
 struct _Istream_Cstr {
@@ -414,17 +419,16 @@
 }; // _Istream_Cstr
 
-struct _Istream_Cquoted {
-	_Istream_Cwidth cstr;
-}; // _Istream_Cquoted
-
 static inline {
 	// width must include room for null terminator, (gcc) scanf does not allow a 0 width => wd > 1 (1 char and null) and rd > 0 (1 char);
 	_Istream_Cwidth wdi( unsigned int wd, char s[] ) {
-		if ( wd <= 1 ) throw (cstring_length){ &cstring_length_vt }; // minimum 1 character and null terminator
+		if ( wd <= 1 ) throwResume ExceptionInst( cstring_length ); // minimum 1 character and null terminator
 		return (_Istream_Cwidth)@{ .s : s, { {.scanset : 0p}, .wd : wd, {.all : 0} } };
 	}
 	_Istream_Cwidth wdi( unsigned int wd, unsigned int rwd, char s[] ) {
-		if ( wd <= 1 || wd <= rwd ) throw (cstring_length){ &cstring_length_vt }; // minimum 1 character, null terminator, plus subset
+		if ( wd <= 1 || wd <= rwd ) throwResume ExceptionInst( cstring_length ); // minimum 1 character, null terminator, plus subset
 		return (_Istream_Cwidth)@{ .s : s, { {.scanset : 0p}, .wd : rwd, {.flags.rwd : true} } };
+	}
+	_Istream_Cstr & getline( _Istream_Cwidth & f, const char delimiter = '\n' ) {
+		f.delimiters[0] = delimiter; f.delimiters[1] = '\0'; f.flags.delimiter = true; return (_Istream_Cstr &)f;
 	}
 	_Istream_Cquoted quoted( char & ch, const char Ldelimiter = '\'', const char Rdelimiter = '\0' ) {
@@ -435,10 +439,7 @@
 		return (_Istream_Cquoted &)f;
 	}
-	_Istream_Cstr & getline( _Istream_Cwidth & f, const char delimiter = '\n' ) {
-		f.delimiters[0] = delimiter; f.delimiters[1] = '\0'; f.flags.delimiter = true; return (_Istream_Cstr &)f;
-	}
 	_Istream_Cstr & incl( const char scanset[], _Istream_Cwidth & f ) { f.scanset = scanset; f.flags.inex = false; return (_Istream_Cstr &)f; }
 	_Istream_Cstr & excl( const char scanset[], _Istream_Cwidth & f ) { f.scanset = scanset; f.flags.inex = true; return (_Istream_Cstr &)f; }
-	_Istream_Cstr ignore( const char s[] ) { return (_Istream_Cwidth)@{ .s : (char *)s, { {.scanset : 0p}, .wd : -1, {.flags.ignore : true} } }; }
+	_Istream_Cstr ignore( const char s[] ) { return (_Istream_Cstr)@{ { .s : (char *)s, { {.scanset : 0p}, .wd : -1, {.flags.ignore : true} } } }; }
 	_Istream_Cstr & ignore( _Istream_Cwidth & f ) { f.flags.ignore = true; return (_Istream_Cstr &)f; }
 	_Istream_Cquoted & ignore( _Istream_Cquoted & f ) { f.cstr.flags.ignore = true; return (_Istream_Cquoted &)f; }
@@ -450,7 +451,5 @@
 	istype & ?|?( istype & is, _Istream_Cquoted f );
 	istype & ?|?( istype & is, _Istream_Cstr f );
-	static inline {
-		istype & ?|?( istype & is, _Istream_Cwidth f ) { return is | *(_Istream_Cstr *)&f; }
-	} // distribution
+	static inline istype & ?|?( istype & is, _Istream_Cwidth f ) { return is | *(_Istream_Cstr *)&f; }
 } // distribution
 
Index: src/AST/Attribute.hpp
===================================================================
--- src/AST/Attribute.hpp	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/AST/Attribute.hpp	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Fri May 10 10:30:00 2019
-// Last Modified By : Aaron B. Moss
+// Last Modified By : Peter A. Buhr
 // Created On       : Fri May 10 10:30:00 2019
-// Update Count     : 1
+// Update Count     : 2
 //
 
@@ -34,5 +34,5 @@
 
 	Attribute( const std::string & name = "", std::vector<ptr<Expr>> && params = {})
-	: name( name ), params( params ) {}
+		: name( name ), params( params ) {}
 	virtual ~Attribute() = default;
 
Index: src/GenPoly/Box.cpp
===================================================================
--- src/GenPoly/Box.cpp	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/GenPoly/Box.cpp	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -366,6 +366,7 @@
 
 	/// Passes extra layout arguments for sized polymorphic type parameters.
-	ast::vector<ast::Expr>::iterator passTypeVars(
+	void passTypeVars(
 		ast::ApplicationExpr * expr,
+		ast::vector<ast::Expr> & extraArgs,
 		ast::FunctionType const * funcType );
 	/// Wraps a function application with a new temporary for the
@@ -387,6 +388,6 @@
 	/// parameter list. arg should point into expr's argument list.
 	void boxParams(
-		ast::ApplicationExpr const * expr,
-		ast::vector<ast::Expr>::iterator arg,
+		ast::ApplicationExpr * expr,
+		ast::Type const * polyRetType,
 		ast::FunctionType const * function,
 		const TypeVarMap & typeVars );
@@ -395,5 +396,5 @@
 	void addInferredParams(
 		ast::ApplicationExpr * expr,
-		ast::vector<ast::Expr>::iterator arg,
+		ast::vector<ast::Expr> & extraArgs,
 		ast::FunctionType const * functionType,
 		const TypeVarMap & typeVars );
@@ -636,8 +637,4 @@
 	ast::Expr const * ret = expr;
 
-	// TODO: This entire section should probably be refactored to do less
-	// pushing to the front/middle of a vector.
-	ptrdiff_t initArgCount = mutExpr->args.size();
-
 	TypeVarMap exprTypeVars;
 	makeTypeVarMap( function, exprTypeVars );
@@ -662,13 +659,10 @@
 	}
 
-	assert( typeSubs );
-	ast::vector<ast::Expr>::iterator argIt =
-		passTypeVars( mutExpr, function );
-	addInferredParams( mutExpr, argIt, function, exprTypeVars );
-
-	argIt = mutExpr->args.begin();
-	std::advance( argIt, ( mutExpr->args.size() - initArgCount ) );
-
-	boxParams( mutExpr, argIt, function, exprTypeVars );
+	ast::vector<ast::Expr> prependArgs;
+	passTypeVars( mutExpr, prependArgs, function );
+	addInferredParams( mutExpr, prependArgs, function, exprTypeVars );
+
+	boxParams( mutExpr, dynRetType, function, exprTypeVars );
+	spliceBegin( mutExpr->args, prependArgs );
 	passAdapters( mutExpr, function, exprTypeVars );
 
@@ -766,9 +760,9 @@
 }
 
-ast::vector<ast::Expr>::iterator CallAdapter::passTypeVars(
+void CallAdapter::passTypeVars(
 		ast::ApplicationExpr * expr,
+		ast::vector<ast::Expr> & extraArgs,
 		ast::FunctionType const * function ) {
 	assert( typeSubs );
-	ast::vector<ast::Expr>::iterator arg = expr->args.begin();
 	// Pass size/align for type variables.
 	for ( ast::ptr<ast::TypeInstType> const & typeVar : function->forall ) {
@@ -780,12 +774,9 @@
 						   toString( typeSubs ).c_str(), typeVar->typeString().c_str() );
 		}
-		arg = expr->args.insert( arg,
+		extraArgs.emplace_back(
 			new ast::SizeofExpr( expr->location, ast::deepCopy( concrete ) ) );
-		arg++;
-		arg = expr->args.insert( arg,
+		extraArgs.emplace_back(
 			new ast::AlignofExpr( expr->location, ast::deepCopy( concrete ) ) );
-		arg++;
-	}
-	return arg;
+	}
 }
 
@@ -913,8 +904,12 @@
 
 void CallAdapter::boxParams(
-		ast::ApplicationExpr const * expr,
-		ast::vector<ast::Expr>::iterator arg,
+		ast::ApplicationExpr * expr,
+		ast::Type const * polyRetType,
 		ast::FunctionType const * function,
 		const TypeVarMap & typeVars ) {
+	// Start at the beginning, but the return argument may have been added.
+	auto arg = expr->args.begin();
+	if ( polyRetType ) ++arg;
+
 	for ( auto param : function->params ) {
 		assertf( arg != expr->args.end(),
@@ -928,8 +923,7 @@
 void CallAdapter::addInferredParams(
 		ast::ApplicationExpr * expr,
-		ast::vector<ast::Expr>::iterator arg,
+		ast::vector<ast::Expr> & extraArgs,
 		ast::FunctionType const * functionType,
 		TypeVarMap const & typeVars ) {
-	ast::vector<ast::Expr>::iterator cur = arg;
 	for ( auto assertion : functionType->assertions ) {
 		auto inferParam = expr->inferred.inferParams().find(
@@ -940,6 +934,5 @@
 		ast::ptr<ast::Expr> newExpr = ast::deepCopy( inferParam->second.expr );
 		boxParam( newExpr, assertion->result, typeVars );
-		cur = expr->args.insert( cur, newExpr.release() );
-		++cur;
+		extraArgs.emplace_back( newExpr.release() );
 	}
 }
@@ -1116,9 +1109,6 @@
 	);
 
-	for ( auto group : group_iterate( realType->assertions,
-			adapterType->assertions, adaptee->assertions ) ) {
-		auto assertArg = std::get<0>( group );
-		auto assertParam = std::get<1>( group );
-		auto assertReal = std::get<2>( group );
+	for ( auto const & [assertArg, assertParam, assertReal] : group_iterate(
+			realType->assertions, adapterType->assertions, adaptee->assertions ) ) {
 		adapteeApp->args.push_back( makeAdapterArg(
 			assertParam->var, assertArg->var->get_type(),
@@ -1977,7 +1967,6 @@
 	bool hasDynamicLayout = false;
 
-	for ( auto pair : group_iterate( baseParams, typeParams ) ) {
-		auto baseParam = std::get<0>( pair );
-		auto typeParam = std::get<1>( pair );
+	for ( auto const & [baseParam, typeParam] : group_iterate(
+			baseParams, typeParams ) ) {
 		if ( !baseParam->isComplete() ) continue;
 		ast::TypeExpr const * typeExpr = typeParam.as<ast::TypeExpr>();
Index: src/InitTweak/FixInit.cpp
===================================================================
--- src/InitTweak/FixInit.cpp	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/InitTweak/FixInit.cpp	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -1134,5 +1134,5 @@
 			ast::Expr * thisExpr = new ast::CastExpr(funcDecl->location, new ast::VariableExpr(funcDecl->location, thisParam ), thisParam->get_type()->stripReferences());
 			ast::Expr * memberDest = new ast::MemberExpr(funcDecl->location, field, thisExpr );
-			ast::ptr<ast::Stmt> callStmt = SymTab::genImplicitCall( srcParam, memberDest, loc, function->name, field, static_cast<SymTab::LoopDirection>(isCtor) );
+			const ast::Stmt * callStmt = SymTab::genImplicitCall( srcParam, memberDest, loc, function->name, field, static_cast<SymTab::LoopDirection>(isCtor) );
 
 			if ( callStmt ) {
Index: src/InitTweak/GenInit.cc
===================================================================
--- src/InitTweak/GenInit.cc	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/InitTweak/GenInit.cc	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -239,5 +239,5 @@
 					if ( varExpr->var == retVal ) return stmt;
 				}
-				ast::ptr<ast::Stmt> ctorStmt = genCtorDtor(
+				const ast::Stmt * ctorStmt = genCtorDtor(
 					retVal->location, "?{}", retVal, stmt->expr );
 				assertf( ctorStmt,
@@ -327,5 +327,5 @@
 void ManagedTypes::endScope() { managedTypes.endScope(); }
 
-ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg) {
+const ast::Stmt * genCtorDtor( const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg ) {
 	assertf(objDecl, "genCtorDtor passed null objDecl");
 	InitExpander srcParam(arg);
Index: src/InitTweak/GenInit.h
===================================================================
--- src/InitTweak/GenInit.h	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/InitTweak/GenInit.h	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -33,5 +33,5 @@
 
 /// generates a single ctor/dtor statement using objDecl as the 'this' parameter and arg as the optional argument
-ast::ptr<ast::Stmt> genCtorDtor (const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr);
+const ast::Stmt * genCtorDtor( const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * objDecl, const ast::Expr * arg = nullptr );
 
 /// creates an appropriate ConstructorInit node which contains a constructor, destructor, and C-initializer
Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/Parser/DeclarationNode.cc	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 12:34:05 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Dec 14 19:05:17 2023
-// Update Count     : 1407
+// Last Modified On : Fri Feb 23 18:25:57 2024
+// Update Count     : 1533
 //
 
@@ -159,7 +159,8 @@
 
 	if ( ! attributes.empty() ) {
-		os << string( indent + 2, ' ' ) << "with attributes " << endl;
+		os << string( indent + 2, ' ' ) << "with attributes" << endl;
 		for ( ast::ptr<ast::Attribute> const & attr : reverseIterate( attributes ) ) {
-			os << string( indent + 4, ' ' ) << attr->name.c_str() << endl;
+			os << string( indent + 4, ' ' );
+			ast::print( os, attr, indent + 2 );
 		} // for
 	} // if
@@ -537,14 +538,16 @@
 } // DeclarationNode::checkSpecifiers
 
-DeclarationNode * DeclarationNode::copySpecifiers( DeclarationNode * q ) {
+DeclarationNode * DeclarationNode::copySpecifiers( DeclarationNode * q, bool copyattr ) {
 	funcSpecs |= q->funcSpecs;
 	storageClasses |= q->storageClasses;
 
-	std::vector<ast::ptr<ast::Attribute>> tmp;
-	tmp.reserve( q->attributes.size() );
-	for ( auto const & attr : q->attributes ) {
-		tmp.emplace_back( ast::shallowCopy( attr.get() ) );
-	}
-	spliceBegin( attributes, tmp );
+	if ( copyattr ) {
+		std::vector<ast::ptr<ast::Attribute>> tmp;
+		tmp.reserve( q->attributes.size() );
+		for ( auto const & attr : q->attributes ) {
+			tmp.emplace_back( ast::shallowCopy( attr.get() ) );
+		} // for
+		spliceBegin( attributes, tmp );
+	} // if
 
 	return this;
@@ -681,13 +684,15 @@
 }
 
-DeclarationNode * DeclarationNode::addType( DeclarationNode * o ) {
+DeclarationNode * DeclarationNode::addType( DeclarationNode * o, bool copyattr ) {
 	if ( o ) {
 		checkSpecifiers( o );
-		copySpecifiers( 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;
+					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;
@@ -700,5 +705,5 @@
 					type = o->type;
 				} // if
-				o->type = nullptr;
+				o->type = nullptr;						// change ownership
 			} else {
 				addTypeToType( o->type, type );
@@ -953,8 +958,8 @@
 }
 
-DeclarationNode * DeclarationNode::cloneBaseType( DeclarationNode * o ) {
+DeclarationNode * DeclarationNode::cloneBaseType( DeclarationNode * o, bool copyattr ) {
 	if ( ! o ) return nullptr;
 
-	o->copySpecifiers( this );
+	o->copySpecifiers( this, copyattr );
 	if ( type ) {
 		TypeData * srcType = type;
@@ -999,4 +1004,7 @@
 			DeclarationNode * newnode = new DeclarationNode;
 			newnode->type = ret;
+			if ( ret->kind == TypeData::Aggregate ) {
+				newnode->attributes.swap( ret->aggregate.attributes );
+			} // if 
 			return newnode;
 		} // if
@@ -1110,8 +1118,8 @@
 					if ( extr->type->kind == TypeData::Aggregate ) {
 						// typedef struct { int A } B is the only case?
-						extracted_named = !extr->type->aggregate.anon;
+						extracted_named = ! extr->type->aggregate.anon;
 					} else if ( extr->type->kind == TypeData::Enum ) {
 						// typedef enum { A } B is the only case?
-						extracted_named = !extr->type->enumeration.anon;
+						extracted_named = ! extr->type->enumeration.anon;
 					} else {
 						extracted_named = true;
Index: src/Parser/DeclarationNode.h
===================================================================
--- src/Parser/DeclarationNode.h	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/Parser/DeclarationNode.h	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -9,7 +9,7 @@
 // Author           : Andrew Beach
 // Created On       : Wed Apr  5 11:38:00 2023
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Apr  5 11:55:00 2023
-// Update Count     : 0
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Feb 17 09:24:12 2024
+// Update Count     : 4
 //
 
@@ -83,6 +83,6 @@
 	void checkQualifiers( const TypeData *, const TypeData * );
 	void checkSpecifiers( DeclarationNode * );
-	DeclarationNode * copySpecifiers( DeclarationNode * );
-	DeclarationNode * addType( DeclarationNode * );
+	DeclarationNode * copySpecifiers( DeclarationNode *, bool = true );
+	DeclarationNode * addType( DeclarationNode *, bool = true );
 	DeclarationNode * addTypedef();
 	DeclarationNode * addEnumBase( DeclarationNode * );
@@ -106,5 +106,5 @@
 
 	DeclarationNode * cloneType( std::string * newName );
-	DeclarationNode * cloneBaseType( DeclarationNode * newdecl );
+	DeclarationNode * cloneBaseType( DeclarationNode * newdecl, bool = true );
 
 	DeclarationNode * appendList( DeclarationNode * node ) {
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/Parser/TypeData.cc	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 15:12:51 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Dec 14 18:59:12 2023
-// Update Count     : 684
+// Last Modified On : Fri Feb 23 08:58:30 2024
+// Update Count     : 734
 //
 
@@ -20,8 +20,10 @@
 
 #include "AST/Decl.hpp"            // for AggregateDecl, ObjectDecl, TypeDe...
+#include "AST/Attribute.hpp"       // for Attribute
 #include "AST/Init.hpp"            // for SingleInit, ListInit
 #include "AST/Print.hpp"           // for print
 #include "Common/SemanticError.h"  // for SemanticError
 #include "Common/utility.h"        // for splice, spliceBegin
+#include "Common/Iterate.hpp"      // for reverseIterate
 #include "Parser/ExpressionNode.h" // for ExpressionNode
 #include "Parser/StatementNode.h"  // for StatementNode
@@ -199,11 +201,12 @@
 		newtype->aggregate.kind = aggregate.kind;
 		newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr;
+		newtype->aggregate.parent = aggregate.parent ? new string( *aggregate.parent ) : nullptr;
 		newtype->aggregate.params = maybeCopy( aggregate.params );
 		newtype->aggregate.actuals = maybeCopy( aggregate.actuals );
 		newtype->aggregate.fields = maybeCopy( aggregate.fields );
+		newtype->aggregate.attributes = aggregate.attributes;
 		newtype->aggregate.body = aggregate.body;
 		newtype->aggregate.anon = aggregate.anon;
 		newtype->aggregate.tagged = aggregate.tagged;
-		newtype->aggregate.parent = aggregate.parent ? new string( *aggregate.parent ) : nullptr;
 		break;
 	case AggregateInst:
@@ -336,5 +339,12 @@
 		} // if
 		if ( aggregate.body ) {
-			os << string( indent + 2, ' ' ) << " with body" << endl;
+			os << string( indent + 2, ' ' ) << "with body" << endl;
+		} // if
+		if ( ! aggregate.attributes.empty() ) {
+			os << string( indent + 2, ' ' ) << "with attributes" << endl;
+			for ( ast::ptr<ast::Attribute> const & attr : reverseIterate( aggregate.attributes ) ) {
+				os << string( indent + 4, ' ' );
+				ast::print( os, attr, indent + 2 );
+			} // for
 		} // if
 		break;
@@ -358,5 +368,5 @@
 		} // if
 		if ( enumeration.body ) {
-			os << string( indent + 2, ' ' ) << " with body" << endl;
+			os << string( indent + 2, ' ' ) << "with body" << endl;
 		} // if
 		if ( base ) {
@@ -1088,28 +1098,28 @@
 
 ast::BaseInstType * buildComAggInst(
-		const TypeData * type,
+		const TypeData * td,
 		std::vector<ast::ptr<ast::Attribute>> && attributes,
 		ast::Linkage::Spec linkage ) {
-	switch ( type->kind ) {
+	switch ( td->kind ) {
 	case TypeData::Enum:
-		if ( type->enumeration.body ) {
+		if ( td->enumeration.body ) {
 			ast::EnumDecl * typedecl =
-				buildEnum( type, std::move( attributes ), linkage );
+				buildEnum( td, std::move( attributes ), linkage );
 			return new ast::EnumInstType(
 				typedecl,
-				buildQualifiers( type )
+				buildQualifiers( td )
 			);
 		} else {
 			return new ast::EnumInstType(
-				*type->enumeration.name,
-				buildQualifiers( type )
+				*td->enumeration.name,
+				buildQualifiers( td )
 			);
 		} // if
 		break;
 	case TypeData::Aggregate:
-		if ( type->aggregate.body ) {
+		if ( td->aggregate.body ) {
 			ast::AggregateDecl * typedecl =
-				buildAggregate( type, std::move( attributes ), linkage );
-			switch ( type->aggregate.kind ) {
+				buildAggregate( td, std::move( attributes ), linkage );
+			switch ( td->aggregate.kind ) {
 			case ast::AggregateDecl::Struct:
 			case ast::AggregateDecl::Coroutine:
@@ -1118,10 +1128,10 @@
 				return new ast::StructInstType(
 					strict_dynamic_cast<ast::StructDecl *>( typedecl ),
-					buildQualifiers( type )
+					buildQualifiers( td )
 				);
 			case ast::AggregateDecl::Union:
 				return new ast::UnionInstType(
 					strict_dynamic_cast<ast::UnionDecl *>( typedecl ),
-					buildQualifiers( type )
+					buildQualifiers( td )
 				);
 			case ast::AggregateDecl::Trait:
@@ -1132,5 +1142,5 @@
 			} // switch
 		} else {
-			switch ( type->aggregate.kind ) {
+			switch ( td->aggregate.kind ) {
 			case ast::AggregateDecl::Struct:
 			case ast::AggregateDecl::Coroutine:
@@ -1138,16 +1148,16 @@
 			case ast::AggregateDecl::Thread:
 				return new ast::StructInstType(
-					*type->aggregate.name,
-					buildQualifiers( type )
+					*td->aggregate.name,
+					buildQualifiers( td )
 				);
 			case ast::AggregateDecl::Union:
 				return new ast::UnionInstType(
-					*type->aggregate.name,
-					buildQualifiers( type )
+					*td->aggregate.name,
+					buildQualifiers( td )
 				);
 			case ast::AggregateDecl::Trait:
 				return new ast::TraitInstType(
-					*type->aggregate.name,
-					buildQualifiers( type )
+					*td->aggregate.name,
+					buildQualifiers( td )
 				);
 			default:
Index: src/Parser/TypeData.h
===================================================================
--- src/Parser/TypeData.h	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/Parser/TypeData.h	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -9,7 +9,7 @@
 // Author           : Peter A. Buhr
 // Created On       : Sat May 16 15:18:36 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Mar  1 10:44:00 2023
-// Update Count     : 206
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Thu Feb 22 16:30:31 2024
+// Update Count     : 210
 //
 
@@ -30,11 +30,12 @@
 		ast::AggregateDecl::Aggregate kind;
 		const std::string * name = nullptr;
+		const std::string * parent = nullptr;
 		DeclarationNode * params = nullptr;
 		ExpressionNode * actuals = nullptr;				// holds actual parameters later applied to AggInst
 		DeclarationNode * fields = nullptr;
+		std::vector<ast::ptr<ast::Attribute>> attributes;
 		bool body;
 		bool anon;
 		bool tagged;
-		const std::string * parent = nullptr;
 	};
 
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/Parser/parser.yy	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Nov 26 13:18:06 2023
-// Update Count     : 6398
+// Last Modified On : Fri Feb 23 18:25:46 2024
+// Update Count     : 6484
 //
 
@@ -102,16 +102,36 @@
 
 DeclarationNode * distAttr( DeclarationNode * typeSpec, DeclarationNode * declList ) {
-	// distribute declaration_specifier across all declared variables, e.g., static, const, but not __attribute__.
+	// Distribute type specifier across all declared variables, e.g., static, const, __attribute__.
 	assert( declList );
-	// printf( "distAttr1 typeSpec %p\n", typeSpec ); typeSpec->print( std::cout );
-	DeclarationNode * cl = (new DeclarationNode)->addType( typeSpec );
-	// printf( "distAttr2 cl %p\n", cl ); cl->type->print( std::cout );
-	// cl->type->aggregate.name = cl->type->aggInst.aggregate->aggregate.name;
-
+
+	// Do not distribute attributes for aggregates because the attributes surrounding the aggregate belong it not the
+	// variables in the declaration list, e.g.,
+	//
+	//   struct __attribute__(( aligned(128) )) S { ...
+	//   } v1 __attribute__(( aligned(64) )), v2 __attribute__(( aligned(32) )), v3;
+	//   struct S v4;
+	//
+	// v1 => 64, v2 =>32, v3 => 128, v2 => 128
+	//
+	// Anonymous aggregates are a special case because there is no aggregate to bind the attribute to; hence it floats
+	// to the declaration list.
+	//
+	//   struct __attribute__(( aligned(128) )) /*anonymous */ { ... } v1;
+	//
+	// v1 => 128
+
+	bool copyattr = ! (typeSpec->type && typeSpec->type->kind == TypeData::Aggregate && ! typeSpec->type->aggregate.anon );
+
+	// addType copies the type information for the aggregate instances from typeSpec into cl's aggInst.aggregate.
+	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() ) ) {
-		cl->cloneBaseType( cur );
+		cl->cloneBaseType( cur, copyattr );				// cur is modified
 	} // for
-	declList->addType( cl );
-	// printf( "distAttr3 declList %p\n", declList ); declList->print( std::cout, 0 );
+
+	// Add first variable in declaration list with hidden type information in aggInst.aggregate, which is used by
+	// extractType to recover the type for the aggregate instances.
+	declList->addType( cl, copyattr );					// cl IS DELETED!!!
 	return declList;
 } // distAttr
@@ -192,8 +212,7 @@
 		fieldList = DeclarationNode::newName( nullptr );
 	} // if
-//	return distAttr( typeSpec, fieldList );				// mark all fields in list
 
 	// printf( "fieldDecl3 typeSpec %p\n", typeSpec ); typeSpec->print( std::cout, 0 );
-	DeclarationNode * temp = distAttr( typeSpec, fieldList );				// mark all fields in list
+	DeclarationNode * temp = distAttr( typeSpec, fieldList ); // mark all fields in list
 	// printf( "fieldDecl4 temp %p\n", temp ); temp->print( std::cout, 0 );
 	return temp;
@@ -761,6 +780,29 @@
 	| string_literal '`' identifier						// CFA, postfix call
 		{ $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
+
+		// SKULLDUGGERY: The typedef table used for parsing does not store fields in structures. To parse a qualified
+		// name, it is assumed all name-tokens after the first are identifiers, regardless of how the lexer identifies
+    	// them. For example:
+		//   
+		//   struct S;
+		//   forall(T) struct T;
+		//   union U;
+		//   enum E { S, T, E };
+		//   struct Z { int S, T, Z, E, U; };
+		//   void fred () {
+		//       Z z;
+		//       z.S;  // lexer returns S is TYPEDEFname
+		//       z.T;  // lexer returns T is TYPEGENname
+		//       z.Z;  // lexer returns Z is TYPEDEFname
+		//       z.U;  // lexer returns U is TYPEDEFname
+		//       z.E;  // lexer returns E is TYPEDEFname
+		//   }
 	| postfix_expression '.' identifier
 		{ $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
+	| postfix_expression '.' TYPEDEFname				// CFA, SKULLDUGGERY
+		{ $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
+	| postfix_expression '.' TYPEGENname				// CFA, SKULLDUGGERY
+		{ $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
+
 	| postfix_expression '.' INTEGERconstant			// CFA, tuple index
 		{ $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_constantInteger( yylloc, *$3 ) ) ); }
@@ -1039,7 +1081,6 @@
 	| logical_OR_expression '?' comma_expression ':' conditional_expression
 		{ $$ = new ExpressionNode( build_cond( yylloc, $1, $3, $5 ) ); }
-		// FIX ME: computes $1 twice
 	| logical_OR_expression '?' /* empty */ ':' conditional_expression // GCC, omitted first operand
-		{ $$ = new ExpressionNode( build_cond( yylloc, $1, $1->clone(), $4 ) ); }
+		{ $$ = new ExpressionNode( build_cond( yylloc, $1, nullptr, $4 ) ); }
 	;
 
@@ -1856,6 +1897,5 @@
 declaration_list:
 	declaration
-	| declaration_list declaration
-		{ $$ = $1->appendList( $2 ); }
+	| declaration_list declaration		{ $$ = $1->appendList( $2 ); }
 	;
 
@@ -1890,10 +1930,4 @@
 declaration:											// old & new style declarations
 	c_declaration ';'
-		{
-			// printf( "C_DECLARATION1 %p %s\n", $$, $$->name ? $$->name->c_str() : "(nil)" );
-			// for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
-			//   printf( "\tattr %s\n", attr->name.c_str() );
-			// } // for
-		}
 	| cfa_declaration ';'								// CFA
 	| static_assert										// C11
@@ -2348,10 +2382,4 @@
 sue_declaration_specifier:								// struct, union, enum + storage class + type specifier
 	sue_type_specifier
-		{
-			// printf( "sue_declaration_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
-			// for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
-			//   printf( "\tattr %s\n", attr->name.c_str() );
-			// } // for
-		}
 	| declaration_qualifier_list sue_type_specifier
 		{ $$ = $2->addQualifiers( $1 ); }
@@ -2364,10 +2392,4 @@
 sue_type_specifier:										// struct, union, enum + type specifier
 	elaborated_type
-		{
-			// printf( "sue_type_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
-			// for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
-			//   printf( "\tattr %s\n", attr->name.c_str() );
-			// } // for
-		}
 	| type_qualifier_list
 		{ if ( $1->type != nullptr && $1->type->forall ) forall = true; } // remember generic type
@@ -2442,10 +2464,4 @@
 elaborated_type:										// struct, union, enum
 	aggregate_type
-		{
-			// printf( "elaborated_type %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );
-			// for ( Attribute * attr: reverseIterate( $$->attributes ) ) {
-			//   printf( "\tattr %s\n", attr->name.c_str() );
-			// } // for
-		}
 	| enum_type
 	;
@@ -2679,5 +2695,5 @@
 		{ $$ = DeclarationNode::newEnum( nullptr, $4, true, false )->addQualifiers( $2 ); }
 	| ENUM attribute_list_opt '!' '{' enumerator_list comma_opt '}'	// invalid syntax rule
-		{ SemanticError( yylloc, "syntax error, hiding '!' the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
+		{ SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
 	| ENUM attribute_list_opt identifier
 		{ typedefTable.makeTypedef( *$3, "enum_type 1" ); }
@@ -2694,5 +2710,5 @@
 		}
 	| ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '!' '{' enumerator_list comma_opt '}' // unqualified type name
-		{ SemanticError( yylloc, "syntax error, hiding '!' the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
+		{ SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
 	| ENUM '(' ')' attribute_list_opt '{' enumerator_list comma_opt '}'
 		{
@@ -2700,5 +2716,5 @@
 		}
 	| ENUM '(' ')' attribute_list_opt '!' '{' enumerator_list comma_opt '}'	// invalid syntax rule
-		{ SemanticError( yylloc, "syntax error, hiding '!' the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
+		{ SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
 	| ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
 		{
@@ -3177,5 +3193,6 @@
 			// unit, which is a dubious task, especially because C uses name rather than structural typing; hence it is
 			// disallowed at the moment.
-			if ( $1->linkage == ast::Linkage::Cforall && ! $1->storageClasses.is_static && $1->type && $1->type->kind == TypeData::AggregateInst ) {
+			if ( $1->linkage == ast::Linkage::Cforall && ! $1->storageClasses.is_static &&
+				 $1->type && $1->type->kind == TypeData::AggregateInst ) {
 				if ( $1->type->aggInst.aggregate->kind == TypeData::Enum && $1->type->aggInst.aggregate->enumeration.anon ) {
 					SemanticError( yylloc, "extern anonymous enumeration is currently unimplemented." ); $$ = nullptr;
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -1018,5 +1018,5 @@
 					}
 
-					if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);						
+					if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);
 					else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
 				}
@@ -1283,5 +1283,5 @@
 						restructureCast( cand->expr, toType, castExpr->isGenerated ),
 						copy( cand->env ), std::move( open ), std::move( need ), cand->cost + thisCost);
-					// currently assertions are always resolved immediately so this should have no effect. 
+					// currently assertions are always resolved immediately so this should have no effect.
 					// if this somehow changes in the future (e.g. delayed by indeterminate return type)
 					// we may need to revisit the logic.
@@ -1618,13 +1618,16 @@
 	void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) {
 		// candidates for condition
+		ast::ptr<ast::Expr> arg1 = notZeroExpr( conditionalExpr->arg1 );
 		CandidateFinder finder1( context, tenv );
-		ast::ptr<ast::Expr> arg1 = notZeroExpr( conditionalExpr->arg1 );
 		finder1.find( arg1, ResolveMode::withAdjustment() );
 		if ( finder1.candidates.empty() ) return;
 
 		// candidates for true result
+		// FIX ME: resolves and runs arg1 twice when arg2 is missing.
+		ast::Expr const * arg2 = conditionalExpr->arg2;
+		arg2 = arg2 ? arg2 : conditionalExpr->arg1.get();
 		CandidateFinder finder2( context, tenv );
 		finder2.allowVoid = true;
-		finder2.find( conditionalExpr->arg2, ResolveMode::withAdjustment() );
+		finder2.find( arg2, ResolveMode::withAdjustment() );
 		if ( finder2.candidates.empty() ) return;
 
@@ -1897,8 +1900,8 @@
 					CandidateRef newCand =
 						std::make_shared<Candidate>(
-							newExpr, copy( tenv ), ast::OpenVarSet{}, 
+							newExpr, copy( tenv ), ast::OpenVarSet{},
 							ast::AssertionSet{}, Cost::zero, cost
 						);
-					
+
 					if (newCand->expr->env) {
 						newCand->env.add(*newCand->expr->env);
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -35,44 +35,43 @@
 
 struct ResolveTypeof : public ast::WithShortCircuiting {
-    const ResolveContext & context;
+	const ResolveContext & context;
 
-		ResolveTypeof( const ResolveContext & context ) :
-			context( context ) {}
+	ResolveTypeof( const ResolveContext & context ) : context( context ) {}
 
-		void previsit( const ast::TypeofType * ) { visit_children = false; }
+	void previsit( const ast::TypeofType * ) { visit_children = false; }
 
-        const ast::Type * postvisit( const ast::TypeofType * typeofType ) {
-        // pass on null expression
-            if ( ! typeofType->expr ) return typeofType;
+	const ast::Type * postvisit( const ast::TypeofType * typeofType ) {
+		// pass on null expression
+		if ( ! typeofType->expr ) return typeofType;
 
-            ast::ptr< ast::Type > newType;
-            if ( auto tyExpr = typeofType->expr.as< ast::TypeExpr >() ) {
-            // typeof wrapping type
-            newType = tyExpr->type;
-        } else {
-            // typeof wrapping expression
-            ast::TypeEnvironment dummy;
-            ast::ptr< ast::Expr > newExpr =
-                resolveInVoidContext( typeofType->expr, context, dummy );
-            assert( newExpr->result && ! newExpr->result->isVoid() );
-            newType = newExpr->result;
-        }
+		ast::ptr< ast::Type > newType;
+		if ( auto tyExpr = typeofType->expr.as< ast::TypeExpr >() ) {
+			// typeof wrapping type
+			newType = tyExpr->type;
+		} else {
+			// typeof wrapping expression
+			ast::TypeEnvironment dummy;
+			ast::ptr< ast::Expr > newExpr =
+				resolveInVoidContext( typeofType->expr, context, dummy );
+			assert( newExpr->result && ! newExpr->result->isVoid() );
+			newType = newExpr->result;
+		}
 
-        // clear qualifiers for base, combine with typeoftype quals regardless
-        if ( typeofType->kind == ast::TypeofType::Basetypeof ) {
-            // replace basetypeof(<enum>) by int
-				if ( newType.as< ast::EnumInstType >() ) {
-					newType = new ast::BasicType{
-						ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) };
-            }
-				reset_qualifiers(
-					newType,
-					( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers );
-        } else {
-				add_qualifiers( newType, typeofType->qualifiers );
-        }
+		// clear qualifiers for base, combine with typeoftype quals regardless
+		if ( typeofType->kind == ast::TypeofType::Basetypeof ) {
+			// replace basetypeof(<enum>) by int
+			if ( newType.as< ast::EnumInstType >() ) {
+				newType = new ast::BasicType(
+					ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) );
+			}
+			reset_qualifiers(
+				newType,
+				( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers );
+		} else {
+			add_qualifiers( newType, typeofType->qualifiers );
+		}
 
-        return newType.release();
-    }
+		return newType.release();
+	}
 };
 
@@ -111,83 +110,75 @@
 
 const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & context ) {
-    if (decl->isTypeFixed) {
-        return decl;
-    }
+	if ( decl->isTypeFixed ) {
+		return decl;
+	}
 
-    auto mutDecl = mutate(decl);
-    fixObjectInit(decl, context);
-    {
-        auto resolvedType = resolveTypeof(decl->type, context);
-        resolvedType = fixArrayType(resolvedType, context);
-        mutDecl->type = resolvedType;
-    }
+	auto mutDecl = mutate(decl);
+	fixObjectInit(decl, context);
+	{
+		auto resolvedType = resolveTypeof(decl->type, context);
+		resolvedType = fixArrayType(resolvedType, context);
+		mutDecl->type = resolvedType;
+	}
 
-    // Do not mangle unnamed variables.
-    if (!mutDecl->name.empty()) {
-        mutDecl->mangleName = Mangle::mangle(mutDecl);
-    }
+	// Do not mangle unnamed variables.
+	if ( !mutDecl->name.empty() ) {
+		mutDecl->mangleName = Mangle::mangle(mutDecl);
+	}
 
-    mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID);
-    mutDecl->isTypeFixed = true;
-    return mutDecl;
+	mutDecl->type = renameTyVars(mutDecl->type, RenameMode::GEN_EXPR_ID);
+	mutDecl->isTypeFixed = true;
+	return mutDecl;
 }
 
-const ast::ObjectDecl *fixObjectInit(const ast::ObjectDecl *decl,
-                                     const ResolveContext &context) {
-    if (decl->isTypeFixed) {
-        return decl;
-    }
+const ast::ObjectDecl *fixObjectInit(
+		const ast::ObjectDecl *decl, const ResolveContext &context) {
+	if ( decl->isTypeFixed ) {
+		return decl;
+	}
 
-    auto mutDecl = mutate(decl);
+	if ( auto listInit = decl->init.as<ast::ListInit>() ) {
+		for ( size_t k = 0; k < listInit->designations.size(); k++ ) {
+			const ast::Designation *des = listInit->designations[k].get();
+			// Desination here
+			ast::Designation * newDesignation = new ast::Designation(des->location);
+			std::deque<ast::ptr<ast::Expr>> newDesignators;
 
-    if ( auto mutListInit = mutDecl->init.as<ast::ListInit>() ) {
-        // std::list<ast::Designation *> newDesignations;        
-
-        for ( size_t k = 0; k < mutListInit->designations.size(); k++ ) {
-            const ast::Designation *des = mutListInit->designations[k].get();
-            // Desination here
-            ast::Designation * newDesignation = new ast::Designation(des->location);
-            std::deque<ast::ptr<ast::Expr>> newDesignators;
-
-            for ( ast::ptr<ast::Expr> designator : des->designators ) {
-                // Stupid flag variable for development, to be removed
-                // bool mutated = false;
-                if ( const ast::NameExpr * designatorName = designator.as<ast::NameExpr>() ) {
-                    auto candidates = context.symtab.lookupId(designatorName->name);
-                    // Does not work for the overloading case currently
-                    // assert( candidates.size() == 1 );
-                    if ( candidates.size() != 1 ) return mutDecl;
-                    auto candidate = candidates.at(0);
-                    if ( const ast::EnumInstType * enumInst = dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type())) {
-                        // determine that is an enumInst, swap it with its const value
-                        assert( candidates.size() == 1 );
-                        const ast::EnumDecl * baseEnum = enumInst->base;
-                        // Need to iterate over all enum value to find the initializer to swap
-                        for ( size_t m = 0; m < baseEnum->members.size(); ++m ) {
-                            const ast::ObjectDecl * mem = baseEnum->members.at(m).as<const ast::ObjectDecl>();
-                            if ( baseEnum->members.at(m)->name == designatorName->name ) {
-                                assert(mem);
-                                newDesignators.push_back( ast::ConstantExpr::from_int(designator->location, m) );
-                                // mutated = true;
-                                break;
-                            }
-                        }
-                    } else {
-                        newDesignators.push_back( des->designators.at(0) );
-                    }
-                } else {
-                    newDesignators.push_back( des->designators.at(0) );
-                }
-            }            
-            
-            newDesignation->designators = newDesignators;
-            mutListInit = ast::mutate_field_index(mutListInit, &ast::ListInit::designations, k, newDesignation);
-            
-        }
-    }
-    return mutDecl;
+			for ( ast::ptr<ast::Expr> designator : des->designators ) {
+				// Stupid flag variable for development, to be removed
+				if ( const ast::NameExpr * designatorName = designator.as<ast::NameExpr>() ) {
+					auto candidates = context.symtab.lookupId(designatorName->name);
+					// Does not work for the overloading case currently
+					// assert( candidates.size() == 1 );
+					if ( candidates.size() != 1 ) return decl;
+					auto candidate = candidates.at(0);
+					if ( const ast::EnumInstType * enumInst = dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type())) {
+						// determine that is an enumInst, swap it with its const value
+						assert( candidates.size() == 1 );
+						const ast::EnumDecl * baseEnum = enumInst->base;
+						// Need to iterate over all enum value to find the initializer to swap
+						for ( size_t m = 0; m < baseEnum->members.size(); ++m ) {
+							const ast::ObjectDecl * mem = baseEnum->members.at(m).as<const ast::ObjectDecl>();
+							if ( baseEnum->members.at(m)->name == designatorName->name ) {
+								assert( mem );
+								newDesignators.push_back( ast::ConstantExpr::from_int(designator->location, m) );
+								break;
+							}
+						}
+					} else {
+						newDesignators.push_back( des->designators.at(0) );
+					}
+				} else {
+					newDesignators.push_back( des->designators.at(0) );
+				}
+			}
+			newDesignation->designators = newDesignators;
+			listInit = ast::mutate_field_index(listInit, &ast::ListInit::designations, k, newDesignation);
+		}
+	}
+	return decl;
 }
 
-}  // namespace ResolvExpr
+} // namespace ResolvExpr
 
 // Local Variables: //
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/ResolvExpr/Resolver.cc	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -50,1198 +50,1194 @@
 
 namespace ResolvExpr {
-	namespace {
-		/// Finds deleted expressions in an expression tree
-		struct DeleteFinder final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder> {
-			const ast::DeletedExpr * result = nullptr;
-
-			void previsit( const ast::DeletedExpr * expr ) {
-				if ( result ) { visit_children = false; }
-				else { result = expr; }
+
+namespace {
+	/// Finds deleted expressions in an expression tree
+	struct DeleteFinder final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder> {
+		const ast::DeletedExpr * result = nullptr;
+
+		void previsit( const ast::DeletedExpr * expr ) {
+			if ( result ) { visit_children = false; }
+			else { result = expr; }
+		}
+
+		void previsit( const ast::Expr * expr ) {
+			if ( result ) { visit_children = false; }
+			if (expr->inferred.hasParams()) {
+				for (auto & imp : expr->inferred.inferParams() ) {
+					imp.second.expr->accept(*visitor);
+				}
 			}
-
-			void previsit( const ast::Expr * expr ) {
-				if ( result ) { visit_children = false; }
-				if (expr->inferred.hasParams()) {
-					for (auto & imp : expr->inferred.inferParams() ) {
-						imp.second.expr->accept(*visitor);
+		}
+	};
+
+	struct ResolveDesignators final : public ast::WithShortCircuiting {
+		ResolveContext& context;
+		bool result = false;
+
+		ResolveDesignators( ResolveContext& _context ): context(_context) {};
+
+		void previsit( const ast::Node * ) {
+			// short circuit if we already know there are designations
+			if ( result ) visit_children = false;
+		}
+
+		void previsit( const ast::Designation * des ) {
+			if ( result ) visit_children = false;
+			else if ( ! des->designators.empty() ) {
+				if ( (des->designators.size() == 1) ) {
+					const ast::Expr * designator = des->designators.at(0);
+					if ( const ast::NameExpr * designatorName = dynamic_cast<const ast::NameExpr *>(designator) ) {
+						auto candidates = context.symtab.lookupId(designatorName->name);
+						for ( auto candidate : candidates ) {
+							if ( dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type()) ) {
+								result = true;
+								break;
+							}
+						}
+					}
+				}
+				visit_children = false;
+			}
+		}
+	};
+} // anonymous namespace
+
+/// Check if this expression is or includes a deleted expression
+const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
+	return ast::Pass<DeleteFinder>::read( expr );
+}
+
+namespace {
+	/// always-accept candidate filter
+	bool anyCandidate( const Candidate & ) { return true; }
+
+	/// Calls the CandidateFinder and finds the single best candidate
+	CandidateRef findUnfinishedKindExpression(
+		const ast::Expr * untyped, const ResolveContext & context, const std::string & kind,
+		std::function<bool(const Candidate &)> pred = anyCandidate, ResolveMode mode = {}
+	) {
+		if ( ! untyped ) return nullptr;
+
+		// xxx - this isn't thread-safe, but should work until we parallelize the resolver
+		static unsigned recursion_level = 0;
+
+		++recursion_level;
+		ast::TypeEnvironment env;
+		CandidateFinder finder( context, env );
+		finder.allowVoid = true;
+		finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
+		--recursion_level;
+
+		// produce a filtered list of candidates
+		CandidateList candidates;
+		for ( auto & cand : finder.candidates ) {
+			if ( pred( *cand ) ) { candidates.emplace_back( cand ); }
+		}
+
+		// produce invalid error if no candidates
+		if ( candidates.empty() ) {
+			SemanticError( untyped,
+				toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""),
+				"expression: ") );
+		}
+
+		// search for cheapest candidate
+		CandidateList winners;
+		bool seen_undeleted = false;
+		for ( CandidateRef & cand : candidates ) {
+			int c = winners.empty() ? -1 : cand->cost.compare( winners.front()->cost );
+
+			if ( c > 0 ) continue;  // skip more expensive than winner
+
+			if ( c < 0 ) {
+				// reset on new cheapest
+				seen_undeleted = ! findDeletedExpr( cand->expr );
+				winners.clear();
+			} else /* if ( c == 0 ) */ {
+				if ( findDeletedExpr( cand->expr ) ) {
+					// skip deleted expression if already seen one equivalent-cost not
+					if ( seen_undeleted ) continue;
+				} else if ( ! seen_undeleted ) {
+					// replace list of equivalent-cost deleted expressions with one non-deleted
+					winners.clear();
+					seen_undeleted = true;
+				}
+			}
+
+			winners.emplace_back( std::move( cand ) );
+		}
+
+		// promote candidate.cvtCost to .cost
+		// promoteCvtCost( winners );
+
+		// produce ambiguous errors, if applicable
+		if ( winners.size() != 1 ) {
+			std::ostringstream stream;
+			stream << "Cannot choose between " << winners.size() << " alternatives for "
+				<< kind << (kind != "" ? " " : "") << "expression\n";
+			ast::print( stream, untyped );
+			stream << " Alternatives are:\n";
+			print( stream, winners, 1 );
+			SemanticError( untyped->location, stream.str() );
+		}
+
+		// single selected choice
+		CandidateRef & choice = winners.front();
+
+		// fail on only expression deleted
+		if ( ! seen_undeleted ) {
+			SemanticError( untyped->location, choice->expr.get(), "Unique best alternative "
+			"includes deleted identifier in " );
+		}
+
+		return std::move( choice );
+	}
+
+	/// Strips extraneous casts out of an expression
+	struct StripCasts final {
+		const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
+			if (
+				castExpr->isGenerated == ast::GeneratedCast
+				&& typesCompatible( castExpr->arg->result, castExpr->result )
+			) {
+				// generated cast is the same type as its argument, remove it after keeping env
+				return ast::mutate_field(
+					castExpr->arg.get(), &ast::Expr::env, castExpr->env );
+			}
+			return castExpr;
+		}
+
+		static void strip( ast::ptr< ast::Expr > & expr ) {
+			ast::Pass< StripCasts > stripper;
+			expr = expr->accept( stripper );
+		}
+	};
+
+	/// Swaps argument into expression pointer, saving original environment
+	void swap_and_save_env( ast::ptr< ast::Expr > & expr, const ast::Expr * newExpr ) {
+		ast::ptr< ast::TypeSubstitution > env = expr->env;
+		expr.set_and_mutate( newExpr )->env = env;
+	}
+
+	/// Removes cast to type of argument (unlike StripCasts, also handles non-generated casts)
+	void removeExtraneousCast( ast::ptr<ast::Expr> & expr ) {
+		if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) {
+			if ( typesCompatible( castExpr->arg->result, castExpr->result ) ) {
+				// cast is to the same type as its argument, remove it
+				swap_and_save_env( expr, castExpr->arg );
+			}
+		}
+	}
+
+} // anonymous namespace
+
+/// Establish post-resolver invariants for expressions
+void finishExpr(
+	ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
+	const ast::TypeSubstitution * oldenv = nullptr
+) {
+	// set up new type substitution for expression
+	ast::ptr< ast::TypeSubstitution > newenv =
+		 oldenv ? oldenv : new ast::TypeSubstitution{};
+	env.writeToSubstitution( *newenv.get_and_mutate() );
+	expr.get_and_mutate()->env = std::move( newenv );
+	// remove unncecessary casts
+	StripCasts::strip( expr );
+}
+
+ast::ptr< ast::Expr > resolveInVoidContext(
+	const ast::Expr * expr, const ResolveContext & context,
+	ast::TypeEnvironment & env
+) {
+	assertf( expr, "expected a non-null expression" );
+
+	// set up and resolve expression cast to void
+	ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
+	CandidateRef choice = findUnfinishedKindExpression(
+		untyped, context, "", anyCandidate, ResolveMode::withAdjustment() );
+
+	// a cast expression has either 0 or 1 interpretations (by language rules);
+	// if 0, an exception has already been thrown, and this code will not run
+	const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
+	env = std::move( choice->env );
+
+	return castExpr->arg;
+}
+
+/// Resolve `untyped` to the expression whose candidate is the best match for a `void`
+/// context.
+ast::ptr< ast::Expr > findVoidExpression(
+	const ast::Expr * untyped, const ResolveContext & context
+) {
+	ast::TypeEnvironment env;
+	ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, context, env );
+	finishExpr( newExpr, env, untyped->env );
+	return newExpr;
+}
+
+namespace {
+	/// resolve `untyped` to the expression whose candidate satisfies `pred` with the
+	/// lowest cost, returning the resolved version
+	ast::ptr< ast::Expr > findKindExpression(
+		const ast::Expr * untyped, const ResolveContext & context,
+		std::function<bool(const Candidate &)> pred = anyCandidate,
+		const std::string & kind = "", ResolveMode mode = {}
+	) {
+		if ( ! untyped ) return {};
+		CandidateRef choice =
+			findUnfinishedKindExpression( untyped, context, kind, pred, mode );
+		ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
+		return std::move( choice->expr );
+	}
+
+	/// Resolve `untyped` to the single expression whose candidate is the best match
+	ast::ptr< ast::Expr > findSingleExpression(
+		const ast::Expr * untyped, const ResolveContext & context
+	) {
+		Stats::ResolveTime::start( untyped );
+		auto res = findKindExpression( untyped, context );
+		Stats::ResolveTime::stop();
+		return res;
+	}
+} // anonymous namespace
+
+ast::ptr< ast::Expr > findSingleExpression(
+	const ast::Expr * untyped, const ast::Type * type,
+	const ResolveContext & context
+) {
+	assert( untyped && type );
+	ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
+	ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, context );
+	removeExtraneousCast( newExpr );
+	return newExpr;
+}
+
+namespace {
+	bool structOrUnion( const Candidate & i ) {
+		const ast::Type * t = i.expr->result->stripReferences();
+		return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t );
+	}
+	/// Predicate for "Candidate has integral type"
+	bool hasIntegralType( const Candidate & i ) {
+		const ast::Type * type = i.expr->result;
+
+		if ( auto bt = dynamic_cast< const ast::BasicType * >( type ) ) {
+			return bt->isInteger();
+		} else if (
+			dynamic_cast< const ast::EnumInstType * >( type )
+			|| dynamic_cast< const ast::ZeroType * >( type )
+			|| dynamic_cast< const ast::OneType * >( type )
+		) {
+			return true;
+		} else return false;
+	}
+
+	/// Resolve `untyped` as an integral expression, returning the resolved version
+	ast::ptr< ast::Expr > findIntegralExpression(
+		const ast::Expr * untyped, const ResolveContext & context
+	) {
+		return findKindExpression( untyped, context, hasIntegralType, "condition" );
+	}
+
+	/// check if a type is a character type
+	bool isCharType( const ast::Type * t ) {
+		if ( auto bt = dynamic_cast< const ast::BasicType * >( t ) ) {
+			return bt->kind == ast::BasicType::Char
+				|| bt->kind == ast::BasicType::SignedChar
+				|| bt->kind == ast::BasicType::UnsignedChar;
+		}
+		return false;
+	}
+
+	/// Advance a type itertor to the next mutex parameter
+	template<typename Iter>
+	inline bool nextMutex( Iter & it, const Iter & end ) {
+		while ( it != end && ! (*it)->is_mutex() ) { ++it; }
+		return it != end;
+	}
+}
+
+class Resolver final
+: public ast::WithSymbolTable, public ast::WithGuards,
+  public ast::WithVisitorRef<Resolver>, public ast::WithShortCircuiting,
+  public ast::WithStmtsToAdd<> {
+
+	ast::ptr< ast::Type > functionReturn = nullptr;
+	ast::CurrentObject currentObject;
+	// for work previously in GenInit
+	static InitTweak::ManagedTypes managedTypes;
+	ResolveContext context;
+
+	bool inEnumDecl = false;
+
+public:
+	static size_t traceId;
+	Resolver( const ast::TranslationGlobal & global ) :
+		ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd),
+		context{ symtab, global } {}
+	Resolver( const ResolveContext & context ) :
+		ast::WithSymbolTable{ context.symtab },
+		context{ symtab, context.global } {}
+
+	const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
+	const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
+	const ast::ObjectDecl * previsit( const ast::ObjectDecl * );
+	void previsit( const ast::AggregateDecl * );
+	void previsit( const ast::StructDecl * );
+	void previsit( const ast::EnumDecl * );
+	const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
+
+	const ast::ArrayType * previsit( const ast::ArrayType * );
+	const ast::PointerType * previsit( const ast::PointerType * );
+
+	const ast::ExprStmt *        previsit( const ast::ExprStmt * );
+	const ast::AsmExpr *         previsit( const ast::AsmExpr * );
+	const ast::AsmStmt *         previsit( const ast::AsmStmt * );
+	const ast::IfStmt *          previsit( const ast::IfStmt * );
+	const ast::WhileDoStmt *     previsit( const ast::WhileDoStmt * );
+	const ast::ForStmt *         previsit( const ast::ForStmt * );
+	const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
+	const ast::CaseClause *      previsit( const ast::CaseClause * );
+	const ast::BranchStmt *      previsit( const ast::BranchStmt * );
+	const ast::ReturnStmt *      previsit( const ast::ReturnStmt * );
+	const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
+	const ast::CatchClause *     previsit( const ast::CatchClause * );
+	const ast::CatchClause *     postvisit( const ast::CatchClause * );
+	const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
+	const ast::WithStmt *        previsit( const ast::WithStmt * );
+
+	const ast::SingleInit *      previsit( const ast::SingleInit * );
+	const ast::ListInit *        previsit( const ast::ListInit * );
+	const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
+
+	void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
+
+	void beginScope() { managedTypes.beginScope(); }
+	void endScope() { managedTypes.endScope(); }
+	bool on_error(ast::ptr<ast::Decl> & decl);
+};
+// size_t Resolver::traceId = Stats::Heap::new_stacktrace_id("Resolver");
+
+InitTweak::ManagedTypes Resolver::managedTypes;
+
+void resolve( ast::TranslationUnit& translationUnit ) {
+	ast::Pass< Resolver >::run( translationUnit, translationUnit.global );
+}
+
+ast::ptr< ast::Init > resolveCtorInit(
+	const ast::ConstructorInit * ctorInit, const ResolveContext & context
+) {
+	assert( ctorInit );
+	ast::Pass< Resolver > resolver( context );
+	return ctorInit->accept( resolver );
+}
+
+const ast::Expr * resolveStmtExpr(
+	const ast::StmtExpr * stmtExpr, const ResolveContext & context
+) {
+	assert( stmtExpr );
+	ast::Pass< Resolver > resolver( context );
+	auto ret = mutate(stmtExpr->accept(resolver));
+	strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
+	return ret;
+}
+
+namespace {
+	const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ResolveContext & context) {
+		std::string name = attr->normalizedName();
+		if (name == "constructor" || name == "destructor") {
+			if (attr->params.size() == 1) {
+				auto arg = attr->params.front();
+				auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), context );
+				auto result = eval(arg);
+
+				auto mutAttr = mutate(attr);
+				mutAttr->params.front() = resolved;
+				if (! result.hasKnownValue) {
+					SemanticWarning(loc, Warning::GccAttributes,
+						toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
+				}
+				else {
+					auto priority = result.knownValue;
+					if (priority < 101) {
+						SemanticWarning(loc, Warning::GccAttributes,
+							toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
+					} else if (priority < 201 && ! buildingLibrary()) {
+						SemanticWarning(loc, Warning::GccAttributes,
+							toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
+					}
+				}
+				return mutAttr;
+			} else if (attr->params.size() > 1) {
+				SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
+			} else {
+				SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
+			}
+		}
+		return attr;
+	}
+}
+
+const ast::FunctionDecl * Resolver::previsit( const ast::FunctionDecl * functionDecl ) {
+	GuardValue( functionReturn );
+
+	assert (functionDecl->unique());
+	if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) {
+		SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations");
+	}
+
+	if (!functionDecl->isTypeFixed) {
+		auto mutDecl = mutate(functionDecl);
+		auto mutType = mutDecl->type.get_and_mutate();
+
+		for (auto & attr: mutDecl->attributes) {
+			attr = handleAttribute(mutDecl->location, attr, context );
+		}
+
+		// handle assertions
+
+		symtab.enterScope();
+		mutType->forall.clear();
+		mutType->assertions.clear();
+		for (auto & typeParam : mutDecl->type_params) {
+			symtab.addType(typeParam);
+			mutType->forall.emplace_back(new ast::TypeInstType(typeParam));
+		}
+		for (auto & asst : mutDecl->assertions) {
+			asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), context);
+			symtab.addId(asst);
+			mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
+		}
+
+		// temporarily adds params to symbol table.
+		// actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl)
+
+		std::vector<ast::ptr<ast::Type>> paramTypes;
+		std::vector<ast::ptr<ast::Type>> returnTypes;
+
+		for (auto & param : mutDecl->params) {
+			param = fixObjectType(param.strict_as<ast::ObjectDecl>(), context);
+			symtab.addId(param);
+			paramTypes.emplace_back(param->get_type());
+		}
+		for (auto & ret : mutDecl->returns) {
+			ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), context);
+			returnTypes.emplace_back(ret->get_type());
+		}
+		// since function type in decl is just a view of param types, need to update that as well
+		mutType->params = std::move(paramTypes);
+		mutType->returns = std::move(returnTypes);
+
+		auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
+
+		std::list<ast::ptr<ast::Stmt>> newStmts;
+		resolveWithExprs (mutDecl->withExprs, newStmts);
+
+		if (mutDecl->stmts) {
+			auto mutStmt = mutDecl->stmts.get_and_mutate();
+			mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts));
+			mutDecl->stmts = mutStmt;
+		}
+
+		symtab.leaveScope();
+
+		mutDecl->type = renamedType;
+		mutDecl->mangleName = Mangle::mangle(mutDecl);
+		mutDecl->isTypeFixed = true;
+		functionDecl = mutDecl;
+	}
+	managedTypes.handleDWT(functionDecl);
+
+	functionReturn = extractResultType( functionDecl->type );
+	return functionDecl;
+}
+
+const ast::FunctionDecl * Resolver::postvisit( const ast::FunctionDecl * functionDecl ) {
+	// default value expressions have an environment which shouldn't be there and trips up
+	// later passes.
+	assert( functionDecl->unique() );
+	ast::FunctionType * mutType = mutate( functionDecl->type.get() );
+
+	for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
+		if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
+			if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
+				if ( init->value->env == nullptr ) continue;
+				// clone initializer minus the initializer environment
+				auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
+				auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
+				auto mutValue = mutate( mutInit->value.get() );
+
+				mutValue->env = nullptr;
+				mutInit->value = mutValue;
+				mutParam->init = mutInit;
+				mutType->params[i] = mutParam;
+
+				assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
+			}
+		}
+	}
+	mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
+	return functionDecl;
+}
+
+const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) {
+	// To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
+	// class-variable `initContext` is changed multiple times because the LHS is analyzed
+	// twice. The second analysis changes `initContext` because a function type can contain
+	// object declarations in the return and parameter types. Therefore each value of
+	// `initContext` is retained so the type on the first analysis is preserved and used for
+	// selecting the RHS.
+	GuardValue( currentObject );
+
+	if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
+		// enumerator initializers should not use the enum type to initialize, since the
+		// enum type is still incomplete at this point. Use `int` instead.
+
+		if ( auto enumBase = dynamic_cast< const ast::EnumInstType * >
+			( objectDecl->get_type() )->base->base ) {
+			objectDecl = fixObjectType( objectDecl, context );
+			currentObject = ast::CurrentObject{
+				objectDecl->location,
+				enumBase
+			};
+		} else {
+			objectDecl = fixObjectType( objectDecl, context );
+			currentObject = ast::CurrentObject{
+				objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
+		}
+	} else {
+		if ( !objectDecl->isTypeFixed ) {
+			auto newDecl = fixObjectType(objectDecl, context);
+			auto mutDecl = mutate(newDecl);
+
+			// generate CtorInit wrapper when necessary.
+			// in certain cases, fixObjectType is called before reaching
+			// 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 ) ) ) ) {
+				// constructed objects cannot be designated
+				if ( InitTweak::isDesignated( mutDecl->init ) ) {
+					ast::Pass<ResolveDesignators> res( context );
+					maybe_accept( mutDecl->init.get(), res );
+					if ( !res.core.result ) {
+						SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object.\n"
+									   "If this is really what you want, initialize with @=." );
+					}
+				}
+				// constructed objects should not have initializers nested too deeply
+				if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
+
+				mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
+			}
+
+			objectDecl = mutDecl;
+		}
+		currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
+	}
+
+	return objectDecl;
+}
+
+void Resolver::previsit( const ast::AggregateDecl * _aggDecl ) {
+	auto aggDecl = mutate(_aggDecl);
+	assertf(aggDecl == _aggDecl, "type declarations must be unique");
+
+	for (auto & member: aggDecl->members) {
+		// nested type decls are hoisted already. no need to do anything
+		if (auto obj = member.as<ast::ObjectDecl>()) {
+			member = fixObjectType(obj, context);
+		}
+	}
+}
+
+void Resolver::previsit( const ast::StructDecl * structDecl ) {
+	previsit(static_cast<const ast::AggregateDecl *>(structDecl));
+	managedTypes.handleStruct(structDecl);
+}
+
+void Resolver::previsit( const ast::EnumDecl * ) {
+	// in case we decide to allow nested enums
+	GuardValue( inEnumDecl );
+	inEnumDecl = true;
+	// don't need to fix types for enum fields
+}
+
+const ast::StaticAssertDecl * Resolver::previsit(
+	const ast::StaticAssertDecl * assertDecl
+) {
+	return ast::mutate_field(
+		assertDecl, &ast::StaticAssertDecl::cond,
+		findIntegralExpression( assertDecl->cond, context ) );
+}
+
+template< typename PtrType >
+const PtrType * handlePtrType( const PtrType * type, const ResolveContext & context ) {
+	if ( type->dimension ) {
+		const ast::Type * sizeType = context.global.sizeType.get();
+		ast::ptr< ast::Expr > dimension = findSingleExpression( type->dimension, sizeType, context );
+		assertf(dimension->env->empty(), "array dimension expr has nonempty env");
+		dimension.get_and_mutate()->env = nullptr;
+		ast::mutate_field( type, &PtrType::dimension, dimension );
+	}
+	return type;
+}
+
+const ast::ArrayType * Resolver::previsit( const ast::ArrayType * at ) {
+	return handlePtrType( at, context );
+}
+
+const ast::PointerType * Resolver::previsit( const ast::PointerType * pt ) {
+	return handlePtrType( pt, context );
+}
+
+const ast::ExprStmt * Resolver::previsit( const ast::ExprStmt * exprStmt ) {
+	visit_children = false;
+	assertf( exprStmt->expr, "ExprStmt has null expression in resolver" );
+
+	return ast::mutate_field(
+		exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, context ) );
+}
+
+const ast::AsmExpr * Resolver::previsit( const ast::AsmExpr * asmExpr ) {
+	visit_children = false;
+
+	asmExpr = ast::mutate_field(
+		asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, context ) );
+
+	return asmExpr;
+}
+
+const ast::AsmStmt * Resolver::previsit( const ast::AsmStmt * asmStmt ) {
+	visitor->maybe_accept( asmStmt, &ast::AsmStmt::input );
+	visitor->maybe_accept( asmStmt, &ast::AsmStmt::output );
+	visit_children = false;
+	return asmStmt;
+}
+
+const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) {
+	return ast::mutate_field(
+		ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) );
+}
+
+const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) {
+	return ast::mutate_field(
+		whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) );
+}
+
+const ast::ForStmt * Resolver::previsit( const ast::ForStmt * forStmt ) {
+	if ( forStmt->cond ) {
+		forStmt = ast::mutate_field(
+			forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, context ) );
+	}
+
+	if ( forStmt->inc ) {
+		forStmt = ast::mutate_field(
+			forStmt, &ast::ForStmt::inc, findVoidExpression( forStmt->inc, context ) );
+	}
+
+	return forStmt;
+}
+
+const ast::SwitchStmt * Resolver::previsit( const ast::SwitchStmt * switchStmt ) {
+	GuardValue( currentObject );
+	switchStmt = ast::mutate_field(
+		switchStmt, &ast::SwitchStmt::cond,
+		findIntegralExpression( switchStmt->cond, context ) );
+	currentObject = ast::CurrentObject{ switchStmt->location, switchStmt->cond->result };
+	return switchStmt;
+}
+
+const ast::CaseClause * Resolver::previsit( const ast::CaseClause * caseStmt ) {
+	if ( caseStmt->cond ) {
+		std::deque< ast::InitAlternative > initAlts = currentObject.getOptions();
+		assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral "
+			"expression." );
+
+		ast::ptr< ast::Expr > untyped =
+			new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
+		ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, context );
+
+		// case condition cannot have a cast in C, so it must be removed here, regardless of
+		// whether it would perform a conversion.
+		if ( const ast::CastExpr * castExpr = newExpr.as< ast::CastExpr >() ) {
+			swap_and_save_env( newExpr, castExpr->arg );
+		}
+
+		caseStmt = ast::mutate_field( caseStmt, &ast::CaseClause::cond, newExpr );
+	}
+	return caseStmt;
+}
+
+const ast::BranchStmt * Resolver::previsit( const ast::BranchStmt * branchStmt ) {
+	visit_children = false;
+	// must resolve the argument of a computed goto
+	if ( branchStmt->kind == ast::BranchStmt::Goto && branchStmt->computedTarget ) {
+		// computed goto argument is void*
+		ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} };
+		branchStmt = ast::mutate_field(
+			branchStmt, &ast::BranchStmt::computedTarget,
+			findSingleExpression( branchStmt->computedTarget, target, context ) );
+	}
+	return branchStmt;
+}
+
+const ast::ReturnStmt * Resolver::previsit( const ast::ReturnStmt * returnStmt ) {
+	visit_children = false;
+	if ( returnStmt->expr ) {
+		returnStmt = ast::mutate_field(
+			returnStmt, &ast::ReturnStmt::expr,
+			findSingleExpression( returnStmt->expr, functionReturn, context ) );
+	}
+	return returnStmt;
+}
+
+const ast::ThrowStmt * Resolver::previsit( const ast::ThrowStmt * throwStmt ) {
+	visit_children = false;
+	if ( throwStmt->expr ) {
+		const ast::StructDecl * exceptionDecl =
+			symtab.lookupStruct( "__cfaehm_base_exception_t" );
+		assert( exceptionDecl );
+		ast::ptr< ast::Type > exceptType =
+			new ast::PointerType{ new ast::StructInstType{ exceptionDecl } };
+		throwStmt = ast::mutate_field(
+			throwStmt, &ast::ThrowStmt::expr,
+			findSingleExpression( throwStmt->expr, exceptType, context ) );
+	}
+	return throwStmt;
+}
+
+const ast::CatchClause * Resolver::previsit( const ast::CatchClause * catchClause ) {
+	// Until we are very sure this invarent (ifs that move between passes have then)
+	// holds, check it. This allows a check for when to decode the mangling.
+	if ( auto ifStmt = catchClause->body.as<ast::IfStmt>() ) {
+		assert( ifStmt->then );
+	}
+	// Encode the catchStmt so the condition can see the declaration.
+	if ( catchClause->cond ) {
+		ast::CatchClause * clause = mutate( catchClause );
+		clause->body = new ast::IfStmt( clause->location, clause->cond, nullptr, clause->body );
+		clause->cond = nullptr;
+		return clause;
+	}
+	return catchClause;
+}
+
+const ast::CatchClause * Resolver::postvisit( const ast::CatchClause * catchClause ) {
+	// Decode the catchStmt so everything is stored properly.
+	const ast::IfStmt * ifStmt = catchClause->body.as<ast::IfStmt>();
+	if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
+		assert( ifStmt->cond );
+		assert( ifStmt->else_ );
+		ast::CatchClause * clause = ast::mutate( catchClause );
+		clause->cond = ifStmt->cond;
+		clause->body = ifStmt->else_;
+		// ifStmt should be implicately deleted here.
+		return clause;
+	}
+	return catchClause;
+}
+
+const ast::WaitForStmt * Resolver::previsit( const ast::WaitForStmt * stmt ) {
+	visit_children = false;
+
+	// Resolve all clauses first
+	for ( unsigned i = 0; i < stmt->clauses.size(); ++i ) {
+		const ast::WaitForClause & clause = *stmt->clauses[i];
+
+		ast::TypeEnvironment env;
+		CandidateFinder funcFinder( context, env );
+
+		// Find all candidates for a function in canonical form
+		funcFinder.find( clause.target, ResolveMode::withAdjustment() );
+
+		if ( funcFinder.candidates.empty() ) {
+			stringstream ss;
+			ss << "Use of undeclared indentifier '";
+			ss << clause.target.strict_as< ast::NameExpr >()->name;
+			ss << "' in call to waitfor";
+			SemanticError( stmt->location, ss.str() );
+		}
+
+		if ( clause.target_args.empty() ) {
+			SemanticError( stmt->location,
+				"Waitfor clause must have at least one mutex parameter");
+		}
+
+		// Find all alternatives for all arguments in canonical form
+		std::vector< CandidateFinder > argFinders =
+			funcFinder.findSubExprs( clause.target_args );
+
+		// List all combinations of arguments
+		std::vector< CandidateList > possibilities;
+		combos( argFinders.begin(), argFinders.end(), back_inserter( possibilities ) );
+
+		// For every possible function:
+		// * try matching the arguments to the parameters, not the other way around because
+		//   more arguments than parameters
+		CandidateList funcCandidates;
+		std::vector< CandidateList > argsCandidates;
+		SemanticErrorException errors;
+		for ( CandidateRef & func : funcFinder.candidates ) {
+			try {
+				auto pointerType = dynamic_cast< const ast::PointerType * >(
+					func->expr->result->stripReferences() );
+				if ( ! pointerType ) {
+					SemanticError( stmt->location, func->expr->result.get(),
+						"candidate not viable: not a pointer type\n" );
+				}
+
+				auto funcType = pointerType->base.as< ast::FunctionType >();
+				if ( ! funcType ) {
+					SemanticError( stmt->location, func->expr->result.get(),
+						"candidate not viable: not a function type\n" );
+				}
+
+				{
+					auto param    = funcType->params.begin();
+					auto paramEnd = funcType->params.end();
+
+					if( ! nextMutex( param, paramEnd ) ) {
+						SemanticError( stmt->location, funcType,
+							"candidate function not viable: no mutex parameters\n");
+					}
+				}
+
+				CandidateRef func2{ new Candidate{ *func } };
+				// strip reference from function
+				func2->expr = referenceToRvalueConversion( func->expr, func2->cost );
+
+				// Each argument must be matched with a parameter of the current candidate
+				for ( auto & argsList : possibilities ) {
+					try {
+						// Declare data structures needed for resolution
+						ast::OpenVarSet open;
+						ast::AssertionSet need, have;
+						ast::TypeEnvironment resultEnv{ func->env };
+						// Add all type variables as open so that those not used in the
+						// parameter list are still considered open
+						resultEnv.add( funcType->forall );
+
+						// load type variables from arguments into one shared space
+						for ( auto & arg : argsList ) {
+							resultEnv.simpleCombine( arg->env );
+						}
+
+						// Make sure we don't widen any existing bindings
+						resultEnv.forbidWidening();
+
+						// Find any unbound type variables
+						resultEnv.extractOpenVars( open );
+
+						auto param = funcType->params.begin();
+						auto paramEnd = funcType->params.end();
+
+						unsigned n_mutex_param = 0;
+
+						// For every argument of its set, check if it matches one of the
+						// parameters. The order is important
+						for ( auto & arg : argsList ) {
+							// Ignore non-mutex arguments
+							if ( ! nextMutex( param, paramEnd ) ) {
+								// We ran out of parameters but still have arguments.
+								// This function doesn't match
+								SemanticError( stmt->location, funcType,
+									toString("candidate function not viable: too many mutex "
+									"arguments, expected ", n_mutex_param, "\n" ) );
+							}
+
+							++n_mutex_param;
+
+							// Check if the argument matches the parameter type in the current scope.
+							// ast::ptr< ast::Type > paramType = (*param)->get_type();
+
+							if (
+								! unify(
+									arg->expr->result, *param, resultEnv, need, have, open )
+							) {
+								// Type doesn't match
+								stringstream ss;
+								ss << "candidate function not viable: no known conversion "
+									"from '";
+								ast::print( ss, *param );
+								ss << "' to '";
+								ast::print( ss, arg->expr->result );
+								ss << "' with env '";
+								ast::print( ss, resultEnv );
+								ss << "'\n";
+								SemanticError( stmt->location, funcType, ss.str() );
+							}
+
+							++param;
+						}
+
+						// All arguments match!
+
+						// Check if parameters are missing
+						if ( nextMutex( param, paramEnd ) ) {
+							do {
+								++n_mutex_param;
+								++param;
+							} while ( nextMutex( param, paramEnd ) );
+
+							// We ran out of arguments but still have parameters left; this
+							// function doesn't match
+							SemanticError( stmt->location, funcType,
+								toString( "candidate function not viable: too few mutex "
+								"arguments, expected ", n_mutex_param, "\n" ) );
+						}
+
+						// All parameters match!
+
+						// Finish the expressions to tie in proper environments
+						finishExpr( func2->expr, resultEnv );
+						for ( CandidateRef & arg : argsList ) {
+							finishExpr( arg->expr, resultEnv );
+						}
+
+						// This is a match, store it and save it for later
+						funcCandidates.emplace_back( std::move( func2 ) );
+						argsCandidates.emplace_back( std::move( argsList ) );
+
+					} catch ( SemanticErrorException & e ) {
+						errors.append( e );
+					}
+				}
+			} catch ( SemanticErrorException & e ) {
+				errors.append( e );
+			}
+		}
+
+		// Make sure correct number of arguments
+		if( funcCandidates.empty() ) {
+			SemanticErrorException top( stmt->location,
+				"No alternatives for function in call to waitfor" );
+			top.append( errors );
+			throw top;
+		}
+
+		if( argsCandidates.empty() ) {
+			SemanticErrorException top( stmt->location,
+				"No alternatives for arguments in call to waitfor" );
+			top.append( errors );
+			throw top;
+		}
+
+		if( funcCandidates.size() > 1 ) {
+			SemanticErrorException top( stmt->location,
+				"Ambiguous function in call to waitfor" );
+			top.append( errors );
+			throw top;
+		}
+		if( argsCandidates.size() > 1 ) {
+			SemanticErrorException top( stmt->location,
+				"Ambiguous arguments in call to waitfor" );
+			top.append( errors );
+			throw top;
+		}
+		// TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
+
+		// build new clause
+		auto clause2 = new ast::WaitForClause( clause.location );
+
+		clause2->target = funcCandidates.front()->expr;
+
+		clause2->target_args.reserve( clause.target_args.size() );
+		const ast::StructDecl * decl_monitor = symtab.lookupStruct( "monitor$" );
+		for ( auto arg : argsCandidates.front() ) {
+			const auto & loc = stmt->location;
+
+			ast::Expr * init = new ast::CastExpr( loc,
+				new ast::UntypedExpr( loc,
+					new ast::NameExpr( loc, "get_monitor" ),
+					{ arg->expr }
+				),
+				new ast::PointerType(
+					new ast::StructInstType(
+						decl_monitor
+					)
+				)
+			);
+
+			clause2->target_args.emplace_back( findSingleExpression( init, context ) );
+		}
+
+		// Resolve the conditions as if it were an IfStmt, statements normally
+		clause2->when_cond = findSingleExpression( clause.when_cond, context );
+		clause2->stmt = clause.stmt->accept( *visitor );
+
+		// set results into stmt
+		auto n = mutate( stmt );
+		n->clauses[i] = clause2;
+		stmt = n;
+	}
+
+	if ( stmt->timeout_stmt ) {
+		// resolve the timeout as a size_t, the conditions like IfStmt, and stmts normally
+		ast::ptr< ast::Type > target =
+			new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
+		auto timeout_time = findSingleExpression( stmt->timeout_time, target, context );
+		auto timeout_cond = findSingleExpression( stmt->timeout_cond, context );
+		auto timeout_stmt = stmt->timeout_stmt->accept( *visitor );
+
+		// set results into stmt
+		auto n = mutate( stmt );
+		n->timeout_time = std::move( timeout_time );
+		n->timeout_cond = std::move( timeout_cond );
+		n->timeout_stmt = std::move( timeout_stmt );
+		stmt = n;
+	}
+
+	if ( stmt->else_stmt ) {
+		// resolve the condition like IfStmt, stmts normally
+		auto else_cond = findSingleExpression( stmt->else_cond, context );
+		auto else_stmt = stmt->else_stmt->accept( *visitor );
+
+		// set results into stmt
+		auto n = mutate( stmt );
+		n->else_cond = std::move( else_cond );
+		n->else_stmt = std::move( else_stmt );
+		stmt = n;
+	}
+
+	return stmt;
+}
+
+const ast::WithStmt * Resolver::previsit( const ast::WithStmt * withStmt ) {
+	auto mutStmt = mutate(withStmt);
+	resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
+	return mutStmt;
+}
+
+void Resolver::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
+	for (auto & expr : exprs) {
+		// only struct- and union-typed expressions are viable candidates
+		expr = findKindExpression( expr, context, structOrUnion, "with expression" );
+
+		// if with expression might be impure, create a temporary so that it is evaluated once
+		if ( Tuples::maybeImpure( expr ) ) {
+			static UniqueName tmpNamer( "_with_tmp_" );
+			const CodeLocation loc = expr->location;
+			auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) );
+			expr = new ast::VariableExpr( loc, tmp );
+			stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) );
+			if ( InitTweak::isConstructable( tmp->type ) ) {
+				// generate ctor/dtor and resolve them
+				tmp->init = InitTweak::genCtorInit( loc, tmp );
+			}
+			// since tmp is freshly created, this should modify tmp in-place
+			tmp->accept( *visitor );
+		} else if (expr->env && expr->env->empty()) {
+			expr = ast::mutate_field(expr.get(), &ast::Expr::env, nullptr);
+		}
+	}
+}
+
+const ast::SingleInit * Resolver::previsit( const ast::SingleInit * singleInit ) {
+	visit_children = false;
+	// resolve initialization using the possibilities as determined by the `currentObject`
+	// cursor.
+	ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{
+		singleInit->location, singleInit->value, currentObject.getOptions() };
+	ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, context );
+	const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
+
+	// move cursor to the object that is actually initialized
+	currentObject.setNext( initExpr->designation );
+
+	// discard InitExpr wrapper and retain relevant pieces.
+	// `initExpr` may have inferred params in the case where the expression specialized a
+	// function pointer, and newExpr may already have inferParams of its own, so a simple
+	// swap is not sufficient
+	ast::Expr::InferUnion inferred = initExpr->inferred;
+	swap_and_save_env( newExpr, initExpr->expr );
+	newExpr.get_and_mutate()->inferred.splice( std::move(inferred) );
+
+	// get the actual object's type (may not exactly match what comes back from the resolver
+	// due to conversions)
+	const ast::Type * initContext = currentObject.getCurrentType();
+
+	removeExtraneousCast( newExpr );
+
+	// check if actual object's type is char[]
+	if ( auto at = dynamic_cast< const ast::ArrayType * >( initContext ) ) {
+		if ( isCharType( at->base ) ) {
+			// check if the resolved type is char*
+			if ( auto pt = newExpr->result.as< ast::PointerType >() ) {
+				if ( isCharType( pt->base ) ) {
+					// strip cast if we're initializing a char[] with a char*
+					// e.g. char x[] = "hello"
+					if ( auto ce = newExpr.as< ast::CastExpr >() ) {
+						swap_and_save_env( newExpr, ce->arg );
 					}
 				}
 			}
-		};
-
-		struct ResolveDesignators final : public ast::WithShortCircuiting {
-			ResolveContext& context;
-			bool result = false;
-
-			ResolveDesignators( ResolveContext& _context ): context{_context} {};
-
-			void previsit( const ast::Node * ) {
-				// short circuit if we already know there are designations
-				if ( result ) visit_children = false;
-			}
-
-			void previsit( const ast::Designation * des ) {
-				if ( result ) visit_children = false;
-				else if ( ! des->designators.empty() ) {
-					if ( (des->designators.size() == 1) ) {
-						const ast::Expr * designator = des->designators.at(0);
-						if ( const ast::NameExpr * designatorName = dynamic_cast<const ast::NameExpr *>(designator) ) {
-							auto candidates = context.symtab.lookupId(designatorName->name);
-							for ( auto candidate : candidates ) {
-								if ( dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type()) ) {
-									result = true;
-									break;
-								}
-							}
-						}
-					}
-					visit_children = false;
-				}
-			}
-		};
-	} // anonymous namespace
-	/// Check if this expression is or includes a deleted expression
-	const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
-		return ast::Pass<DeleteFinder>::read( expr );
-	}
-
-	namespace {
-		/// always-accept candidate filter
-		bool anyCandidate( const Candidate & ) { return true; }
-
-		/// Calls the CandidateFinder and finds the single best candidate
-		CandidateRef findUnfinishedKindExpression(
-			const ast::Expr * untyped, const ResolveContext & context, const std::string & kind,
-			std::function<bool(const Candidate &)> pred = anyCandidate, ResolveMode mode = {}
-		) {
-			if ( ! untyped ) return nullptr;
-
-			// xxx - this isn't thread-safe, but should work until we parallelize the resolver
-			static unsigned recursion_level = 0;
-
-			++recursion_level;
-			ast::TypeEnvironment env;
-			CandidateFinder finder( context, env );
-			finder.allowVoid = true;
-			finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
-			--recursion_level;
-
-			// produce a filtered list of candidates
-			CandidateList candidates;
-			for ( auto & cand : finder.candidates ) {
-				if ( pred( *cand ) ) { candidates.emplace_back( cand ); }
-			}
-
-			// produce invalid error if no candidates
-			if ( candidates.empty() ) {
-				SemanticError( untyped,
-					toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""),
-					"expression: ") );
-			}
-
-			// search for cheapest candidate
-			CandidateList winners;
-			bool seen_undeleted = false;
-			for ( CandidateRef & cand : candidates ) {
-				int c = winners.empty() ? -1 : cand->cost.compare( winners.front()->cost );
-
-				if ( c > 0 ) continue;  // skip more expensive than winner
-
-				if ( c < 0 ) {
-					// reset on new cheapest
-					seen_undeleted = ! findDeletedExpr( cand->expr );
-					winners.clear();
-				} else /* if ( c == 0 ) */ {
-					if ( findDeletedExpr( cand->expr ) ) {
-						// skip deleted expression if already seen one equivalent-cost not
-						if ( seen_undeleted ) continue;
-					} else if ( ! seen_undeleted ) {
-						// replace list of equivalent-cost deleted expressions with one non-deleted
-						winners.clear();
-						seen_undeleted = true;
-					}
-				}
-
-				winners.emplace_back( std::move( cand ) );
-			}
-
-			// promote candidate.cvtCost to .cost
-			// promoteCvtCost( winners );
-
-			// produce ambiguous errors, if applicable
-			if ( winners.size() != 1 ) {
-				std::ostringstream stream;
-				stream << "Cannot choose between " << winners.size() << " alternatives for "
-					<< kind << (kind != "" ? " " : "") << "expression\n";
-				ast::print( stream, untyped );
-				stream << " Alternatives are:\n";
-				print( stream, winners, 1 );
-				SemanticError( untyped->location, stream.str() );
-			}
-
-			// single selected choice
-			CandidateRef & choice = winners.front();
-
-			// fail on only expression deleted
-			if ( ! seen_undeleted ) {
-				SemanticError( untyped->location, choice->expr.get(), "Unique best alternative "
-				"includes deleted identifier in " );
-			}
-
-			return std::move( choice );
-		}
-
-		/// Strips extraneous casts out of an expression
-		struct StripCasts final {
-			const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
-				if (
-					castExpr->isGenerated == ast::GeneratedCast
-					&& typesCompatible( castExpr->arg->result, castExpr->result )
-				) {
-					// generated cast is the same type as its argument, remove it after keeping env
-					return ast::mutate_field(
-						castExpr->arg.get(), &ast::Expr::env, castExpr->env );
-				}
-				return castExpr;
-			}
-
-			static void strip( ast::ptr< ast::Expr > & expr ) {
-				ast::Pass< StripCasts > stripper;
-				expr = expr->accept( stripper );
-			}
-		};
-
-		/// Swaps argument into expression pointer, saving original environment
-		void swap_and_save_env( ast::ptr< ast::Expr > & expr, const ast::Expr * newExpr ) {
-			ast::ptr< ast::TypeSubstitution > env = expr->env;
-			expr.set_and_mutate( newExpr )->env = env;
-		}
-
-		/// Removes cast to type of argument (unlike StripCasts, also handles non-generated casts)
-		void removeExtraneousCast( ast::ptr<ast::Expr> & expr ) {
-			if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) {
-				if ( typesCompatible( castExpr->arg->result, castExpr->result ) ) {
-					// cast is to the same type as its argument, remove it
-					swap_and_save_env( expr, castExpr->arg );
-				}
-			}
-		}
-
-
-	} // anonymous namespace
-/// Establish post-resolver invariants for expressions
-		void finishExpr(
-			ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
-			const ast::TypeSubstitution * oldenv = nullptr
-		) {
-			// set up new type substitution for expression
-			ast::ptr< ast::TypeSubstitution > newenv =
-				 oldenv ? oldenv : new ast::TypeSubstitution{};
-			env.writeToSubstitution( *newenv.get_and_mutate() );
-			expr.get_and_mutate()->env = std::move( newenv );
-			// remove unncecessary casts
-			StripCasts::strip( expr );
-		}
-
-	ast::ptr< ast::Expr > resolveInVoidContext(
-		const ast::Expr * expr, const ResolveContext & context,
-		ast::TypeEnvironment & env
-	) {
-		assertf( expr, "expected a non-null expression" );
-
-		// set up and resolve expression cast to void
-		ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
-		CandidateRef choice = findUnfinishedKindExpression(
-			untyped, context, "", anyCandidate, ResolveMode::withAdjustment() );
-
-		// a cast expression has either 0 or 1 interpretations (by language rules);
-		// if 0, an exception has already been thrown, and this code will not run
-		const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
-		env = std::move( choice->env );
-
-		return castExpr->arg;
-	}
-
-	/// Resolve `untyped` to the expression whose candidate is the best match for a `void`
-		/// context.
-		ast::ptr< ast::Expr > findVoidExpression(
-			const ast::Expr * untyped, const ResolveContext & context
-		) {
-			ast::TypeEnvironment env;
-			ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, context, env );
-			finishExpr( newExpr, env, untyped->env );
-			return newExpr;
-		}
-
-	namespace {
-
-
-		/// resolve `untyped` to the expression whose candidate satisfies `pred` with the
-		/// lowest cost, returning the resolved version
-		ast::ptr< ast::Expr > findKindExpression(
-			const ast::Expr * untyped, const ResolveContext & context,
-			std::function<bool(const Candidate &)> pred = anyCandidate,
-			const std::string & kind = "", ResolveMode mode = {}
-		) {
-			if ( ! untyped ) return {};
-			CandidateRef choice =
-				findUnfinishedKindExpression( untyped, context, kind, pred, mode );
-			ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
-			return std::move( choice->expr );
-		}
-
-		/// Resolve `untyped` to the single expression whose candidate is the best match
-		ast::ptr< ast::Expr > findSingleExpression(
-			const ast::Expr * untyped, const ResolveContext & context
-		) {
-			Stats::ResolveTime::start( untyped );
-			auto res = findKindExpression( untyped, context );
-			Stats::ResolveTime::stop();
-			return res;
-		}
-	} // anonymous namespace
-
-	ast::ptr< ast::Expr > findSingleExpression(
-		const ast::Expr * untyped, const ast::Type * type,
-		const ResolveContext & context
-	) {
-		assert( untyped && type );
-		ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
-		ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, context );
-		removeExtraneousCast( newExpr );
-		return newExpr;
-	}
-
-	namespace {
-		bool structOrUnion( const Candidate & i ) {
-			const ast::Type * t = i.expr->result->stripReferences();
-			return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t );
-		}
-		/// Predicate for "Candidate has integral type"
-		bool hasIntegralType( const Candidate & i ) {
-			const ast::Type * type = i.expr->result;
-
-			if ( auto bt = dynamic_cast< const ast::BasicType * >( type ) ) {
-				return bt->isInteger();
-			} else if (
-				dynamic_cast< const ast::EnumInstType * >( type )
-				|| dynamic_cast< const ast::ZeroType * >( type )
-				|| dynamic_cast< const ast::OneType * >( type )
-			) {
-				return true;
-			} else return false;
-		}
-
-		/// Resolve `untyped` as an integral expression, returning the resolved version
-		ast::ptr< ast::Expr > findIntegralExpression(
-			const ast::Expr * untyped, const ResolveContext & context
-		) {
-			return findKindExpression( untyped, context, hasIntegralType, "condition" );
-		}
-
-		/// check if a type is a character type
-		bool isCharType( const ast::Type * t ) {
-			if ( auto bt = dynamic_cast< const ast::BasicType * >( t ) ) {
-				return bt->kind == ast::BasicType::Char
-					|| bt->kind == ast::BasicType::SignedChar
-					|| bt->kind == ast::BasicType::UnsignedChar;
-			}
+		}
+	}
+
+	// move cursor to next object in preparation for next initializer
+	currentObject.increment();
+
+	// set initializer expression to resolved expression
+	return ast::mutate_field( singleInit, &ast::SingleInit::value, std::move(newExpr) );
+}
+
+const ast::ListInit * Resolver::previsit( const ast::ListInit * listInit ) {
+	// move cursor into brace-enclosed initializer-list
+	currentObject.enterListInit( listInit->location );
+
+	assert( listInit->designations.size() == listInit->initializers.size() );
+	for ( unsigned i = 0; i < listInit->designations.size(); ++i ) {
+		// iterate designations and initializers in pairs, moving the cursor to the current
+		// designated object and resolving the initializer against that object
+		listInit = ast::mutate_field_index(
+			listInit, &ast::ListInit::designations, i,
+			currentObject.findNext( listInit->designations[i] ) );
+		listInit = ast::mutate_field_index(
+			listInit, &ast::ListInit::initializers, i,
+			listInit->initializers[i]->accept( *visitor ) );
+	}
+
+	// move cursor out of brace-enclosed initializer-list
+	currentObject.exitListInit();
+
+	visit_children = false;
+	return listInit;
+}
+
+const ast::ConstructorInit * Resolver::previsit( const ast::ConstructorInit * ctorInit ) {
+	visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
+	visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
+
+	// found a constructor - can get rid of C-style initializer
+	// xxx - Rob suggests this field is dead code
+	ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr );
+
+	// intrinsic single-parameter constructors and destructors do nothing. Since this was
+	// implicitly generated, there's no way for it to have side effects, so get rid of it to
+	// clean up generated code
+	if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
+		ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::ctor, nullptr );
+	}
+	if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
+		ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::dtor, nullptr );
+	}
+
+	return ctorInit;
+}
+
+// suppress error on autogen functions and mark invalid autogen as deleted.
+bool Resolver::on_error(ast::ptr<ast::Decl> & decl) {
+	if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
+		// xxx - can intrinsic gen ever fail?
+		if (functionDecl->linkage == ast::Linkage::AutoGen) {
+			auto mutDecl = mutate(functionDecl);
+			mutDecl->isDeleted = true;
+			mutDecl->stmts = nullptr;
+			decl = mutDecl;
 			return false;
 		}
-
-		/// Advance a type itertor to the next mutex parameter
-		template<typename Iter>
-		inline bool nextMutex( Iter & it, const Iter & end ) {
-			while ( it != end && ! (*it)->is_mutex() ) { ++it; }
-			return it != end;
-		}
-	}
-
-	class Resolver final
-	: public ast::WithSymbolTable, public ast::WithGuards,
-	  public ast::WithVisitorRef<Resolver>, public ast::WithShortCircuiting,
-	  public ast::WithStmtsToAdd<> {
-
-		ast::ptr< ast::Type > functionReturn = nullptr;
-		ast::CurrentObject currentObject;
-		// for work previously in GenInit
-		static InitTweak::ManagedTypes managedTypes;
-		ResolveContext context;
-
-		bool inEnumDecl = false;
-
-	public:
-		static size_t traceId;
-		Resolver( const ast::TranslationGlobal & global ) :
-			ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd),
-			context{ symtab, global } {}
-		Resolver( const ResolveContext & context ) :
-			ast::WithSymbolTable{ context.symtab },
-			context{ symtab, context.global } {}
-
-		const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
-		const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
-		const ast::ObjectDecl * previsit( const ast::ObjectDecl * );
-		void previsit( const ast::AggregateDecl * );
-		void previsit( const ast::StructDecl * );
-		void previsit( const ast::EnumDecl * );
-		const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
-
-		const ast::ArrayType * previsit( const ast::ArrayType * );
-		const ast::PointerType * previsit( const ast::PointerType * );
-
-		const ast::ExprStmt *        previsit( const ast::ExprStmt * );
-		const ast::AsmExpr *         previsit( const ast::AsmExpr * );
-		const ast::AsmStmt *         previsit( const ast::AsmStmt * );
-		const ast::IfStmt *          previsit( const ast::IfStmt * );
-		const ast::WhileDoStmt *     previsit( const ast::WhileDoStmt * );
-		const ast::ForStmt *         previsit( const ast::ForStmt * );
-		const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
-		const ast::CaseClause *      previsit( const ast::CaseClause * );
-		const ast::BranchStmt *      previsit( const ast::BranchStmt * );
-		const ast::ReturnStmt *      previsit( const ast::ReturnStmt * );
-		const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
-		const ast::CatchClause *     previsit( const ast::CatchClause * );
-		const ast::CatchClause *     postvisit( const ast::CatchClause * );
-		const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
-		const ast::WithStmt *        previsit( const ast::WithStmt * );
-
-		const ast::SingleInit *      previsit( const ast::SingleInit * );
-		const ast::ListInit *        previsit( const ast::ListInit * );
-		const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
-
-		void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
-
-		void beginScope() { managedTypes.beginScope(); }
-		void endScope() { managedTypes.endScope(); }
-		bool on_error(ast::ptr<ast::Decl> & decl);
-	};
-	// size_t Resolver::traceId = Stats::Heap::new_stacktrace_id("Resolver");
-
-	InitTweak::ManagedTypes Resolver::managedTypes;
-
-	void resolve( ast::TranslationUnit& translationUnit ) {
-		ast::Pass< Resolver >::run( translationUnit, translationUnit.global );
-	}
-
-	ast::ptr< ast::Init > resolveCtorInit(
-		const ast::ConstructorInit * ctorInit, const ResolveContext & context
-	) {
-		assert( ctorInit );
-		ast::Pass< Resolver > resolver( context );
-		return ctorInit->accept( resolver );
-	}
-
-	const ast::Expr * resolveStmtExpr(
-		const ast::StmtExpr * stmtExpr, const ResolveContext & context
-	) {
-		assert( stmtExpr );
-		ast::Pass< Resolver > resolver( context );
-		auto ret = mutate(stmtExpr->accept(resolver));
-		strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
-		return ret;
-	}
-
-	namespace {
-		const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ResolveContext & context) {
-			std::string name = attr->normalizedName();
-			if (name == "constructor" || name == "destructor") {
-				if (attr->params.size() == 1) {
-					auto arg = attr->params.front();
-					auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), context );
-					auto result = eval(arg);
-
-					auto mutAttr = mutate(attr);
-					mutAttr->params.front() = resolved;
-					if (! result.hasKnownValue) {
-						SemanticWarning(loc, Warning::GccAttributes,
-							toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
-					}
-					else {
-						auto priority = result.knownValue;
-						if (priority < 101) {
-							SemanticWarning(loc, Warning::GccAttributes,
-								toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
-						} else if (priority < 201 && ! buildingLibrary()) {
-							SemanticWarning(loc, Warning::GccAttributes,
-								toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
-						}
-					}
-					return mutAttr;
-				} else if (attr->params.size() > 1) {
-					SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
-				} else {
-					SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
-				}
-			}
-			return attr;
-		}
-	}
-
-	const ast::FunctionDecl * Resolver::previsit( const ast::FunctionDecl * functionDecl ) {
-		GuardValue( functionReturn );
-
-		assert (functionDecl->unique());
-		if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) {
-			SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations");
-		}
-
-		if (!functionDecl->isTypeFixed) {
-			auto mutDecl = mutate(functionDecl);
-			auto mutType = mutDecl->type.get_and_mutate();
-
-			for (auto & attr: mutDecl->attributes) {
-				attr = handleAttribute(mutDecl->location, attr, context );
-			}
-
-			// handle assertions
-
-			symtab.enterScope();
-			mutType->forall.clear();
-			mutType->assertions.clear();
-			for (auto & typeParam : mutDecl->type_params) {
-				symtab.addType(typeParam);
-				mutType->forall.emplace_back(new ast::TypeInstType(typeParam));
-			}
-			for (auto & asst : mutDecl->assertions) {
-				asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), context);
-				symtab.addId(asst);
-				mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
-			}
-
-			// temporarily adds params to symbol table.
-			// actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl)
-
-			std::vector<ast::ptr<ast::Type>> paramTypes;
-			std::vector<ast::ptr<ast::Type>> returnTypes;
-
-			for (auto & param : mutDecl->params) {
-				param = fixObjectType(param.strict_as<ast::ObjectDecl>(), context);
-				symtab.addId(param);
-				paramTypes.emplace_back(param->get_type());
-			}
-			for (auto & ret : mutDecl->returns) {
-				ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), context);
-				returnTypes.emplace_back(ret->get_type());
-			}
-			// since function type in decl is just a view of param types, need to update that as well
-			mutType->params = std::move(paramTypes);
-			mutType->returns = std::move(returnTypes);
-
-			auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
-
-			std::list<ast::ptr<ast::Stmt>> newStmts;
-			resolveWithExprs (mutDecl->withExprs, newStmts);
-
-			if (mutDecl->stmts) {
-				auto mutStmt = mutDecl->stmts.get_and_mutate();
-				mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts));
-				mutDecl->stmts = mutStmt;
-			}
-
-			symtab.leaveScope();
-
-			mutDecl->type = renamedType;
-			mutDecl->mangleName = Mangle::mangle(mutDecl);
-			mutDecl->isTypeFixed = true;
-			functionDecl = mutDecl;
-		}
-		managedTypes.handleDWT(functionDecl);
-
-		functionReturn = extractResultType( functionDecl->type );
-		return functionDecl;
-	}
-
-	const ast::FunctionDecl * Resolver::postvisit( const ast::FunctionDecl * functionDecl ) {
-		// default value expressions have an environment which shouldn't be there and trips up
-		// later passes.
-		assert( functionDecl->unique() );
-		ast::FunctionType * mutType = mutate( functionDecl->type.get() );
-
-		for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
-			if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
-				if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
-					if ( init->value->env == nullptr ) continue;
-					// clone initializer minus the initializer environment
-					auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
-					auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
-					auto mutValue = mutate( mutInit->value.get() );
-
-					mutValue->env = nullptr;
-					mutInit->value = mutValue;
-					mutParam->init = mutInit;
-					mutType->params[i] = mutParam;
-
-					assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
-				}
-			}
-		}
-		mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
-		return functionDecl;
-	}
-
-	const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) {
-		// To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
-		// class-variable `initContext` is changed multiple times because the LHS is analyzed
-		// twice. The second analysis changes `initContext` because a function type can contain
-		// object declarations in the return and parameter types. Therefore each value of
-		// `initContext` is retained so the type on the first analysis is preserved and used for
-		// selecting the RHS.
-		GuardValue( currentObject );
-
-		if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
-			// enumerator initializers should not use the enum type to initialize, since the
-			// enum type is still incomplete at this point. Use `int` instead.
-
-			if ( auto enumBase = dynamic_cast< const ast::EnumInstType * >
-				( objectDecl->get_type() )->base->base ) {
-				objectDecl = fixObjectType( objectDecl, context );
-				currentObject = ast::CurrentObject{
-					objectDecl->location,
-					enumBase
-				};
-			} else {
-				objectDecl = fixObjectType( objectDecl, context );
-				currentObject = ast::CurrentObject{
-					objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
-			}
-
-		}
-		else {
-			if ( !objectDecl->isTypeFixed ) {
-				auto newDecl = fixObjectType(objectDecl, context);
-				auto mutDecl = mutate(newDecl);
-
-				// generate CtorInit wrapper when necessary.
-				// in certain cases, fixObjectType is called before reaching
-				// 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 ) ) ) ) {
-					// constructed objects cannot be designated
-					if ( InitTweak::isDesignated( mutDecl->init ) ) {
-						ast::Pass<ResolveDesignators> res( context );
-						maybe_accept( mutDecl->init.get(), res );
-						if ( !res.core.result ) {
-							SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object.\n"
-										   "If this is really what you want, initialize with @=." );
-						}
-					}
-					// constructed objects should not have initializers nested too deeply
-					if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
-
-					mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
-				}
-
-				objectDecl = mutDecl;
-			}
-			currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
-		}
-
-		return objectDecl;
-	}
-
-	void Resolver::previsit( const ast::AggregateDecl * _aggDecl ) {
-		auto aggDecl = mutate(_aggDecl);
-		assertf(aggDecl == _aggDecl, "type declarations must be unique");
-
-		for (auto & member: aggDecl->members) {
-			// nested type decls are hoisted already. no need to do anything
-			if (auto obj = member.as<ast::ObjectDecl>()) {
-				member = fixObjectType(obj, context);
-			}
-		}
-	}
-
-	void Resolver::previsit( const ast::StructDecl * structDecl ) {
-		previsit(static_cast<const ast::AggregateDecl *>(structDecl));
-		managedTypes.handleStruct(structDecl);
-	}
-
-	void Resolver::previsit( const ast::EnumDecl * ) {
-		// in case we decide to allow nested enums
-		GuardValue( inEnumDecl );
-		inEnumDecl = true;
-		// don't need to fix types for enum fields
-	}
-
-	const ast::StaticAssertDecl * Resolver::previsit(
-		const ast::StaticAssertDecl * assertDecl
-	) {
-		return ast::mutate_field(
-			assertDecl, &ast::StaticAssertDecl::cond,
-			findIntegralExpression( assertDecl->cond, context ) );
-	}
-
-	template< typename PtrType >
-	const PtrType * handlePtrType( const PtrType * type, const ResolveContext & context ) {
-		if ( type->dimension ) {
-			const ast::Type * sizeType = context.global.sizeType.get();
-			ast::ptr< ast::Expr > dimension = findSingleExpression( type->dimension, sizeType, context );
-			assertf(dimension->env->empty(), "array dimension expr has nonempty env");
-			dimension.get_and_mutate()->env = nullptr;
-			ast::mutate_field( type, &PtrType::dimension, dimension );
-		}
-		return type;
-	}
-
-	const ast::ArrayType * Resolver::previsit( const ast::ArrayType * at ) {
-		return handlePtrType( at, context );
-	}
-
-	const ast::PointerType * Resolver::previsit( const ast::PointerType * pt ) {
-		return handlePtrType( pt, context );
-	}
-
-	const ast::ExprStmt * Resolver::previsit( const ast::ExprStmt * exprStmt ) {
-		visit_children = false;
-		assertf( exprStmt->expr, "ExprStmt has null expression in resolver" );
-
-		return ast::mutate_field(
-			exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, context ) );
-	}
-
-	const ast::AsmExpr * Resolver::previsit( const ast::AsmExpr * asmExpr ) {
-		visit_children = false;
-
-		asmExpr = ast::mutate_field(
-			asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, context ) );
-
-		return asmExpr;
-	}
-
-	const ast::AsmStmt * Resolver::previsit( const ast::AsmStmt * asmStmt ) {
-		visitor->maybe_accept( asmStmt, &ast::AsmStmt::input );
-		visitor->maybe_accept( asmStmt, &ast::AsmStmt::output );
-		visit_children = false;
-		return asmStmt;
-	}
-
-	const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) {
-		return ast::mutate_field(
-			ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) );
-	}
-
-	const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) {
-		return ast::mutate_field(
-			whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) );
-	}
-
-	const ast::ForStmt * Resolver::previsit( const ast::ForStmt * forStmt ) {
-		if ( forStmt->cond ) {
-			forStmt = ast::mutate_field(
-				forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, context ) );
-		}
-
-		if ( forStmt->inc ) {
-			forStmt = ast::mutate_field(
-				forStmt, &ast::ForStmt::inc, findVoidExpression( forStmt->inc, context ) );
-		}
-
-		return forStmt;
-	}
-
-	const ast::SwitchStmt * Resolver::previsit( const ast::SwitchStmt * switchStmt ) {
-		GuardValue( currentObject );
-		switchStmt = ast::mutate_field(
-			switchStmt, &ast::SwitchStmt::cond,
-			findIntegralExpression( switchStmt->cond, context ) );
-		currentObject = ast::CurrentObject{ switchStmt->location, switchStmt->cond->result };
-		return switchStmt;
-	}
-
-	const ast::CaseClause * Resolver::previsit( const ast::CaseClause * caseStmt ) {
-		if ( caseStmt->cond ) {
-			std::deque< ast::InitAlternative > initAlts = currentObject.getOptions();
-			assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral "
-				"expression." );
-
-			ast::ptr< ast::Expr > untyped =
-				new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
-			ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, context );
-
-			// case condition cannot have a cast in C, so it must be removed here, regardless of
-			// whether it would perform a conversion.
-			if ( const ast::CastExpr * castExpr = newExpr.as< ast::CastExpr >() ) {
-				swap_and_save_env( newExpr, castExpr->arg );
-			}
-
-			caseStmt = ast::mutate_field( caseStmt, &ast::CaseClause::cond, newExpr );
-		}
-		return caseStmt;
-	}
-
-	const ast::BranchStmt * Resolver::previsit( const ast::BranchStmt * branchStmt ) {
-		visit_children = false;
-		// must resolve the argument of a computed goto
-		if ( branchStmt->kind == ast::BranchStmt::Goto && branchStmt->computedTarget ) {
-			// computed goto argument is void*
-			ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} };
-			branchStmt = ast::mutate_field(
-				branchStmt, &ast::BranchStmt::computedTarget,
-				findSingleExpression( branchStmt->computedTarget, target, context ) );
-		}
-		return branchStmt;
-	}
-
-	const ast::ReturnStmt * Resolver::previsit( const ast::ReturnStmt * returnStmt ) {
-		visit_children = false;
-		if ( returnStmt->expr ) {
-			returnStmt = ast::mutate_field(
-				returnStmt, &ast::ReturnStmt::expr,
-				findSingleExpression( returnStmt->expr, functionReturn, context ) );
-		}
-		return returnStmt;
-	}
-
-	const ast::ThrowStmt * Resolver::previsit( const ast::ThrowStmt * throwStmt ) {
-		visit_children = false;
-		if ( throwStmt->expr ) {
-			const ast::StructDecl * exceptionDecl =
-				symtab.lookupStruct( "__cfaehm_base_exception_t" );
-			assert( exceptionDecl );
-			ast::ptr< ast::Type > exceptType =
-				new ast::PointerType{ new ast::StructInstType{ exceptionDecl } };
-			throwStmt = ast::mutate_field(
-				throwStmt, &ast::ThrowStmt::expr,
-				findSingleExpression( throwStmt->expr, exceptType, context ) );
-		}
-		return throwStmt;
-	}
-
-	const ast::CatchClause * Resolver::previsit( const ast::CatchClause * catchClause ) {
-		// Until we are very sure this invarent (ifs that move between passes have then)
-		// holds, check it. This allows a check for when to decode the mangling.
-		if ( auto ifStmt = catchClause->body.as<ast::IfStmt>() ) {
-			assert( ifStmt->then );
-		}
-		// Encode the catchStmt so the condition can see the declaration.
-		if ( catchClause->cond ) {
-			ast::CatchClause * clause = mutate( catchClause );
-			clause->body = new ast::IfStmt( clause->location, clause->cond, nullptr, clause->body );
-			clause->cond = nullptr;
-			return clause;
-		}
-		return catchClause;
-	}
-
-	const ast::CatchClause * Resolver::postvisit( const ast::CatchClause * catchClause ) {
-		// Decode the catchStmt so everything is stored properly.
-		const ast::IfStmt * ifStmt = catchClause->body.as<ast::IfStmt>();
-		if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
-			assert( ifStmt->cond );
-			assert( ifStmt->else_ );
-			ast::CatchClause * clause = ast::mutate( catchClause );
-			clause->cond = ifStmt->cond;
-			clause->body = ifStmt->else_;
-			// ifStmt should be implicately deleted here.
-			return clause;
-		}
-		return catchClause;
-	}
-
-	const ast::WaitForStmt * Resolver::previsit( const ast::WaitForStmt * stmt ) {
-		visit_children = false;
-
-		// Resolve all clauses first
-		for ( unsigned i = 0; i < stmt->clauses.size(); ++i ) {
-			const ast::WaitForClause & clause = *stmt->clauses[i];
-
-			ast::TypeEnvironment env;
-			CandidateFinder funcFinder( context, env );
-
-			// Find all candidates for a function in canonical form
-			funcFinder.find( clause.target, ResolveMode::withAdjustment() );
-
-			if ( funcFinder.candidates.empty() ) {
-				stringstream ss;
-				ss << "Use of undeclared indentifier '";
-				ss << clause.target.strict_as< ast::NameExpr >()->name;
-				ss << "' in call to waitfor";
-				SemanticError( stmt->location, ss.str() );
-			}
-
-			if ( clause.target_args.empty() ) {
-				SemanticError( stmt->location,
-					"Waitfor clause must have at least one mutex parameter");
-			}
-
-			// Find all alternatives for all arguments in canonical form
-			std::vector< CandidateFinder > argFinders =
-				funcFinder.findSubExprs( clause.target_args );
-
-			// List all combinations of arguments
-			std::vector< CandidateList > possibilities;
-			combos( argFinders.begin(), argFinders.end(), back_inserter( possibilities ) );
-
-			// For every possible function:
-			// * try matching the arguments to the parameters, not the other way around because
-			//   more arguments than parameters
-			CandidateList funcCandidates;
-			std::vector< CandidateList > argsCandidates;
-			SemanticErrorException errors;
-			for ( CandidateRef & func : funcFinder.candidates ) {
-				try {
-					auto pointerType = dynamic_cast< const ast::PointerType * >(
-						func->expr->result->stripReferences() );
-					if ( ! pointerType ) {
-						SemanticError( stmt->location, func->expr->result.get(),
-							"candidate not viable: not a pointer type\n" );
-					}
-
-					auto funcType = pointerType->base.as< ast::FunctionType >();
-					if ( ! funcType ) {
-						SemanticError( stmt->location, func->expr->result.get(),
-							"candidate not viable: not a function type\n" );
-					}
-
-					{
-						auto param    = funcType->params.begin();
-						auto paramEnd = funcType->params.end();
-
-						if( ! nextMutex( param, paramEnd ) ) {
-							SemanticError( stmt->location, funcType,
-								"candidate function not viable: no mutex parameters\n");
-						}
-					}
-
-					CandidateRef func2{ new Candidate{ *func } };
-					// strip reference from function
-					func2->expr = referenceToRvalueConversion( func->expr, func2->cost );
-
-					// Each argument must be matched with a parameter of the current candidate
-					for ( auto & argsList : possibilities ) {
-						try {
-							// Declare data structures needed for resolution
-							ast::OpenVarSet open;
-							ast::AssertionSet need, have;
-							ast::TypeEnvironment resultEnv{ func->env };
-							// Add all type variables as open so that those not used in the
-							// parameter list are still considered open
-							resultEnv.add( funcType->forall );
-
-							// load type variables from arguments into one shared space
-							for ( auto & arg : argsList ) {
-								resultEnv.simpleCombine( arg->env );
-							}
-
-							// Make sure we don't widen any existing bindings
-							resultEnv.forbidWidening();
-
-							// Find any unbound type variables
-							resultEnv.extractOpenVars( open );
-
-							auto param = funcType->params.begin();
-							auto paramEnd = funcType->params.end();
-
-							unsigned n_mutex_param = 0;
-
-							// For every argument of its set, check if it matches one of the
-							// parameters. The order is important
-							for ( auto & arg : argsList ) {
-								// Ignore non-mutex arguments
-								if ( ! nextMutex( param, paramEnd ) ) {
-									// We ran out of parameters but still have arguments.
-									// This function doesn't match
-									SemanticError( stmt->location, funcType,
-										toString("candidate function not viable: too many mutex "
-										"arguments, expected ", n_mutex_param, "\n" ) );
-								}
-
-								++n_mutex_param;
-
-								// Check if the argument matches the parameter type in the current scope.
-								// ast::ptr< ast::Type > paramType = (*param)->get_type();
-
-								if (
-									! unify(
-										arg->expr->result, *param, resultEnv, need, have, open )
-								) {
-									// Type doesn't match
-									stringstream ss;
-									ss << "candidate function not viable: no known conversion "
-										"from '";
-									ast::print( ss, *param );
-									ss << "' to '";
-									ast::print( ss, arg->expr->result );
-									ss << "' with env '";
-									ast::print( ss, resultEnv );
-									ss << "'\n";
-									SemanticError( stmt->location, funcType, ss.str() );
-								}
-
-								++param;
-							}
-
-							// All arguments match!
-
-							// Check if parameters are missing
-							if ( nextMutex( param, paramEnd ) ) {
-								do {
-									++n_mutex_param;
-									++param;
-								} while ( nextMutex( param, paramEnd ) );
-
-								// We ran out of arguments but still have parameters left; this
-								// function doesn't match
-								SemanticError( stmt->location, funcType,
-									toString( "candidate function not viable: too few mutex "
-									"arguments, expected ", n_mutex_param, "\n" ) );
-							}
-
-							// All parameters match!
-
-							// Finish the expressions to tie in proper environments
-							finishExpr( func2->expr, resultEnv );
-							for ( CandidateRef & arg : argsList ) {
-								finishExpr( arg->expr, resultEnv );
-							}
-
-							// This is a match, store it and save it for later
-							funcCandidates.emplace_back( std::move( func2 ) );
-							argsCandidates.emplace_back( std::move( argsList ) );
-
-						} catch ( SemanticErrorException & e ) {
-							errors.append( e );
-						}
-					}
-				} catch ( SemanticErrorException & e ) {
-					errors.append( e );
-				}
-			}
-
-			// Make sure correct number of arguments
-			if( funcCandidates.empty() ) {
-				SemanticErrorException top( stmt->location,
-					"No alternatives for function in call to waitfor" );
-				top.append( errors );
-				throw top;
-			}
-
-			if( argsCandidates.empty() ) {
-				SemanticErrorException top( stmt->location,
-					"No alternatives for arguments in call to waitfor" );
-				top.append( errors );
-				throw top;
-			}
-
-			if( funcCandidates.size() > 1 ) {
-				SemanticErrorException top( stmt->location,
-					"Ambiguous function in call to waitfor" );
-				top.append( errors );
-				throw top;
-			}
-			if( argsCandidates.size() > 1 ) {
-				SemanticErrorException top( stmt->location,
-					"Ambiguous arguments in call to waitfor" );
-				top.append( errors );
-				throw top;
-			}
-			// TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
-
-			// build new clause
-			auto clause2 = new ast::WaitForClause( clause.location );
-
-			clause2->target = funcCandidates.front()->expr;
-
-			clause2->target_args.reserve( clause.target_args.size() );
-			const ast::StructDecl * decl_monitor = symtab.lookupStruct( "monitor$" );
-			for ( auto arg : argsCandidates.front() ) {
-				const auto & loc = stmt->location;
-
-				ast::Expr * init = new ast::CastExpr( loc,
-					new ast::UntypedExpr( loc,
-						new ast::NameExpr( loc, "get_monitor" ),
-						{ arg->expr }
-					),
-					new ast::PointerType(
-						new ast::StructInstType(
-							decl_monitor
-						)
-					)
-				);
-
-				clause2->target_args.emplace_back( findSingleExpression( init, context ) );
-			}
-
-			// Resolve the conditions as if it were an IfStmt, statements normally
-			clause2->when_cond = findSingleExpression( clause.when_cond, context );
-			clause2->stmt = clause.stmt->accept( *visitor );
-
-			// set results into stmt
-			auto n = mutate( stmt );
-			n->clauses[i] = clause2;
-			stmt = n;
-		}
-
-		if ( stmt->timeout_stmt ) {
-			// resolve the timeout as a size_t, the conditions like IfStmt, and stmts normally
-			ast::ptr< ast::Type > target =
-				new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
-			auto timeout_time = findSingleExpression( stmt->timeout_time, target, context );
-			auto timeout_cond = findSingleExpression( stmt->timeout_cond, context );
-			auto timeout_stmt = stmt->timeout_stmt->accept( *visitor );
-
-			// set results into stmt
-			auto n = mutate( stmt );
-			n->timeout_time = std::move( timeout_time );
-			n->timeout_cond = std::move( timeout_cond );
-			n->timeout_stmt = std::move( timeout_stmt );
-			stmt = n;
-		}
-
-		if ( stmt->else_stmt ) {
-			// resolve the condition like IfStmt, stmts normally
-			auto else_cond = findSingleExpression( stmt->else_cond, context );
-			auto else_stmt = stmt->else_stmt->accept( *visitor );
-
-			// set results into stmt
-			auto n = mutate( stmt );
-			n->else_cond = std::move( else_cond );
-			n->else_stmt = std::move( else_stmt );
-			stmt = n;
-		}
-
-		return stmt;
-	}
-
-	const ast::WithStmt * Resolver::previsit( const ast::WithStmt * withStmt ) {
-		auto mutStmt = mutate(withStmt);
-		resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
-		return mutStmt;
-	}
-
-	void Resolver::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
-		for (auto & expr : exprs) {
-			// only struct- and union-typed expressions are viable candidates
-			expr = findKindExpression( expr, context, structOrUnion, "with expression" );
-
-			// if with expression might be impure, create a temporary so that it is evaluated once
-			if ( Tuples::maybeImpure( expr ) ) {
-				static UniqueName tmpNamer( "_with_tmp_" );
-				const CodeLocation loc = expr->location;
-				auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) );
-				expr = new ast::VariableExpr( loc, tmp );
-				stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) );
-				if ( InitTweak::isConstructable( tmp->type ) ) {
-					// generate ctor/dtor and resolve them
-					tmp->init = InitTweak::genCtorInit( loc, tmp );
-				}
-				// since tmp is freshly created, this should modify tmp in-place
-				tmp->accept( *visitor );
-			}
-			else if (expr->env && expr->env->empty()) {
-				expr = ast::mutate_field(expr.get(), &ast::Expr::env, nullptr);
-			}
-		}
-	}
-
-
-	const ast::SingleInit * Resolver::previsit( const ast::SingleInit * singleInit ) {
-		visit_children = false;
-		// resolve initialization using the possibilities as determined by the `currentObject`
-		// cursor.
-		ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{
-			singleInit->location, singleInit->value, currentObject.getOptions() };
-		ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, context );
-		const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
-
-		// move cursor to the object that is actually initialized
-		currentObject.setNext( initExpr->designation );
-
-		// discard InitExpr wrapper and retain relevant pieces.
-		// `initExpr` may have inferred params in the case where the expression specialized a
-		// function pointer, and newExpr may already have inferParams of its own, so a simple
-		// swap is not sufficient
-		ast::Expr::InferUnion inferred = initExpr->inferred;
-		swap_and_save_env( newExpr, initExpr->expr );
-		newExpr.get_and_mutate()->inferred.splice( std::move(inferred) );
-
-		// get the actual object's type (may not exactly match what comes back from the resolver
-		// due to conversions)
-		const ast::Type * initContext = currentObject.getCurrentType();
-
-		removeExtraneousCast( newExpr );
-
-		// check if actual object's type is char[]
-		if ( auto at = dynamic_cast< const ast::ArrayType * >( initContext ) ) {
-			if ( isCharType( at->base ) ) {
-				// check if the resolved type is char*
-				if ( auto pt = newExpr->result.as< ast::PointerType >() ) {
-					if ( isCharType( pt->base ) ) {
-						// strip cast if we're initializing a char[] with a char*
-						// e.g. char x[] = "hello"
-						if ( auto ce = newExpr.as< ast::CastExpr >() ) {
-							swap_and_save_env( newExpr, ce->arg );
-						}
-					}
-				}
-			}
-		}
-
-		// move cursor to next object in preparation for next initializer
-		currentObject.increment();
-
-		// set initializer expression to resolved expression
-		return ast::mutate_field( singleInit, &ast::SingleInit::value, std::move(newExpr) );
-	}
-
-	const ast::ListInit * Resolver::previsit( const ast::ListInit * listInit ) {
-		// move cursor into brace-enclosed initializer-list
-		currentObject.enterListInit( listInit->location );
-
-		assert( listInit->designations.size() == listInit->initializers.size() );
-		for ( unsigned i = 0; i < listInit->designations.size(); ++i ) {
-			// iterate designations and initializers in pairs, moving the cursor to the current
-			// designated object and resolving the initializer against that object
-			listInit = ast::mutate_field_index(
-				listInit, &ast::ListInit::designations, i,
-				currentObject.findNext( listInit->designations[i] ) );
-			listInit = ast::mutate_field_index(
-				listInit, &ast::ListInit::initializers, i,
-				listInit->initializers[i]->accept( *visitor ) );
-		}
-
-		// move cursor out of brace-enclosed initializer-list
-		currentObject.exitListInit();
-
-		visit_children = false;
-		return listInit;
-	}
-
-	const ast::ConstructorInit * Resolver::previsit( const ast::ConstructorInit * ctorInit ) {
-		visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
-		visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
-
-		// found a constructor - can get rid of C-style initializer
-		// xxx - Rob suggests this field is dead code
-		ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr );
-
-		// intrinsic single-parameter constructors and destructors do nothing. Since this was
-		// implicitly generated, there's no way for it to have side effects, so get rid of it to
-		// clean up generated code
-		if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
-			ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::ctor, nullptr );
-		}
-		if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
-			ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::dtor, nullptr );
-		}
-
-		return ctorInit;
-	}
-
-	// suppress error on autogen functions and mark invalid autogen as deleted.
-	bool Resolver::on_error(ast::ptr<ast::Decl> & decl) {
-		if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
-			// xxx - can intrinsic gen ever fail?
-			if (functionDecl->linkage == ast::Linkage::AutoGen) {
-				auto mutDecl = mutate(functionDecl);
-				mutDecl->isDeleted = true;
-				mutDecl->stmts = nullptr;
-				decl = mutDecl;
-				return false;
-			}
-		}
-		return true;
-	}
+	}
+	return true;
+}
 
 } // namespace ResolvExpr
Index: src/SymTab/GenImplicitCall.cpp
===================================================================
--- src/SymTab/GenImplicitCall.cpp	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/SymTab/GenImplicitCall.cpp	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// GenImplicitCall.hpp --
+// GenImplicitCall.cpp -- Generate code for implicit operator calls.
 //
 // Author           : Andrew Beach
@@ -31,8 +31,9 @@
 namespace {
 
-template< typename OutIter >
+using Inserter = std::back_insert_iterator<std::list<ast::ptr<ast::Stmt>>>;
+
 ast::ptr< ast::Stmt > genCall(
 	InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
-	const CodeLocation & loc, const std::string & fname, OutIter && out,
+	const CodeLocation & loc, const std::string & fname, Inserter && out,
 	const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
 
@@ -41,8 +42,7 @@
 /// optionally returns a statement which must be inserted prior to the containing loop, if
 /// there is one
-template< typename OutIter >
 ast::ptr< ast::Stmt > genScalarCall(
 	InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
-	const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type,
+	const CodeLocation & loc, std::string fname, Inserter && out, const ast::Type * type,
 	const ast::Type * addCast = nullptr
 ) {
@@ -97,8 +97,7 @@
 /// Store in out a loop which calls fname on each element of the array with srcParam and
 /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0
-template< typename OutIter >
 void genArrayCall(
 	InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
-	const CodeLocation & loc, const std::string & fname, OutIter && out,
+	const CodeLocation & loc, const std::string & fname, Inserter && out,
 	const ast::ArrayType * array, const ast::Type * addCast = nullptr,
 	LoopDirection forward = LoopForward
@@ -166,18 +165,17 @@
 }
 
-template< typename OutIter >
 ast::ptr< ast::Stmt > genCall(
 	InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
-	const CodeLocation & loc, const std::string & fname, OutIter && out,
+	const CodeLocation & loc, const std::string & fname, Inserter && out,
 	const ast::Type * type, const ast::Type * addCast, LoopDirection forward
 ) {
 	if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
 		genArrayCall(
-			srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast,
+			srcParam, dstParam, loc, fname, std::forward< Inserter&& >( out ), at, addCast,
 			forward );
 		return {};
 	} else {
 		return genScalarCall(
-			srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast );
+			srcParam, dstParam, loc, fname, std::forward< Inserter&& >( out ), type, addCast );
 	}
 }
@@ -185,5 +183,5 @@
 } // namespace
 
-ast::ptr< ast::Stmt > genImplicitCall(
+const ast::Stmt * genImplicitCall(
 	InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
 	const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
@@ -191,5 +189,5 @@
 ) {
 	// unnamed bit fields are not copied as they cannot be accessed
-	if ( isUnnamedBitfield( obj ) ) return {};
+	if ( isUnnamedBitfield( obj ) ) return nullptr;
 
 	ast::ptr< ast::Type > addCast;
@@ -199,22 +197,18 @@
 	}
 
-	std::vector< ast::ptr< ast::Stmt > > stmts;
+	std::list< ast::ptr< ast::Stmt > > stmts;
 	genCall(
 		srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );
 
-	if ( stmts.empty() ) {
-		return {};
-	} else if ( stmts.size() == 1 ) {
-		const ast::Stmt * callStmt = stmts.front();
-		if ( addCast ) {
-			// implicitly generated ctor/dtor calls should be wrapped so that later passes are
-			// aware they were generated.
-			callStmt = new ast::ImplicitCtorDtorStmt( callStmt->location, callStmt );
-		}
-		return callStmt;
-	} else {
-		assert( false );
-		return {};
-	}
+	if ( stmts.empty() ) return nullptr;
+	assert( stmts.size() == 1 );
+
+	const ast::Stmt * callStmt = stmts.front().release();
+	// Implicitly generated ctor/dtor calls should be wrapped so that
+	// later passes are aware they were generated.
+	if ( addCast ) {
+		callStmt = new ast::ImplicitCtorDtorStmt( callStmt->location, callStmt );
+	}
+	return callStmt;
 }
 
@@ -226,4 +220,2 @@
 // compile-command: "make install" //
 // End: //
-
-
Index: src/SymTab/GenImplicitCall.hpp
===================================================================
--- src/SymTab/GenImplicitCall.hpp	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/SymTab/GenImplicitCall.hpp	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// GenImplicitCall.hpp --
+// GenImplicitCall.hpp -- Generate code for implicit operator calls.
 //
 // Author           : Andrew Beach
@@ -25,5 +25,5 @@
 /// Returns a generated call expression to function fname with srcParam and
 /// dstParam. Intended to be used with generated ?=?, ?{}, and ^?{} calls.
-ast::ptr<ast::Stmt> genImplicitCall(
+const ast::Stmt * genImplicitCall(
 	InitTweak::InitExpander & srcParam, const ast::Expr * dstParam,
 	const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/Validate/Autogen.cpp	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -133,6 +133,5 @@
 	/// Generates a single struct member operation.
 	/// (constructor call, destructor call, assignment call)
-	// This is managed because it uses another helper that returns a ast::ptr.
-	ast::ptr<ast::Stmt> makeMemberOp(
+	const ast::Stmt * makeMemberOp(
 		const CodeLocation& location,
 		const ast::ObjectDecl * dstParam, const ast::Expr * src,
@@ -525,5 +524,5 @@
 }
 
-ast::ptr<ast::Stmt> StructFuncGenerator::makeMemberOp(
+const ast::Stmt * StructFuncGenerator::makeMemberOp(
 		const CodeLocation& location, const ast::ObjectDecl * dstParam,
 		const ast::Expr * src, const ast::ObjectDecl * field,
@@ -540,5 +539,5 @@
 		)
 	);
-	auto stmt = genImplicitCall(
+	const ast::Stmt * stmt = genImplicitCall(
 		srcParam, dstSelect, location, func->name,
 		field, direction
@@ -598,9 +597,9 @@
 			location, field, new ast::VariableExpr( location, srcParam )
 		) : nullptr;
-		ast::ptr<ast::Stmt> stmt =
+		const ast::Stmt * stmt =
 			makeMemberOp( location, dstParam, srcSelect, field, func, direction );
 
 		if ( nullptr != stmt ) {
-			stmts->kids.push_back( stmt );
+			stmts->kids.emplace_back( stmt );
 		}
 	}
@@ -623,5 +622,5 @@
 	for ( auto param = params.begin() + 1 ; current != end ; ++current ) {
 		const ast::ptr<ast::Decl> & member = *current;
-		ast::ptr<ast::Stmt> stmt = nullptr;
+		const ast::Stmt * stmt = nullptr;
 		auto field = member.as<ast::ObjectDecl>();
 		// Not sure why it could be null.
@@ -641,5 +640,5 @@
 
 		if ( nullptr != stmt ) {
-			stmts->kids.push_back( stmt );
+			stmts->kids.emplace_back( stmt );
 		}
 	}
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ src/main.cc	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -181,4 +181,5 @@
 
 static void _Signal(struct sigaction & act, int sig, int flags ) {
+	sigemptyset( &act.sa_mask );
 	act.sa_flags = flags;
 
Index: tests/.expect/attributes.arm64.txt
===================================================================
--- tests/.expect/attributes.arm64.txt	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/.expect/attributes.arm64.txt	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -6,5 +6,5 @@
 
 }
-struct __anonymous0 {
+struct __attribute__ ((unused)) __anonymous0 {
 };
 static inline void _X12_constructorFv_S12__anonymous0_autogen___1(struct __anonymous0 *_X4_dstS12__anonymous0_1);
Index: tests/.expect/attributes.x64.txt
===================================================================
--- tests/.expect/attributes.x64.txt	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/.expect/attributes.x64.txt	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -6,5 +6,5 @@
 
 }
-struct __anonymous0 {
+struct __attribute__ ((unused)) __anonymous0 {
 };
 static inline void _X12_constructorFv_S12__anonymous0_autogen___1(struct __anonymous0 *_X4_dstS12__anonymous0_1);
Index: tests/.expect/attributes.x86.txt
===================================================================
--- tests/.expect/attributes.x86.txt	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/.expect/attributes.x86.txt	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -6,5 +6,5 @@
 
 }
-struct __anonymous0 {
+struct __attribute__ ((unused)) __anonymous0 {
 };
 static inline void _X12_constructorFv_S12__anonymous0_autogen___1(struct __anonymous0 *_X4_dstS12__anonymous0_1);
Index: tests/collections/.expect/string-istream-manip.txt
===================================================================
--- tests/collections/.expect/string-istream-manip.txt	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/collections/.expect/string-istream-manip.txt	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -70,4 +70,14 @@
 14 
 15 
+16 get this line
+17 @# this line 1)-{}
+18 @# this line 1)-{}
+19 abc
+20 abc  
+21  d d
+
+d 
+22 		ZC44%
+23 		ZC44%
 1 yyyyyyyyyyyyyyyyyyyy
 2 abcxxx
@@ -85,2 +95,12 @@
 14 
 15 
+16 get this line
+17 @# this line 1)-{}
+18 @# this line 1)-{}
+19 abc
+20 abc  
+21  d d
+
+d 
+22 		ZC44%
+23 		ZC44%
Index: tests/collections/.in/string-istream-manip.txt
===================================================================
--- tests/collections/.in/string-istream-manip.txt	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/collections/.in/string-istream-manip.txt	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -38,4 +38,14 @@
 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwwwaaaaaaaawwwwwwww
 uuuuu
+get this line
+@# this line 1)-{}%
+@# this line 2)-{}%
+    "abc"
+'abc  '
+{ d d
+
+d }
+X		ZC44%Y
+X		ZC55%Y
 abc 
 cccccb 
@@ -45,2 +55,12 @@
 aaaaaaaaxxxxxxxxaabbccbbdddwwwbbbbbbbbwwwwwwwwaaaaaaaawwwwwwwwaaaaaaaawwwwwwww
 uuuuu
+get this line
+@# this line 1)-{}%
+@# this line 2)-{}%
+    "abc"
+'abc  '
+{ d d
+
+d }
+X		ZC44%Y
+X		ZC55%Y
Index: tests/collections/string-istream-manip.cfa
===================================================================
--- tests/collections/string-istream-manip.cfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/collections/string-istream-manip.cfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,194 +10,212 @@
 // The test cases that use plainjane(-) are exercising the via-manipulator code path,
 // just with trivial manipulation.
-static _Istream_Sstr plainjane( string     & s )  { return (_Istream_Sstr)@{  s, {{0p}, -1, {.flags.rwd : false}} }; }
+static _Istream_Sstr plainjane( string & s )  { return (_Istream_Sstr)@{  s, {{0p}, -1, {.flags.rwd : false}} }; }
 static _Istream_Rstr plainjane( string_res & s )  { return (_Istream_Rstr)@{ &s, {{0p}, -1, {.flags.rwd : false}} }; }
 
 static void forceStringHeapFreeSpaceTo(int desiredSize) {
-    for (1_000_000) {
-        string x = "a";
-        (void)x;
-      if (desiredSize == DEBUG_string_bytes_avail_until_gc(DEBUG_string_heap())) return;
-    }
-    sout | "Unable to force size" | desiredSize | "in 1,000,000 tries";
+	for (1_000_000) {
+		string x = "a";
+		(void)x;
+		if (desiredSize == DEBUG_string_bytes_avail_until_gc(DEBUG_string_heap())) return;
+	}
+	sout | "Unable to force size" | desiredSize | "in 1,000,000 tries";
 }
 
 int main() {
-    // These "pre" cases deal with issues analogous to the "pre" cases of io/manipulatorsInput.
-    // The acceptance criterion is simpler but driving the cases is harder.
-    // The tests just read strings and echo what they read; acceptance of simple echoing assures
-    // no spurious splitting merging.
-    // The lengths of the strings are chosen to match white-box knowledge of when the string layer
-    // has tor drive the cstring layer through a second iteration:
-    //  - for no-manip, lengths are near the room at end of string heap
-    //    (chosen target size of 9 showed the original bug on preS2, aligned with the other cases)
-    //  - for manip, lengths are near the auxiliary buffer size of 128
-    // Only first case repeats for string_res; rest run only from the passthru string layer.
-    // Similarly, the manipulator breadth isn't checked at the cstring layer either.
-    {
-        // S: string, no manipulator
-        void echoTillX(const char * casename) {
-            string s;
-            // loop assumes behaviour not tested until main-case #15:
-            // on reading nothing, the prior string value is left alone
-            do {
-                s = "";
-                forceStringHeapFreeSpaceTo(9);
-                sin | s;
-                sout | casename | s;
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preS1");
-        echoTillX("preS2");
-        echoTillX("preS3");
-        echoTillX("preS4");
-    }
-    {
-        // SMN: string, manipulator for no-op
-        void echoTillX(const char * casename) {
-            string s;
-            do {
-                s = "";
-                sin | plainjane( s );
-                sout | casename | s;
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preSMN1");
-        echoTillX("preSMN2");
-        echoTillX("preSMN3");
-        echoTillX("preSMN4");
-    }
-    {
-        // RMN: string_res, manipulator for no-op
-        void echoTillX(const char * casename) {
-            string_res s;
-            do {
-                s = "";
-                sin | plainjane( s );
-                sout | casename | s;
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preRMN1");
-        echoTillX("preRMN2");
-        echoTillX("preRMN3");
-        echoTillX("preRMN4");
-    }
-    {
-        // SMI: string, manipulator `incl`
-        void echoTillX(const char * casename) {
-            string s;
-            do {
-                s = "";
-                sin | skip("-\n");
-                sin | incl( ".:|# x", s );
-                sout | casename | " \"" | s | "\"";
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preSMI1");
-        echoTillX("preSMI2");
-        echoTillX("preSMI3");
-        echoTillX("preSMI4");
-    }
-    {
-        // SME: string, manipulator `excl`
-        void echoTillX(const char * casename) {
-            string s;
-            do {
-                s = "";
-                sin | skip("-\n");
-                sin | excl( "-\n", s );
-                sout | casename | " \"" | s | "\"";
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preSME1");
-        echoTillX("preSME2");
-        echoTillX("preSME3");
-        echoTillX("preSME4");
-    }
-    sin | skip("-\n");
-    {
-        // SMG: string, manipulator `getline`
-        void echoTillX(const char * casename) {
-            string s;
-            do {
-                s = "";
-                sin | getline( s );
-                sout | casename | s;
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-        }
-        echoTillX("preSMG1");
-        echoTillX("preSMG2");
-        echoTillX("preSMG3");
-        echoTillX("preSMG4");
-    }
-    {
-        // SMD: string, manipulator (`getline` with custom) delimiter
-        void echoTillX(const char * casename) {
-            string s;
-            do {
-                s = "";
-                sin | getline( s, '@' );
-                sout | casename | s;
-            } while ( size(s) > 0 && s[size(s)-1] != 'x' );
-            sin | skip(" \n");
-        }
-        echoTillX("preSMD1");
-        echoTillX("preSMD2");
-        echoTillX("preSMD3");
-        echoTillX("preSMD4");
-    }
-
-    /* Keep harmonized with io/manipulatorsInput */
-    {
-        string s = "yyyyyyyyyyyyyyyyyyyy";
-        char sk[] = "abc";
-        sin | "abc " | skip( sk ) | skip( 5 );          sout | "1" | s;
-        sin | s;                                        sout | "2" | s;
-        sin | ignore( s );                              sout | "3" | s;
-        sin | wdi( 8, s );                              sout | "4" | s;
-        sin | ignore( wdi( 8, s ) );                    sout | "5" | s;
-
-        sin | incl( "abc", s );                         sout | "6" | s;
-        sin | excl( "abc", s );                         sout | "7" | s;
-        sin | ignore( incl( "abc", s ) );               sout | "8" | s;
-        sin | ignore( excl( "abc", s ) );               sout | "9" | s;
-        sin | incl( "abc", wdi( 8, s ) );               sout | "10" | s;
-        sin | excl( "abc", wdi( 8, s ) );               sout | "11" | s;
-        sin | ignore( incl( "abc", wdi( 8, s ) ) );     sout | "12" | s;
-        sin | ignore( excl( "abc", wdi( 8, s ) ) );     sout | "13" | s;
+	// These "pre" cases deal with issues analogous to the "pre" cases of io/manipulatorsInput.
+	// The acceptance criterion is simpler but driving the cases is harder.
+	// The tests just read strings and echo what they read; acceptance of simple echoing assures
+	// no spurious splitting merging.
+	// The lengths of the strings are chosen to match white-box knowledge of when the string layer
+	// has tor drive the cstring layer through a second iteration:
+	//  - for no-manip, lengths are near the room at end of string heap
+	//	(chosen target size of 9 showed the original bug on preS2, aligned with the other cases)
+	//  - for manip, lengths are near the auxiliary buffer size of 128
+	// Only first case repeats for string_res; rest run only from the passthru string layer.
+	// Similarly, the manipulator breadth isn't checked at the cstring layer either.
+	{
+		// S: string, no manipulator
+		void echoTillX(const char * casename) {
+			string s;
+			// loop assumes behaviour not tested until main-case #15:
+			// on reading nothing, the prior string value is left alone
+			do {
+				s = "";
+				forceStringHeapFreeSpaceTo(9);
+				sin | s;
+				sout | casename | s;
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preS1");
+		echoTillX("preS2");
+		echoTillX("preS3");
+		echoTillX("preS4");
+	}
+	{
+		// SMN: string, manipulator for no-op
+		void echoTillX(const char * casename) {
+			string s;
+			do {
+				s = "";
+				sin | plainjane( s );
+				sout | casename | s;
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preSMN1");
+		echoTillX("preSMN2");
+		echoTillX("preSMN3");
+		echoTillX("preSMN4");
+	}
+	{
+		// RMN: string_res, manipulator for no-op
+		void echoTillX(const char * casename) {
+			string_res s;
+			do {
+				s = "";
+				sin | plainjane( s );
+				sout | casename | s;
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preRMN1");
+		echoTillX("preRMN2");
+		echoTillX("preRMN3");
+		echoTillX("preRMN4");
+	}
+	{
+		// SMI: string, manipulator `incl`
+		void echoTillX(const char * casename) {
+			string s;
+			do {
+				s = "";
+				sin | skip("-\n");
+				sin | incl( ".:|# x", s );
+				sout | casename | " \"" | s | "\"";
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preSMI1");
+		echoTillX("preSMI2");
+		echoTillX("preSMI3");
+		echoTillX("preSMI4");
+	}
+	{
+		// SME: string, manipulator `excl`
+		void echoTillX(const char * casename) {
+			string s;
+			do {
+				s = "";
+				sin | skip("-\n");
+				sin | excl( "-\n", s );
+				sout | casename | " \"" | s | "\"";
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preSME1");
+		echoTillX("preSME2");
+		echoTillX("preSME3");
+		echoTillX("preSME4");
+	}
+	sin | skip("-\n");
+	{
+		// SMG: string, manipulator `getline`
+		void echoTillX(const char * casename) {
+			string s;
+			do {
+				s = "";
+				sin | getline( s );
+				sout | casename | s;
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+		}
+		echoTillX("preSMG1");
+		echoTillX("preSMG2");
+		echoTillX("preSMG3");
+		echoTillX("preSMG4");
+	}
+	{
+		// SMD: string, manipulator (`getline` with custom) delimiter
+		void echoTillX(const char * casename) {
+			string s;
+			do {
+				s = "";
+				sin | getline( s, '@' );
+				sout | casename | s;
+			} while ( size(s) > 0 && s[size(s)-1] != 'x' );
+			sin | skip(" \n");
+		}
+		echoTillX("preSMD1");
+		echoTillX("preSMD2");
+		echoTillX("preSMD3");
+		echoTillX("preSMD4");
+	}
+	// Keep harmonized with io/manipulatorsInput.
+	{
+		string s = "yyyyyyyyyyyyyyyyyyyy";
+		char sk[] = "abc";
+		sin | "abc " | skip( sk ) | skip( 5 );			sout | "1" | s;
+		sin | s;										sout | "2" | s;
+		sin | ignore( s );								sout | "3" | s;
+		sin | wdi( 8, s );								sout | "4" | s;
+		sin | ignore( wdi( 8, s ) );					sout | "5" | s;
+
+		sin | incl( "abc", s );							sout | "6" | s;
+		sin | excl( "abc", s );							sout | "7" | s;
+		sin | ignore( incl( "abc", s ) );				sout | "8" | s;
+		sin | ignore( excl( "abc", s ) );				sout | "9" | s;
+		sin | incl( "abc", wdi( 8, s ) );				sout | "10" | s;
+		sin | excl( "abc", wdi( 8, s ) );				sout | "11" | s;
+		sin | ignore( incl( "abc", wdi( 8, s ) ) );		sout | "12" | s;
+		sin | ignore( excl( "abc", wdi( 8, s ) ) );		sout | "13" | s;
+		sin | nl;
+
+		s = "q";
+		sin | incl( "abc", s );							sout | "14" | s;
+		s = "q";
+		sin | excl( "u", s );							sout | "15" | s;
+		sin | skip( "u" ) | nl;
+
+		sin | getline( s );								sout | "16" | s;
+		sin | getline( s, '%' ) | nl;					sout | "17" | s;
+		sin | ignore( getline( s, '%' ) ) | nl;			sout | "18" | s;
+
+		sin | quoted( s );								sout | "19" | s;
+		sin | quoted( s, '\'' );						sout | "20" | s;
+		sin | quoted( s, '{', '}' );					sout | "21" | s;
+		sin | quoted( s, 'X', 'Y' );					sout | "22" | s;
+		sin | ignore( quoted( s, 'X', 'Y' ) );			sout | "23" | s;
+		sin | nl;
+	}
+	// Full repeat on string_res layer assures the full manipulator vocabulary is supported there.
+	{
+		string_res s = "yyyyyyyyyyyyyyyyyyyy";
+		char sk[] = "abc";
+		sin | "abc " | skip( sk ) | skip( 5 );			sout | "1" | s;
+		sin | s;										sout | "2" | s;
+		sin | ignore( s );								sout | "3" | s;
+		sin | wdi( 8, s );								sout | "4" | s;
+		sin | ignore( wdi( 8, s ) );					sout | "5" | s;
+
+		sin | incl( "abc", s );							sout | "6" | s;
+		sin | excl( "abc", s );							sout | "7" | s;
+		sin | ignore( incl( "abc", s ) );				sout | "8" | s;
+		sin | ignore( excl( "abc", s ) );				sout | "9" | s;
+		sin | incl( "abc", wdi( 8, s ) );				sout | "10" | s;
+		sin | excl( "abc", wdi( 8, s ) );				sout | "11" | s;
+		sin | ignore( incl( "abc", wdi( 8, s ) ) );		sout | "12" | s;
+		sin | ignore( excl( "abc", wdi( 8, s ) ) );		sout | "13" | s;
 		sin | "\n";
 
 		s = "q";
-		sin | incl( "abc", s );                         sout | "14" | s;
-		s = "q";
-		sin | excl( "u", s );                           sout | "15" | s;
+		sin | incl( "abc", s );							sout | "14" | s;
+		s = "q";
+		sin | excl( "u", s );							sout | "15" | s;
 		sin | skip( "u" );
 		sin | "\n";
-	}
-    // Full repeat on string_res layer assures the full manipulator vocabulary is supported there.
-    {
-        string_res s = "yyyyyyyyyyyyyyyyyyyy";
-        char sk[] = "abc";
-        sin | "abc " | skip( sk ) | skip( 5 );          sout | "1" | s;
-        sin | s;                                        sout | "2" | s;
-        sin | ignore( s );                              sout | "3" | s;
-        sin | wdi( 8, s );                              sout | "4" | s;
-        sin | ignore( wdi( 8, s ) );                    sout | "5" | s;
-
-        sin | incl( "abc", s );                         sout | "6" | s;
-        sin | excl( "abc", s );                         sout | "7" | s;
-        sin | ignore( incl( "abc", s ) );               sout | "8" | s;
-        sin | ignore( excl( "abc", s ) );               sout | "9" | s;
-        sin | incl( "abc", wdi( 8, s ) );               sout | "10" | s;
-        sin | excl( "abc", wdi( 8, s ) );               sout | "11" | s;
-        sin | ignore( incl( "abc", wdi( 8, s ) ) );     sout | "12" | s;
-        sin | ignore( excl( "abc", wdi( 8, s ) ) );     sout | "13" | s;
-		sin | "\n";
-
-		s = "q";
-		sin | incl( "abc", s );                         sout | "14" | s;
-		s = "q";
-		sin | excl( "u", s );                           sout | "15" | s;
-		sin | skip( "u" );
-		sin | "\n";
-    }
+		sin | getline( s );								sout | "16" | s;
+		sin | getline( s, '%' ) | nl;					sout | "17" | s;
+		sin | ignore( getline( s, '%' ) ) | nl;			sout | "18" | s;
+
+		sin | quoted( s );								sout | "19" | s;
+		sin | quoted( s, '\'' );						sout | "20" | s;
+		sin | quoted( s, '{', '}' );					sout | "21" | s;
+		sin | quoted( s, 'X', 'Y' );					sout | "22" | s;
+		sin | ignore( quoted( s, 'X', 'Y' ) );			sout | "23" | s;
+	}
 }
Index: tests/configs/parsebools.cfa
===================================================================
--- tests/configs/parsebools.cfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/configs/parsebools.cfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,11 +10,10 @@
 // Author           : Thierry Delisle
 // Created On       : Wed Oct 12 15:28:01 2022
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sun Feb 11 09:26:13 2024
+// Update Count     : 2
 //
 
 #include <fstream.hfa>
-
 #include "../meta/fork+exec.hfa"
 
@@ -22,5 +21,5 @@
 #include <parseargs.hfa>
 
-int main(int argc, char * argv[]) {
+int main( int argc, char * argv[] ) {
 	check_main(argv[0]);
 
@@ -41,5 +40,5 @@
 
 	char **left;
-	parse_args( options, "[OPTIONS]...\ntesting bool parameters", left);
+	parse_args( options, "[OPTIONS]...\ntesting bool parameters", left );
 
 	sout | "yes/no     :" | YN;
@@ -51,97 +50,90 @@
 }
 
-int true_main(const char * path, char * env[]) {
-	printf("no arg:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsebools", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
+int true_main( const char * path, char * env[] ) {
+	printf( "no arg:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsebools", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
 		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
-	printf("all true/set arg:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsebools", "-e=yes", "-y=Y", "-n=y", "-t=true", "-s", "-u", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+	printf( "all true/set arg:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsebools", "-e=yes", "-y=Y", "-n=y", "-t=true", "-s", "-u", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
-	printf("all false/unset arg:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsebools", "-e=no", "-y=N", "-n=n", "-t=false", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+	printf( "all false/unset arg:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsebools", "-e=no", "-y=N", "-n=n", "-t=false", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
-	printf("gibberish arg 1:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsebools", "-y=true", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+	printf( "gibberish arg 1:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsebools", "-y=true", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
-	printf("gibberish arg 2:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsebools", "-t=yes", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+	printf( "gibberish arg 2:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsebools", "-t=yes", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
-	printf("gibberish arg 3:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsebools", "-s=yes", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+	printf( "gibberish arg 3:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsebools", "-s=yes", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
-	printf("gibberish arg 4:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsebools", "-u=yes", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+	printf( "gibberish arg 4:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsebools", "-u=yes", ( const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
-	printf("All Done!\n");
+	printf( "All Done!\n" );
 
 	return 0;
Index: tests/configs/parsenums.cfa
===================================================================
--- tests/configs/parsenums.cfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/configs/parsenums.cfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -32,8 +32,8 @@
 #endif
 
-int true_main(const char * exec);
-
-int main(int argc, char * argv[]) {
-	check_main(argv[0]);
+int true_main( const char * exec );
+
+int main( int argc, char * argv[]) {
+	check_main( argv[0]);
 
 	int i = -3;
@@ -52,5 +52,5 @@
 
 	char **left;
-	parse_args( options, "[OPTIONS]...\ntesting bool parameters", left);
+	parse_args( options, "[OPTIONS]...\ntesting bool parameters", left );
 
 	sout | "int                :" | i;
@@ -61,157 +61,145 @@
 }
 
-int true_main(const char * path, char * env[]) {
-	printf("no arg:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	printf("all 0 arg:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", "-i=0", "-u=0", "-l=0", "-L=0", "-d=0", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	printf("negative vals arg:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", "-i=-1", "-d=-1", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	printf("funky notation arg:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", "-i=0x10", "-u=0x20", "-l=0x300", "-L=0x4000", "-d=5e6", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	printf("big values arg:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", "-i=2147483647", "-u=4294967295", "-l=" BIG_UNSIGNED_LONG, "-L=18446744073709551615", "-d=5e6", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	printf("too big values arg:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", "-i=2147483648", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", "-u=4294967296", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", "-l=" TOO_BIG_UNSIGNED_LONG, (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", "-L=18446744073709551616", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	printf("negative errors arg:\n");
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", "-u=-1", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", "-l=-1", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	if(pid_t child = strict_fork(); child == 0) {
-		int ret = execle(path, "parsenums", "-L=-1", (const char*)0p, env);
-		if(ret < 0) {
-			fprintf(stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror(errno));
-			exit(1);
-		}
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
-
-	printf("All Done!\n");
+int true_main( const char * path, char * env[] ) {
+	printf( "no arg:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	printf( "all 0 arg:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", "-i=0", "-u=0", "-l=0", "-L=0", "-d=0", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	printf( "negative vals arg:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", "-i=-1", "-d=-1", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	printf( "funky notation arg:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", "-i=0x10", "-u=0x20", "-l=0x300", "-L=0x4000", "-d=5e6", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	printf( "big values arg:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", "-i=2147483647", "-u=4294967295", "-l=" BIG_UNSIGNED_LONG, "-L=18446744073709551615", "-d=5e6", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	printf( "too big values arg:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", "-i=2147483648", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", "-u=4294967296", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", "-l=" TOO_BIG_UNSIGNED_LONG, (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", "-L=18446744073709551616", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	printf( "negative errors arg:\n" );
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", "-u=-1", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", "-l=-1", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	if ( pid_t child = strict_fork(); child == 0 ) {
+		int ret = execle( path, "parsenums", "-L=-1", (const char*)0p, env );
+		if ( ret < 0 ) {
+			fprintf( stderr, "Execl 2 returned with error: %d '%s'\n", errno, strerror( errno ) );
+			exit( 1 );
+		} // if
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
+
+	printf( "All Done!\n" );
 
 	return 0;
Index: tests/configs/usage.cfa
===================================================================
--- tests/configs/usage.cfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/configs/usage.cfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,7 +10,7 @@
 // Author           : Thierry Delisle
 // Created On       : Wed Oct 12 15:28:01 2022
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sun Feb 11 09:29:51 2024
+// Update Count     : 1
 //
 
@@ -24,25 +24,23 @@
 
 	sout | "No args, no errors";
-	if(pid_t child = strict_fork(); child == 0) {
+	if ( pid_t child = strict_fork(); child == 0 ) {
 		array( cfa_option, 0 ) opts;
-		print_args_usage(1, fake_argv, opts, "Test usage", false);
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+		print_args_usage(1, fake_argv, opts, "Test usage", false );
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
 	sout | "No args, with errors";
-	if(pid_t child = strict_fork(); child == 0) {
+	if ( pid_t child = strict_fork(); child == 0 ) {
 		array( cfa_option, 0 ) opts;
-		print_args_usage(1, fake_argv, opts, "Test usage", true);
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+		print_args_usage(1, fake_argv, opts, "Test usage", true );
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
 	sout | "Args with short names only:";
-	if(pid_t child = strict_fork(); child == 0) {
+	if ( pid_t child = strict_fork(); child == 0 ) {
 		int a, b, c;
 		array( cfa_option, 3 ) opts;
@@ -50,13 +48,12 @@
 		opts[1] = (cfa_option){'b', "", "Second arg", b };
 		opts[2] = (cfa_option){'c', "", "Third arg", c };
-		print_args_usage(1, fake_argv, opts, "Test usage", false);
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+		print_args_usage(1, fake_argv, opts, "Test usage", false );
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
 	sout | "Args with long names only:";
-	if(pid_t child = strict_fork(); child == 0) {
+	if ( pid_t child = strict_fork(); child == 0 ) {
 		int a, b, c;
 		array( cfa_option, 3 ) opts;
@@ -64,13 +61,12 @@
 		opts[1] = (cfa_option){'\0', "BB", "Second arg", b };
 		opts[2] = (cfa_option){'\0', "CC", "Third arg", c };
-		print_args_usage(1, fake_argv, opts, "Test usage", false);
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+		print_args_usage(1, fake_argv, opts, "Test usage", false );
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
 	sout | "Mix of short and long args:";
-	if(pid_t child = strict_fork(); child == 0) {
+	if ( pid_t child = strict_fork(); child == 0 ) {
 		int a, b, c;
 		array( cfa_option, 3 ) opts;
@@ -78,13 +74,12 @@
 		opts[1] = (cfa_option){'b', "BBBB", "Second arg", b };
 		opts[2] = (cfa_option){'\0', "CC", "Third arg", c };
-		print_args_usage(1, fake_argv, opts, "Test usage", false);
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+		print_args_usage(1, fake_argv, opts, "Test usage", false );
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
 	sout | "Mix of short and long and some missing description:";
-	if(pid_t child = strict_fork(); child == 0) {
+	if ( pid_t child = strict_fork(); child == 0 ) {
 		int a, b, c;
 		array( cfa_option, 3 ) opts;
@@ -92,13 +87,12 @@
 		opts[1] = (cfa_option){'b', "BBBB", "", b };
 		opts[2] = (cfa_option){'\0', "CC", "Third arg", c };
-		print_args_usage(1, fake_argv, opts, "Test usage", false);
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+		print_args_usage(1, fake_argv, opts, "Test usage", false );
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 
 	sout | "Mix of short and long and some long description:";
-	if(pid_t child = strict_fork(); child == 0) {
+	if ( pid_t child = strict_fork(); child == 0 ) {
 		int a, b, c;
 		array( cfa_option, 3 ) opts;
@@ -106,12 +100,11 @@
 		opts[1] = (cfa_option){'b', "BBBB", "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", b };
 		opts[2] = (cfa_option){'\0', "CC", "Third arg", c };
-		print_args_usage(1, fake_argv, opts, "Test usage", false);
-	}
-	else {
-		int status = do_wait(child);
-		print_status(status);
-	}
+		print_args_usage(1, fake_argv, opts, "Test usage", false );
+	} else {
+		int status = do_wait( child );
+		print_status( status );
+	} // if
 }
 
 // no used
-static int true_main(const char * path, char * env[]) { return 0; }
+static int true_main( const char * path, char * env[]) { return 0; }
Index: tests/errors/.expect/declaration.txt
===================================================================
--- tests/errors/.expect/declaration.txt	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/errors/.expect/declaration.txt	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -8,5 +8,5 @@
   with members
     i: int 
-   with body
+  with body
 
 
@@ -14,5 +14,5 @@
   with members
     i: int 
-   with body
+  with body
 
 
Index: tests/exceptions/pingpong_nonlocal.cfa
===================================================================
--- tests/exceptions/pingpong_nonlocal.cfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/exceptions/pingpong_nonlocal.cfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -2,7 +2,7 @@
 #include <thread.hfa>
 #include <mutex_stmt.hfa>
+#include <Exception.hfa>
 
-exception num_ping_pongs { int num; };
-vtable(num_ping_pongs) num_ping_pongs_vt;
+ExceptionDecl( num_ping_pongs, int num; );
 
 thread Ping_Pong {
@@ -16,5 +16,5 @@
 	this.name = name;
 	cnt = 0;
-	?{}( except, &num_ping_pongs_vt, 0 );
+	?{}( except, ExceptionArgs( num_ping_pongs, 0 ) );
 }
 
@@ -29,5 +29,5 @@
 		for () {
 			while( ! poll( this ) ) { yield(); }
-            inc_resume_at( cnt );
+			inc_resume_at( cnt );
 		}
 	} catchResume( num_ping_pongs * e; e->num < numtimes ) {
@@ -37,5 +37,5 @@
 		mutex( sout ) sout | name | "catch" | cnt | e->num;
 		if ( e->num == numtimes ) {
-            inc_resume_at( e->num );
+			inc_resume_at( e->num );
 		}
 	}
@@ -49,6 +49,5 @@
 		&ping.partner = &pong;							// create cycle
 		&pong.partner = &ping;
-		num_ping_pongs except{ &num_ping_pongs_vt, 0 };
-		resumeAt( pong, except );
+		resumeAt( pong, ExceptionInst( num_ping_pongs, 0 ) );
 	}
 	sout | "main end";
Index: tests/io/.in/manipulatorsInput.txt
===================================================================
--- tests/io/.in/manipulatorsInput.txt	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/io/.in/manipulatorsInput.txt	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -13,5 +13,5 @@
 @# this line 1)-{}%
 @# this line 2)-{}%
-"abc"
+    "abc"
 'abc  '
 { d d
@@ -35,5 +35,5 @@
 @# this line 1)-{}%
 @# this line 2)-{}%
-"abc"
+    "abc"
 'abc  '
 { d d
Index: tests/io/manipulatorsInput.cfa
===================================================================
--- tests/io/manipulatorsInput.cfa	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tests/io/manipulatorsInput.cfa	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -7,6 +7,6 @@
 // Created On       : Sat Jun  8 17:58:54 2019
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Jan 28 11:59:55 2024
-// Update Count     : 133
+// Last Modified On : Mon Feb  5 21:54:49 2024
+// Update Count     : 134
 // 
 
@@ -114,5 +114,5 @@
 		sin | wdi( sizeof(s), s );						sout | "2" | s;
 		sin | ignore( s );								sout | "3" | s;
- 		sin | wdi( sizeof(s), 8, s );					sout | "4" | s;
+		sin | wdi( sizeof(s), 8, s );					sout | "4" | s;
 		sin | ignore( wdi( sizeof(s), 8, s ) );			sout | "5" | s;
 
@@ -131,8 +131,8 @@
 		s[0] = 'q'; s[1] = '\0';
 		sin | excl( "u", wdi( sizeof(s), s ) );			sout | "15" | s;
-		sin | skip( "u" ) | "\n";
+		sin | skip( "u" ) | nl;
 		sin | getline( wdi( sizeof(s), s ) );			sout | "16" | s;
-		sin | getline( wdi( sizeof(s), s ), '%' ) | "\n"; sout | "17" | s;
-		sin | ignore( getline( wdi( sizeof(s), s ), '%' ) ) | "\n"; sout | "18" | s;
+		sin | getline( wdi( sizeof(s), s ), '%' ) | nl; sout | "17" | s;
+		sin | ignore( getline( wdi( sizeof(s), s ), '%' ) ) | nl; sout | "18" | s;
 
 		sin | quoted( wdi( sizeof(s), s ) );			sout | "19" | s;
Index: tools/cfa.nanorc
===================================================================
--- tools/cfa.nanorc	(revision 0522ebe7b3ae7204a1d2c50a1bc7273bfa36762a)
+++ tools/cfa.nanorc	(revision a4da45ee15c7b12fa95d6fa3d7ed164730c4d88e)
@@ -10,6 +10,7 @@
 color green "\<(forall|trait|(o|d|f|t)type|mutex|_Bool|volatile|virtual)\>"
 color green "\<(float|double|bool|char|int|short|long|enum|void|auto)\>"
-color green "\<(static|const|extern|(un)?signed|inline|sizeof|vtable)\>"
 color green "\<((s?size)|one|zero|((u_?)?int(8|16|32|64|ptr)))_t\>"
+color green "\<(static|const|extern|(un)?signed|inline)\>"
+color green "\<(typeof|vtable|sizeof|alignof)\>"
 
 # Declarations
