Changes in / [7042c60:cf191ac]


Ignore:
Files:
1 added
1 deleted
46 edited

Legend:

Unmodified
Added
Removed
  • doc/LaTeXmacros/common.sty

    r7042c60 rcf191ac  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Thu Apr 18 09:14:02 2024
    14 %% Update Count     : 657
     13%% Last Modified On : Sun Feb 25 23:30:09 2024
     14%% Update Count     : 645
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    108108\renewcommand\subparagraph{\@startsection{subparagraph}{4}{\z@}{-1.5ex \@plus -1ex \@minus -.2ex}{-1em}{\normalfont\normalsize\bfseries\itshape}}
    109109
     110% index macros
    110111\newcommand{\italic}[1]{\emph{\hyperpage{#1}}}
    111112\newcommand{\Definition}[1]{\textbf{\hyperpage{#1}}}
    112 \newcommand{\see}{\protect\@ifstar\@ssee\@see}
    113 \newcommand{\@ssee}[1]{(See #1)}
    114 \newcommand{\@see}[1]{(see #1)}
    115 
    116 % index macros
     113\newcommand{\see}[1]{(see #1)}
    117114
    118115% Define some commands that produce formatted index entries suitable for cross-references.
     
    155152\newcommand{\newtermFontInline}{\emph}
    156153\newcommand{\newterm}{\protect\@ifstar\@snewterm\@newterm}
     154\newcommand{\@newterm}[2][\@empty]{\lowercase{\def\temp{#2}}{\newtermFontInline{#2}}\ifx#1\@empty\index{\temp}\else\index{#1@{\protect#2}}\fi}
    157155\newcommand{\@snewterm}[2][\@empty]{{\newtermFontInline{#2}}\ifx#1\@empty\index{#2}\else\index{#1@{\protect#2}}\fi}
    158 \newcommand{\@newterm}[2][\@empty]{\lowercase{\def\temp{#2}}{\newtermFontInline{#2}}\ifx#1\@empty\index{\temp}\else\index{#1@{\protect#2}}\fi}
    159156
    160157% \snake{<identifier>}
     
    205202
    206203\newenvironment{cquote}{%
    207         \list{}{\topsep=\lst@aboveskip\parskip=0pt\partopsep=0pt\itemsep=0pt\parsep=0pt\listparindent=0pt\leftmargin=\parindentlnth\rightmargin=0pt}%
     204        \list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=4pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}%
    208205        \item\relax
    209         \lstset{resetmargins=true}
    210206}{%
    211207        \endlist
     
    349345\fi%
    350346
    351 \usepackage{tabularx}                                   % if @ is used for lstMakeShortInline, allows @{}
    352 
    353347% Local Variables: %
    354348% tab-width: 4 %
  • doc/LaTeXmacros/common.tex

    r7042c60 rcf191ac  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Thu Apr 18 09:15:38 2024
    14 %% Update Count     : 664
     13%% Last Modified On : Mon Feb 26 08:06:05 2024
     14%% Update Count     : 615
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    109109\renewcommand\subparagraph{\@startsection{subparagraph}{4}{\z@}{-1.5ex \@plus -1ex \@minus -.2ex}{-1em}{\normalfont\normalsize\bfseries\itshape}}
    110110
     111% index macros
    111112\newcommand{\italic}[1]{\emph{\hyperpage{#1}}}
    112113\newcommand{\Definition}[1]{\textbf{\hyperpage{#1}}}
    113 \newcommand{\see}{\protect\@ifstar\@ssee\@see}
    114 \newcommand{\@ssee}[1]{(See #1)}
    115 \newcommand{\@see}[1]{(see #1)}
    116 
    117 % index macros
     114\newcommand{\see}[1]{(see #1)}
    118115
    119116% Define some commands that produce formatted index entries suitable for cross-references.
     
    156153\newcommand{\newtermFontInline}{\emph}
    157154\newcommand{\newterm}{\protect\@ifstar\@snewterm\@newterm}
     155\newcommand{\@newterm}[2][\@empty]{\lowercase{\def\temp{#2}}{\newtermFontInline{#2}}\ifx#1\@empty\index{\temp}\else\index{#1@{\protect#2}}\fi}
    158156\newcommand{\@snewterm}[2][\@empty]{{\newtermFontInline{#2}}\ifx#1\@empty\index{#2}\else\index{#1@{\protect#2}}\fi}
    159 \newcommand{\@newterm}[2][\@empty]{\lowercase{\def\temp{#2}}{\newtermFontInline{#2}}\ifx#1\@empty\index{\temp}\else\index{#1@{\protect#2}}\fi}
    160157
    161158% \snake{<identifier>}
     
    204201\newcommand{\VS}{\abbrevFont{vs}}
    205202\newcommand{\vs}{\VS\CheckPeriod}
     203\makeatother
    206204
    207205\newenvironment{cquote}{%
    208         \list{}{\topsep=\lst@aboveskip\parskip=0pt\partopsep=0pt\itemsep=0pt\parsep=0pt\listparindent=0pt\leftmargin=\parindentlnth\rightmargin=0pt}%
     206        \list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=4pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}%
    209207        \item\relax
    210         \lstset{resetmargins=true}
    211208}{%
    212209        \endlist
    213210}% cquote
    214 \makeatother
    215211
    216212\newenvironment{rationale}{%
     
    353349\fi%
    354350
    355 \usepackage{tabularx}                                   % if @ is used for lstMakeShortInline, allows @{}
    356 
    357351% Local Variables: %
    358352% tab-width: 4 %
  • doc/LaTeXmacros/lstlang.sty

    r7042c60 rcf191ac  
    88%% Created On       : Sat May 13 16:34:42 2017
    99%% Last Modified By : Peter A. Buhr
    10 %% Last Modified On : Mon Apr 15 11:28:44 2024
    11 %% Update Count     : 43
     10%% Last Modified On : Tue Mar 12 17:29:58 2024
     11%% Update Count     : 42
    1212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1313
     
    116116                alignas, _Alignas, alignof, _Alignof, __alignof, __alignof__, and, asm, __asm, __asm__, _Atomic, __attribute, __attribute__,
    117117                __auto_type, basetypeof, _Bool, catch, catchResume, choose, coerce, corun, cofor, _Complex, __complex, __complex__,
    118                 __const, __const__, continue, coroutine, _Decimal32, _Decimal64, _Decimal128, disable, dtype, enable, exception, __extension__,
     118                __const, __const__, continue, _Decimal32, _Decimal64, _Decimal128, disable, dtype, enable, exception, __extension__,
    119119                fallthrough, fallthru, finally, fixup, __float80, float80, __float128, float128, _Float16, _Float32, _Float32x, _Float64,
    120120                _Float64x, _Float128, _Float128x, forall, fortran, ftype, generator, _Generic, _Imaginary, __imag, __imag__, inline,
  • doc/bibliography/pl.bib

    r7042c60 rcf191ac  
    519519    year        = 1963,
    520520    pages       = {1-17},
    521 }
    522 
    523 @misc{AlgolW,
    524     keywords    = {AlgolW},
    525     contributer = {pabuhr@plg},
    526     author      = {Henry Bauer and Sheldon Becker and Susan L. Graham and Edwin Satterthwaite and Richard L. Sites},
    527     title       = {{Algol W} Language Description},
    528     month       = jun,
    529     year        = 1972,
    530     howpublished= {\url{https://www.algol60.org/docsW/algolw.pdf}},
    531521}
    532522
  • doc/theses/jiada_liang_MMath/CFAenum.tex

    r7042c60 rcf191ac  
    137137\section{Pure Enumerators}
    138138
    139 An empty enumerator type, @enum()@, implies the enumerators are opaque symbols without values but set properties;
     139An empty enumerator type, @enum()@, implies the enumerators are pure symbols without values but set properties;
    140140hence, there is no default conversion to @int@.
    141141
  • doc/theses/jiada_liang_MMath/Makefile

    r7042c60 rcf191ac  
    1313BibSRC = ${wildcard *.bib}
    1414
    15 TeXLIB = .:${LaTMac}:${Build}:                  # common latex macros
    16 BibLIB = .:${BibRep}:                           # common citation repository
     15TeXLIB = .:${LaTMac}:${Build}:
     16BibLIB = .:${BibRep}:
    1717
    1818MAKEFLAGS = --no-print-directory # --silent
  • doc/theses/jiada_liang_MMath/background.tex

    r7042c60 rcf191ac  
    11\chapter{Background}
     2\lstnewenvironment{clang}[1][]{\lstset{language=[ANSI]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    23
    34\CFA is a backwards-compatible extension of the C programming language.
     
    4748
    4849\section{C Enumeration}
    49 \label{s:CEnumeration}
    5050
    51 The C enumeration has the following syntax~\cite[\S~6.7.2.2]{C11}.
    52 \begin{clang}[identifierstyle=\linespread{0.9}\it]
    53 $\it enum$-specifier:
    54         enum identifier$\(_{opt}\)$ { enumerator-list }
    55         enum identifier$\(_{opt}\)$ { enumerator-list , }
    56         enum identifier
    57 enumerator-list:
    58         enumerator
    59         enumerator-list , enumerator
    60 enumerator:
    61         enumeration-constant
    62         enumeration-constant = constant-expression
    63 \end{clang}
    64 The terms \emph{enumeration} and \emph{enumerator} used in this work \see{\VRef{s:Terminology}} come from the grammar.
    65 The C enumeration semantics is discussed using examples.
    66 
    67 An unnamed enumeration is used to provide secondary renaming, like a @const@ declaration in other languages.
    68 \begin{clang}
    69 enum { Size = 20, Pi = 3.14159 };   // unnamed enumeration $\(\Rightarrow\)$ no ordering
    70 \end{clang}
    71 This declaration form is not an enumeration even though it is declared using an @enum@ because it has none of the following enumeration properties.
    72 
    73 A \emph{named} enumeration type is an actual enumeration.
     51The C enumeration has the following syntax and semantics.
    7452\begin{clang}
    7553enum Weekday { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun, };
  • doc/theses/jiada_liang_MMath/intro.tex

    r7042c60 rcf191ac  
    11\chapter{Introduction}
    22
    3 All types in a programming language must have a set of constants, and these constants have \Newterm{primary names}, \eg integral types have constants @-1@, @17@, @0xff@, floating-point types have constants @5.3@, @2.3E-5@, @0xff.ffp0@, character types have constants @'a'@, @"abc\n"@, \mbox{\lstinline{u8"}\texttt{\guillemotleft{na\"{i}ve}\guillemotright}\lstinline{"}}, \etc.
    4 Con\-stants can be overloaded among types, \eg @0@ is a null pointer for all pointer types, and the value zero for integral and floating-point types.
    5 (In \CFA, the primary constants @0@ and @1@ can be overloaded for any type.)
     3All types in a programming language must have a set of constants, and these constants have \Newterm{primary names}, \eg integral types have constants @-1@, @17@, @12345@, \etc.
     4Constants can be overloaded among types, \eg @0@ is a null pointer for all pointer types, and the value zero for integral and floating-point types.
    65Hence, each primary constant has a symbolic name referring to its internal representation, and these names are dictated by language syntax related to types.
    7 In theory, there are an infinite set of primary constant names per type.
     6In theory, there are an infinite set of primary names per type.
    87
    9 \Newterm{Secondary naming} is a common practice in mathematics, engineering and computer science, \eg $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MB (megabyte, 1E6), and in general situations, \eg specific times (noon, New Years), cities (Big Apple), flowers (Lily), \etc.
     8\Newterm{Secondary naming} is a common practice in mathematics and engineering, \eg $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MHz (1E6), and in general situations, \eg specific times (noon, New Years), cities (Big Apple), flowers (Lily), \etc.
    109Many programming languages capture this important software-engineering capability through a mechanism called \Newterm{constant} or \Newterm{literal} naming, where a secondary name is aliased to a primary name.
    11 Its purpose is for readability and to eliminate duplication of the primary constant throughout a program.
    12 For example, a meaningful secondary name replaces a primary name throughout a program;
    13 thereafter, changing the binding of the secondary to primary name automatically distributes the rebinding, preventing errors.
    14 In some cases, secondary naming is \Newterm{opaque}, where the matching internal representation can be chosen arbitrarily, and only equality operations are available, \eg @O_RDONLY@, @O_WRONLY@, @O_CREAT@, @O_TRUNC@, @O_APPEND@.
     10In some cases, secondary naming is \Newterm{pure}, where the matching internal representation can be chosen arbitrarily, and only equality operations are available, \eg @O_RDONLY@, @O_WRONLY@, @O_CREAT@, @O_TRUNC@, @O_APPEND@.
     11(The names the thing.)
    1512Because a secondary name is a constant, it cannot appear in a mutable context, \eg \mbox{$\pi$ \lstinline{= 42}} is meaningless, and a constant has no address, \ie it is an \Newterm{rvalue}\footnote{
    1613The term rvalue defines an expression that can only appear on the right-hand side of an assignment expression.}.
    1714
    18 Secondary names can form an (ordered) set, \eg days of a week, months of a year, floors of a building (basement, ground, 1st), colours in a rainbow, \etc.
     15Secondary names can form an (ordered) set, \eg days of the week, months of a year, floors of a building (basement, ground, 1st), colours in a rainbow, \etc.
    1916Many programming languages capture these groupings through a mechanism called an \Newterm{enumeration}.
    2017\begin{quote}
    2118enumerate (verb, transitive).
    2219To count, ascertain the number of;
    23 more usually, to mention (a number of things or persons) separately, as if for the purpose of counting;
    24 to specify as in a list or catalogue.~\cite{OEDenumerate}
     20\emph{more
     21usually, to mention (a number of things or persons) separately, as if for the
     22purpose of counting};
     23to specify as in a list or catalogue.~\cite{OED}
    2524\end{quote}
    26 Within an enumeration set, the enumeration names must be unique, and instances of an enumerated type are \emph{often} restricted to hold only the secondary names.
     25Within an enumeration set, the enumeration names must be unique, and instances of an enumerated type are restricted to hold only the secondary names.
    2726It is possible to enumerate among set names without having an ordering among the set elements.
    2827For example, the week, the weekdays, the weekend, and every second day of the week.
     
    3029for ( cursor in Mon, Tue, Wed, Thu, Fri, Sat, Sun } ... $\C[3.75in]{// week}$
    3130for ( cursor in Mon, Tue, Wed, Thu, Fri } ...   $\C{// weekday}$
    32 for ( cursor in Sat, Sun } ...                                  $\C{// weekend}$
     31for ( cursor in Thu, Fri } ...                                  $\C{// weekend}$
    3332for ( cursor in Mon, Wed, Fri, Sun } ...                $\C{// every second day of week}\CRT$
    3433\end{cfa}
    35 This independence from internal representation allows multiple names to have the same representation (eighth note, quaver), giving synonyms.
     34This independence from internal representation allows multiple names to have the same representation (eight note, quaver), giving synonyms.
    3635A set can have a partial or total ordering, making it possible to compare set elements, \eg Monday is before Friday and Friday is after.
    37 Ordering allows iterating among the enumeration set using relational operators and advancement, \eg:
     36Ordering allows iterating among the enumeration set using relational operators and advancement, \eg
    3837\begin{cfa}
    3938for ( cursor = Monday; cursor @<=@ Friday; cursor = @succ@( cursor ) ) ...
    4039\end{cfa}
    41 Here the internal representation for the secondary names are logically \emph{generated} rather than listing a subset of names.
    42 
    43 Hence, the fundamental aspects of an enumeration are:
    44 \begin{enumerate}
    45 \item
    46 \begin{sloppypar}
    47 It provides a finite set of secondary names, which become its primary constants.
    48 This differentiates an enumeration from general types with an infinite set
    49 of primary constants.
    50 \end{sloppypar}
    51 \item
    52 The secondary names are constants, which follows transitively from their binding (aliasing) to primary names, which are constants.
    53 \item
    54 Defines a type for generating instants (variables).
    55 \item
    56 For safety, an enumeration instance should be restricted to hold only its type's secondary names.
    57 \item
    58 There is a mechanism for \emph{enumerating} over the secondary names, where the ordering can be implicit from the type, explicitly listed, or generated arithmetically.
    59 \end{enumerate}
     40Here the internal representations for the secondary names are \emph{generated} rather than listing a subset of names.
    6041
    6142
    6243\section{Terminology}
    63 \label{s:Terminology}
    6444
    65 The term \Newterm{enumeration} defines a type with a set of secondary names, and the term \Newterm{enumerator} represents an arbitrary secondary name \see{\VRef{s:CEnumeration} for the name derivation}.
    66 As well, an enumerated type can have three fundamental properties, \Newterm{label}, \Newterm{order}, and \Newterm{value}.
     45The term \Newterm{enumeration} defines the set of secondary names, and the term \Newterm{enumerator} represents an arbitrary secondary name.
     46As well, an enumerated type has three fundamental properties, \Newterm{label}, \Newterm{order}, and \Newterm{value}.
    6747\begin{cquote}
    6848\sf\setlength{\tabcolsep}{3pt}
    6949\begin{tabular}{rcccccccr}
    7050\it\color{red}enumeration       & \multicolumn{8}{c}{\it\color{red}enumerators} \\
    71 $\downarrow$\hspace*{15pt}      & \multicolumn{8}{c}{$\downarrow$}                              \\
    72 @enum@ Week \{                          & Mon,  & Tue,  & Wed,  & Thu,  & Fri,  & Sat,  & Sun {\color{red}= 42} & \};   \\
     51$\downarrow$\hspace*{25pt}      & \multicolumn{8}{c}{$\downarrow$}                              \\
     52@enum@ Week \{                          & Mon,  & Tue,  & Wed,  & Thu,  & Fri,  & Sat,  & Sun = 42      & \};   \\
    7353\it\color{red}label                     & Mon   & Tue   & Wed   & Thu   & Fri   & Sat   & Sun           &               \\
    7454\it\color{red}order                     & 0             & 1             & 2             & 3             & 4             & 5             & 6                     &               \\
    75 \it\color{red}value                     & 0             & 1             & 2             & 3             & 4             & 5             & {\color{red}42}               &
     55\it\color{red}value                     & 0             & 1             & 2             & 3             & 4             & 5             & 42            &
    7656\end{tabular}
    7757\end{cquote}
     
    9272\section{Motivation}
    9373
    94 Many programming languages provide an enumeration-like mechanism, which may or may not cover the previous five fundamental enumeration aspects.
    95 Hence, the term \emph{enumeration} can be confusing and misunderstood.
    96 Furthermore, some languages conjoin the enumeration with other type features, making it difficult to tease apart which featuring is being used.
    97 This section discusses some language features that are sometimes called an enumeration but do not provide all enumeration aspects.
     74Some programming languages only provide secondary renaming, which can be simulated by an enumeration without ordering.
     75\begin{cfa}
     76const Size = 20, Pi = 3.14159;
     77enum { Size = 20, Pi = 3.14159 };   // unnamed enumeration $\(\Rightarrow\)$ no ordering
     78\end{cfa}
     79In both cases, it is possible to compare the secondary names, \eg @Size < Pi@, if that is meaningful;
     80however, without an enumeration type-name, it is impossible to create an iterator cursor.
    9881
    99 
    100 \subsection{Aliasing}
    101 
    102 Some languages provide simple secondary aliasing (renaming), \eg:
    103 \begin{cfa}
    104 const Size = 20, Pi = 3.14159, Name = "Jane";
    105 \end{cfa}
    106 The secondary name is logically replaced in the program text by its corresponding primary name.
    107 Therefore, it is possible to compare the secondary names, \eg @Size < Pi@, only because the primary constants allow it, whereas \eg @Pi < Name@ might be disallowed depending on the language.
    108 
    109 Aliasing is not macro substitution, \eg @#define Size 20@, where a name is replaced by its value \emph{before} compilation, so the name is invisible to the programming language.
    110 With aliasing, each secondary name is part of the language, and hence, participates fully, such as name overloading in the type system.
    111 Aliasing is not an immutable variable, \eg:
    112 \begin{cfa}
    113 extern @const@ int Size = 20;
    114 extern void foo( @const@ int @&@ size );
    115 foo( Size ); // take the address of (reference) Size
    116 \end{cfa}
    117 Taking the address of an immutable variable makes it an \Newterm{lvalue}, which implies it has storage.
    118 With separate compilation, it is necessary to choose one translation unit to perform the initialization.
    119 If aliasing does require storage, its address and initialization are opaque (compiler only), similar to \CC rvalue reference @&&@.
    120 
    121 Aliasing does provide readability and automatic resubstitution.
    122 It also provides simple enumeration properties, but with extra effort.
     82Secondary renaming can similate an enumeration, but with extra effort.
    12383\begin{cfa}
    12484const Mon = 1, Tue = 2, Wed = 3, Thu = 4, Fri = 5, Sat = 6, Sun = 7;
    12585\end{cfa}
    126 Any reordering of the enumerators requires manual renumbering.
     86Furthermore, reordering the enumerators requires manual renumbering.
    12787\begin{cfa}
    12888const Sun = 1, Mon = 2, Tue = 3, Wed = 4, Thu = 5, Fri = 6, Sat = 7;
    12989\end{cfa}
    130 For these reasons, aliasing is sometimes called an enumeration.
    131 However, there is no type to create a type-checked instance or iterator cursor, so there is no ability for enumerating.
    132 Hence, there are multiple enumeration aspects not provided by aliasing, justifying a separate enumeration type in a programming language.
     90Finally, there is no common type to create a type-checked instance or iterator cursor.
     91Hence, there is only a weak equivalence between secondary naming and enumerations, justifying the enumeration type in a programming language.
    13392
     93A variant (algebraic) type is often promoted as a kind of enumeration, \ie a varient type can simulate an enumeration.
     94A variant type is a tagged-union, where the possible types may be heterogeneous.
     95\begin{cfa}
     96@variant@ Variant {
     97        @int tag;@  // optional/implicit: 0 => int, 1 => double, 2 => S
     98        @union {@ // implicit
     99                case int i;
     100                case double d;
     101                case struct S { int i, j; } s;
     102        @};@
     103};
     104\end{cfa}
     105Crucially, the union implies instance storage is shared by all of the variant types.
     106Hence, a variant is dynamically typed, as in a dynamic-typed programming-language, but the set of types is statically bound, similar to some aspects of dynamic gradual-typing~\cite{Gradual Typing}.
     107Knowing which type is in a variant instance is crucial for correctness.
     108Occasionally, it is possible to statically determine all regions where each variant type is used, so a tag and runtime checking is unnecessary;
     109otherwise, a tag is required to denote the particular type in the variant and the tag checked at runtime using some form of type pattern-matching.
    134110
    135 \subsection{Algebraic Data Type}
     111The tag can be implicitly set by the compiler on assignment, or explicitly set by the program\-mer.
     112Type pattern-matching is then used to dynamically test the tag and branch to a section of code to safely manipulate the value, \eg:
     113\begin{cfa}[morekeywords={match}]
     114Variant v = 3;  // implicitly set tag to 0
     115@match@( v ) {    // know the type or test the tag
     116        case int { /* only access i field in v */ }
     117        case double { /* only access d field in v */ }
     118        case S { /* only access s field in v */ }
     119}
     120\end{cfa}
     121For safety, either all variant types must be listed or a @default@ case must exist with no field accesses.
    136122
    137 An algebraic data type (ADT)\footnote{ADT is overloaded with abstract data type.} is another language feature often linked with enumeration, where an ADT conjoins an arbitrary type, possibly a \lstinline[language=C++]{class} or @union@, and a named constructor.
    138 For example, in Haskell:
    139 \begin{haskell}
    140 data S = S { i::Int, d::Double }                $\C{// structure}$
    141 data @Foo@ = A Int | B Double | C S             $\C{// ADT, composed of three types}$
    142 foo = A 3;                                                              $\C{// type Foo is inferred}$
    143 bar = B 3.5
    144 baz = C S{ i = 7, d = 7.5 }
    145 \end{haskell}
    146 the ADT has three variants (constructors), @A@, @B@, @C@ with associated types @Int@, @Double@, and @S@.
    147 The constructors create an initialized value of the specific type that is bound to the immutable variables @foo@, @bar@, and @baz@.
    148 Hence, the ADT @Foo@ is like a union containing values of the associated types, and a constructor name is used to access the value using dynamic pattern-matching.
    149 \begin{cquote}
    150 \setlength{\tabcolsep}{15pt}
    151 \begin{tabular}{@{}ll@{}}
    152 \begin{haskell}
    153 prtfoo val = -- function
    154     -- pattern match on constructor
    155     case val of
    156       @A@ a -> print a
    157       @B@ b -> print b
    158       @C@ (S i d) -> do
    159           print i
    160           print d
    161 \end{haskell}
    162 &
    163 \begin{haskell}
    164 main = do
    165     prtfoo foo
    166     prtfoo bar
    167     prtfoo baz
    168 3
    169 3.5
    170 7
    171 7.5
    172 \end{haskell}
    173 \end{tabular}
    174 \end{cquote}
    175 For safety, most languages require all assocaited types to be listed or a default case with no field accesses.
     123To simulate an enumeration with a variant, the tag is \emph{re-purposed} for either ordering or value and the variant types are omitted.
     124\begin{cfa}
     125variant Weekday {
     126        int tag; // implicit 0 => Mon, ..., 6 => Sun
     127        @case Mon;@ // no type
     128        ...
     129        @case Sun;@
     130};
     131\end{cfa}
     132The type system ensures tag setting and testing are correctly done.
     133However, the enumeration operations are limited to the available tag operations, \eg pattern matching.
     134\begin{cfa}
     135Week week = Mon;
     136if ( @dynamic_cast(Mon)@week ) ... // test tag == Mon
     137\end{cfa}
     138While enumerating among tag names is possible:
     139\begin{cfa}[morekeywords={in}]
     140for ( cursor in Mon, Wed, Fri, Sun ) ...
     141\end{cfa}
     142ordering for iteration would require a \emph{magic} extension, such as a special @enum@ variant, because it has no meaning for a regular variant, \ie @int@ < @double@.
    176143
    177 A less frequent case is multiple constructors with the same type.
    178 \begin{haskell}
    179 data Bar = X Int | Y Int | Z Int;
    180 foo = X 3;
    181 bar = Y 3;
    182 baz = Z 5;
    183 \end{haskell}
    184 Here, the constructor name gives different meaning to the values in the common \lstinline[language=Haskell]{Int} type, \eg the value @3@ has different interpretations depending on the constructor name in the pattern matching.
     144However, if a special @enum@ variant allows the tags to be heterogeneously typed, ordering must fall back on case positioning, as many types have incomparable values.
     145Iterating using tag ordering and heterogeneous types, also requires pattern matching.
     146\begin{cfa}[morekeywords={match}]
     147for ( cursor = Mon; cursor <= Fri; cursor = succ( cursor) ) {
     148        match( cursor ) {
     149                case Mon { /* access special type for Mon */ }
     150                ...
     151                case Fri { /* access special type for Fri */ }
     152                default
     153        }
     154}
     155\end{cfa}
     156If the variant type is changed by adding/removing types or the loop range changes, the pattern matching must be adjusted.
     157As well, if the start/stop values are dynamic, it may be impossible to statically determine if all variant types are listed.
    185158
    186 Note, the term \Newterm{variant} is often associated with ADTs.
    187 However, there are multiple languages with a @variant@ type that is not an ADT \see{Algol68~\cite{Algol68} or \CC \lstinline{variant}}.
    188 In these languages, the variant is often a union using RTTI tags, which cannot be used to simulate an enumeration.
    189 Hence, in this work the term variant is not a synonym for ADT.
    190 
    191 % https://downloads.haskell.org/ghc/latest/docs/libraries/base-4.19.1.0-179c/GHC-Enum.html
    192 % https://hackage.haskell.org/package/base-4.19.1.0/docs/GHC-Enum.html
    193 
    194 The association between ADT and enumeration occurs if all the constructors have a unit (empty) type, \eg @struct unit {}@.
    195 Note, the unit type is not the same as \lstinline{void}, \eg:
    196 \begin{cfa}
    197 void foo( void );
    198 struct unit {} u;  // empty type
    199 unit bar( unit );
    200 foo( foo() );        // void argument does not match with void parameter
    201 bar( bar( u ) );   // unit argument does match with unit parameter
    202 \end{cfa}
    203 
    204 For example, in the Haskell ADT:
    205 \begin{haskell}
    206 data Week = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving(Enum, Eq, Show)
    207 \end{haskell}
    208 the default type for each constructor is the unit type, and deriving from @Enum@ enforces no other type, @Eq@ allows equality comparison, and @Show@ is for printing.
    209 The nullary constructors for the unit types are numbered left-to-right from $0$ to @maxBound@$- 1$, and provides enumerating operations @succ@, @pred@, @enumFrom@ @enumFromTo@.
    210 \VRef[Figure]{f:HaskellEnumeration} shows enumeration comparison and iterating (enumerating).
    211 
    212 \begin{figure}
    213 \begin{cquote}
    214 \setlength{\tabcolsep}{15pt}
    215 \begin{tabular}{@{}ll@{}}
    216 \begin{haskell}
    217 day = Tue
    218 main = do
    219     if day == Tue then
    220         print day
    221     else
    222         putStr "not Tue"
    223     print (enumFrom Mon)            -- week
    224     print (enumFromTo Mon Fri)   -- weekday
    225     print (enumFromTo Sat Sun)  -- weekend
    226 \end{haskell}
    227 &
    228 \begin{haskell}
    229 Tue
    230 [Mon,Tue,Wed,Thu,Fri,Sat,Sun]
    231 [Mon,Tue,Wed,Thu,Fri]
    232 [Sat,Sun]
    233 
    234 
    235 
    236 
    237 
    238 \end{haskell}
    239 \end{tabular}
    240 \end{cquote}
    241 \caption{Haskell Enumeration}
    242 \label{f:HaskellEnumeration}
    243 \end{figure}
    244 
    245 The key observation is the dichotomy between an ADT and enumeration: the ADT uses the associated type resulting in a union-like data structure, and the enumeration does not use the associated type, and hence, is not a union.
    246 While the enumeration is constructed using the ADT mechanism, it is so restricted it is not really an ADT.
    247 Furthermore, a general ADT cannot be an enumeration because the constructors generate different values making enumerating meaningless.
    248 While functional programming languages regularly repurpose the ADT type into an enumeration type, this process seems contrived and confusing.
    249 Hence, there is only a weak equivalence between an enumeration and ADT, justifying a separate enumeration type in a programming language.
     159Re-purposing the notion of enumerating into variant types is ill formed and confusing.
     160Hence, there is only a weak equivalence between an enumeration and variant type, justifying the enumeration type in a programming language.
    250161
    251162
    252163\section{Contributions}
    253164
    254 The goal of this work is to to extend the simple and unsafe enumeration type in the C programming-language into a complex and safe enumeration type in the \CFA programming-language, while maintaining backwards compatibility with C.
     165The goal of this work is to to extend the simple and unsafe enumeration type in the C programming-language into a sophisticated and safe type in the \CFA programming-language, while maintain backwards compatibility with C.
    255166On the surface, enumerations seem like a simple type.
    256167However, when extended with advanced features, enumerations become complex for both the type system and the runtime implementation.
    257168
    258 The contribution of this work are:
    259169\begin{enumerate}
    260170\item
     
    265175typing
    266176\item
    267 subseting
     177subset
    268178\item
    269179inheritance
  • doc/theses/jiada_liang_MMath/relatedwork.tex

    r7042c60 rcf191ac  
    2323\section{Pascal}
    2424\label{s:Pascal}
     25\lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    2526
    2627Classic Pascal has the \lstinline[language=pascal]{const} declaration binding a name to a constant literal/expression.
     
    5051
    5152\section{Ada}
    52 
    53 An Ada enumeration type is a set of ordered unscoped identifiers (enumerators) bound to \emph{unique} \Newterm{literals}.\footnote{%
    54 Ada is \emph{case-insensitive} so identifiers may appear in multiple forms and still be the same, \eg \lstinline{Mon}, \lstinline{moN}, and \lstinline{MON} (a questionable design decision).}
     53\lstnewenvironment{ada}[1][]{\lstset{language=[2005]Ada,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},literate={'}{\ttfamily'\!}1}\lstset{#1}}{}
     54
     55An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
    5556\begin{ada}
    56 type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun ); -- literals (enumerators)
     57type RGB is ( Red, Green, Blue ); -- 3 literals (enumerators)
    5758\end{ada}
    5859Object initialization and assignment are restricted to the enumerators of this type.
    59 While Ada enumerators are unscoped, like C, Ada enumerators are overloadable.
     60Enumerators 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.
     61To explicitly set enumerator values, \emph{all} enumerators must be set in \emph{ascending} order, \ie there is no auto-initialization.
    6062\begin{ada}
    61 type RGB is ( @Red@, @Green@, Blue );
     63type RGB is ( Red, Green, Blue );
     64@for RGB use ( Red => 10, Green => 20, Blue => 30 );@ -- ascending order
     65\end{ada}
     66Hence, the position, value, label tuples are:
     67\begin{ada}
     68(0, 10, RED)  (1, 20, GREEN)  (2, 30, BLUE)
     69\end{ada}
     70Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same, \eg @Red@ and @RED@ (a questionable design decision).
     71
     72Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope.
     73The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of enumerators, which is always ascending.
     74
     75Ada enumerators are overloadable.
     76\begin{ada}
    6277type Traffic_Light is ( @Red@, Yellow, @Green@ );
    6378\end{ada}
    64 Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded identifiers.
     79Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded names.
    6580\VRef[Figure]{f:AdaEnumeration} shows how ambiguity is handled using a cast, \ie \lstinline[language=ada]{RGB'(Red)}.
    6681
     
    87102\end{figure}
    88103
    89 Enumerators without initialization are auto-initialized from left to right, starting at zero, incrementing by 1.
    90 Enumerators with initialization must set \emph{all} enumerators in \emph{ascending} order, \ie there is no auto-initialization.
    91 \begin{ada}
    92 type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
    93 for Week use ( Mon => 0, Tue => 1, Wed => 2, Thu => @10@, Fri => 11, Sat => 14, Sun => 15 );
    94 \end{ada}
    95 The enumeration operators are the equality and relational operators, @=@, @/=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of acsending enumerators.
    96 
    97 Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package identifiers.
     104Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package names.
    98105\begin{ada}
    99106OtherRed : RGB renames Red;
     
    106113There are three pairs of inverse enumeration pseudo-functions (attributes): @'Pos@ and @'Val@, @'Enum_Rep@ and @'Enum_Val@, and @'Image@ and @'Value@,
    107114\begin{cquote}
     115\lstDeleteShortInline@
    108116\setlength{\tabcolsep}{15pt}
    109117\begin{tabular}{@{}ll@{}}
     
    120128\end{ada}
    121129\end{tabular}
     130\lstMakeShortInline@
    122131\end{cquote}
    123132These attributes are important for IO.
     
    129138\end{ada}
    130139which is syntactic sugar for the label and not character literals from the predefined type @Character@.
    131 The purpose is strictly readability using character literals rather than identifiers.
     140The purpose is strictly readability using character literals rather than names.
    132141\begin{ada}
    133142Op : Operator := '+';
     
    162171An enumeration type can be used in the Ada \lstinline[language=ada]{case} (all enumerators must appear or a default) or iterating constructs.
    163172\begin{cquote}
     173\lstDeleteShortInline@
    164174\setlength{\tabcolsep}{15pt}
    165175\begin{tabular}{@{}ll@{}}
     
    201211\end{ada}
    202212\end{tabular}
     213\lstMakeShortInline@
    203214\end{cquote}
    204215
     
    214225\section{\CC}
    215226\label{s:C++RelatedWork}
     227\lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    216228
    217229\CC has the equivalent of Pascal typed @const@ declarations \see{\VRef{s:Pascal}}, with static and dynamic initialization.
    218230\begin{c++}
    219 const auto one = 0 + 1;                                 $\C{// static initialization}$
     231const auto one = 0 + 1;                                 $\C{// static intialization}$
    220232const auto NULL = nullptr;
    221233const auto PI = 3.14159;
     
    225237                                Sat = Fri + 1, Sun = Sat + 1;
    226238int sa[Sun];
    227 const auto r = random();                                $\C{// dynamic initialization}$
     239const auto r = random();                                $\C{// dynamic intialization}$
    228240int da[r];                                                              $\C{// VLA}$
    229241\end{c++}
     
    307319\section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE
    308320\label{s:Csharp}
     321\lstnewenvironment{csharp}[1][]{\lstset{language=[Sharp]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    309322
    310323% https://www.tutorialsteacher.com/codeeditor?cid=cs-mk8Ojx
     
    349362\begin{figure}
    350363\centering
     364\lstDeleteShortInline@
    351365\begin{tabular}{@{}l|l@{}}
    352366\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
     
    400414\end{csharp}
    401415\end{tabular}
     416\lstMakeShortInline@
    402417\caption{\Csharp: Free Routine Versus Class Enumeration}
    403418\label{CsharpFreeVersusClass}
     
    406421
    407422\section{Golang}
     423\lstnewenvironment{Go}[1][]{\lstset{language=Go,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    408424
    409425Golang provides pseudo-enumeration similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
     
    413429const ( S = 0; T; USA = "USA"; U; V = 3.1; W ) $\C{// type change, implicit/explicit: 0 0 USA USA 3.1 3.1}$
    414430\end{Go}
    415 Constant identifiers are unscoped and must be unique (no overloading).
     431Constant names are unscoped and must be unique (no overloading).
    416432The first enumerator \emph{must} be explicitly initialized;
    417433subsequent enumerators can be implicitly or explicitly initialized.
     
    443459Basic switch and looping are possible.
    444460\begin{cquote}
     461\lstDeleteShortInline@
    445462\setlength{\tabcolsep}{15pt}
    446463\begin{tabular}{@{}ll@{}}
     
    465482\end{Go}
    466483\end{tabular}
     484\lstMakeShortInline@
    467485\end{cquote}
    468486However, the loop prints the values from 0 to 13 because there is no actual enumeration.
     
    470488
    471489\section{Java}
     490\lstnewenvironment{Java}[1][]{\lstset{language=Java,morekeywords={enum,assert,strictfp},
     491        escapechar=\$,moredelim=**[is][\color{red}]{!}{!},}\lstset{#1}}{}
    472492
    473493Every enumeration in Java is an enumeration class.
     
    493513\begin{figure}
    494514\centering
     515\lstDeleteShortInline@
    495516\begin{tabular}{@{}l|l@{}}
    496517\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
     
    532553\end{Java}
    533554\end{tabular}
     555\lstMakeShortInline@
    534556\caption{Java: Free Routine Versus Class Enumeration}
    535557\label{f:JavaFreeVersusClass}
     
    584606
    585607\section{Rust}
    586 % https://doc.rust-lang.org/reference/items/enumerations.html
     608\lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    587609
    588610Rust provides a scoped enumeration based on variant types.
     
    630652
    631653\section{Swift}
     654\lstnewenvironment{swift}[1][]{\lstset{language=Swift,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    632655
    633656% https://www.programiz.com/swift/online-compiler
     
    9871010
    9881011
    989 \section{Python 3.13}
    990 % https://docs.python.org/3/howto/enum.html
    991 
    992 Python is a dynamically-typed reflexive programming language with multiple versions, and hence, it is possible to extend existing or build new language features within the language.
    993 As a result, discussing Python enumerations is a moving target, because if a features does not exist, if can often be created with varying levels of complexity.
    994 Nevertheless, an attempt has been made to discuss core enumeration features that come with Python 3.13.
    995 
    996 A Python enumeration type is a set of ordered scoped identifiers (enumerators) bound to \emph{unique} values.
    997 An enumeration is not a basic type;
    998 it is a @class@ inheriting from the @Enum@ class, where the enumerators must be explicitly initialized, \eg:
    999 \begin{python}
    1000 class Week(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
    1001 \end{python}
    1002 and/or explicitly auto initialized, \eg:
    1003 \begin{python}
    1004 class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @auto()@; Sat = 4; Sun = @auto()@
    1005 \end{python}
    1006 where @auto@ increments by 1 from the previous enumerator value.
    1007 Object initialization and assignment are restricted to the enumerators of this type.
    1008 An enumerator initialized with same value is an alias and invisible at the enumeration level, \ie the alias it substituted for its aliasee.
    1009 \begin{python}
    1010 class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @10@; Sat = @10@; Sun = @10@
    1011 \end{python}
    1012 Here, the enumeration has only 4 enumerators and 3 aliases.
    1013 An alias is only visible by dropping down to the @class@ level and asking for class members.
    1014 @Enum@ only supports equality comparison between enumerator values;
    1015 the extended class @OrderedEnum@ adds relational operators @<@, @<=@, @>@, and @>=@.
    1016 
    1017 There are bidirectional enumeration pseudo-functions for label and value, but there is no concept of access using ordering (position).
    1018 \begin{cquote}
    1019 \setlength{\tabcolsep}{15pt}
    1020 \begin{tabular}{@{}ll@{}}
    1021 \begin{python}
    1022 Week.Thu.value == 10;
    1023 Week.Thu.name == 'Thu';
    1024 \end{python}
    1025 &
    1026 \begin{python}
    1027 Week( 10 ) == Thu
    1028 Week['Thu'].value = 10
    1029 \end{python}
    1030 \end{tabular}
    1031 \end{cquote}
    1032 
    1033 As an enumeration is a \lstinline[language=python]{class}, its own methods.
    1034 \begin{python}
    1035 class Week(Enum):
    1036         Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
    1037         $\\@$classmethod
    1038         def today(cls, date):
    1039                 return cls(date.isoweekday())
    1040 print( "today:", Week.today(date.today()))
    1041 today: Week.Mon
    1042 \end{python}
    1043 The method @today@ retrieves the day of the week and uses it as an index to print out the corresponding label of @Week@.
     1012\section{Python}
     1013\lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
     1014
     1015A Python enumeration is a set of symbolic names bound to \emph{unique} values.
     1016They are similar to global variables, but offer a more useful @repr()@, grouping, type-safety, and additional features.
     1017Enumerations inherits from the @Enum@ class, \eg:
     1018\begin{python}
     1019class Weekday(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
     1020class RGB(@Enum@): Red = 1; Green = 2; Blue = 3
     1021\end{python}
     1022
     1023Depending on the nature of the enum a member's value may or may not be important, but either way that value can be used to get the corresponding member:
     1024\begin{python}
     1025print( repr( Weekday( 3 ) ) )
     1026<Weekday.Wed: 3>
     1027\end{python}
     1028As you can see, the @repr()@ of a member shows the enum name, the member name, and the value.
     1029The @str()@ of a member shows only the enum name and member name:
     1030\begin{python}
     1031print( str( Weekday.Thu ), Weekday.Thu )
     1032Weekday.Thu Weekday.Thu
     1033\end{python}
     1034The type of an enumeration member is the enum it belongs to:
     1035\begin{python}
     1036print( type( Weekday.Thu ) )
     1037<enum 'Weekday'>
     1038print( isinstance(Weekday.Fri, Weekday) )
     1039True
     1040\end{python}
     1041Enum members have an attribute that contains just their name:
     1042\begin{python}
     1043print(Weekday.TUESDAY.name)
     1044TUESDAY
     1045\end{python}
     1046Likewise, they have an attribute for their value:
     1047\begin{python}
     1048Weekday.WEDNESDAY.value
     10493
     1050\end{python}
     1051
     1052Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added.
     1053For example, @datetime.date@ has two methods for returning the weekday: @weekday()@ and @isoweekday()@.
     1054The difference is that one of them counts from 0-6 and the other from 1-7.
     1055Rather than keep track of that ourselves we can add a method to the @Weekday@ enum to extract the day from the date instance and return the matching enum member:
     1056\begin{python}
     1057class Weekday(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = 15; Sat = 16; Sun = 17
     1058$@$classmethod
     1059def from_date(cls, date):
     1060        return cls(date.isoweekday())
     1061\end{python}
     1062Now we can find out what today is! Observe:
     1063\begin{python}
     1064>>> from datetime import date
     1065>>> Weekday.from_date(date.today())     
     1066<Weekday.TUESDAY: 2>
     1067\end{python}
     1068Of course, if you're reading this on some other day, you'll see that day instead.
     1069
     1070This Weekday enum is great if our variable only needs one day, but what if we need several? Maybe we're writing a function to plot chores during a week, and don't want to use a @list@ -- we could use a different type of @Enum@:
     1071\begin{python}
     1072from enum import Flag
     1073class WeekdayF(@Flag@): Mon = @1@; Tue = @2@; Wed = @4@; Thu = @8@; Fri = @16@; Sat = @32@; Sun = @64@
     1074\end{python}
     1075We've changed two things: we're inherited from @Flag@, and the values are all powers of 2.
    10441076
    10451077@Flag@ allows combining several members into a single variable:
    10461078\begin{python}
    1047 print( repr(WeekF.Sat | WeekF.Sun) )
    1048 <WeekF.Sun|Sat: 96>
     1079print( repr(WeekdayF.Sat | WeekdayF.Sun) )
     1080<WeekdayF.Sun|Sat: 96>
    10491081\end{python}
    10501082You can even iterate over a @Flag@ variable:
     
    10521084for day in weekend:
    10531085        print(day)
    1054 WeekF.Sat
    1055 WeekF.Sun
     1086Weekday.SATURDAY
     1087Weekday.SUNDAY
    10561088\end{python}
    10571089Okay, let's get some chores set up:
    10581090\begin{python}
    10591091>>> chores_for_ethan = {
    1060 ...    'feed the cat': Week.MONDAY | Week.WEDNESDAY | Week.FRIDAY,
    1061 ...    'do the dishes': Week.TUESDAY | Week.THURSDAY,
    1062 ...    'answer SO questions': Week.SATURDAY,
     1092...    'feed the cat': Weekday.MONDAY | Weekday.WEDNESDAY | Weekday.FRIDAY,
     1093...    'do the dishes': Weekday.TUESDAY | Weekday.THURSDAY,
     1094...    'answer SO questions': Weekday.SATURDAY,
    10631095...    }
    10641096\end{python}
     
    10691101...        if day in days:
    10701102...            print(chore)
    1071 >>> show_chores(chores_for_ethan, Week.SATURDAY)
     1103>>> show_chores(chores_for_ethan, Weekday.SATURDAY)
    10721104answer SO questions
    10731105\end{python}
    1074 Auto incrmenet for @Flag@ is by powers of 2.
    1075 \begin{python}
    1076 class WeekF(Flag): Mon = auto(); Tue = auto(); Wed = auto(); Thu = auto(); Fri = auto();  \
    1077                                                         Sat = auto(); Sun = auto(); Weekend = Sat | Sun
    1078 for d in WeekF:
    1079         print( f"{d.name}: {d.value}", end=" ")
    1080 Mon: 1 Tue: 2 Wed: 4 Thu: 8 Fri: 16 Sat: 32 Sun: 64 WeekA.Weekend
     1106In cases where the actual values of the members do not matter, you can save yourself some work and use @auto()@ for the values:
     1107\begin{python}
     1108>>> from enum import auto
     1109>>> class Weekday(Flag):
     1110...    MONDAY = auto()
     1111...    TUESDAY = auto()
     1112...    WEDNESDAY = auto()
     1113...    THURSDAY = auto()
     1114...    FRIDAY = auto()
     1115...    SATURDAY = auto()
     1116...    SUNDAY = auto()
     1117...    WEEKEND = SATURDAY | SUNDAY
    10811118\end{python}
    10821119
     
    10861123@Enum@ allows such access:
    10871124\begin{python}
    1088 print(RGB(1), RGB(3), )
    1089 RGB.RED RGB.GREEN
     1125>>> Color(1)
     1126<Color.RED: 1>
     1127>>> Color(3)
     1128<Color.BLUE: 3>
    10901129\end{python}
    10911130If you want to access enum members by name, use item access:
    10921131\begin{python}
    1093 print( RGBa['RED'], RGBa['GREEN'] )
    1094 RGB.RED RGB.GREEN
     1132Color['RED']
     1133<Color.RED: 1>
     1134
     1135Color['GREEN']
     1136<Color.GREEN: 2>
    10951137\end{python}
    10961138If you have an enum member and need its name or value:
    10971139\begin{python}
    1098 member = RGBa.RED
    1099 print( f"{member.name} {member.value}" )
    1100 RED 1
    1101 \end{python}
    1102 
     1140>>> member = Color.RED
     1141>>> member.name
     1142'RED'
     1143>>> member.value
     11441
     1145\end{python}
     1146
     1147\subsection{Duplicating enum members and values}
     1148
     1149An enum member can have other names associated with it.
     1150Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@.
     1151By-value lookup of the value of @A@ will return the member @A@.
     1152By-name lookup of @A@ will return the member @A@.
     1153By-name lookup of @B@ will also return the member @A@:
     1154\begin{python}
     1155class Shape(Enum): SQUARE = 2; DIAMOND = 1; CIRCLE = 3; ALIAS_FOR_SQUARE = 2
     1156>>> Shape.SQUARE
     1157<Shape.SQUARE: 2>
     1158>>> Shape.ALIAS_FOR_SQUARE
     1159<Shape.SQUARE: 2>
     1160>>> Shape(2)
     1161<Shape.SQUARE: 2>
     1162\end{python}
     1163
     1164Note: Attempting to create a member with the same name as an already defined attribute (another member, a method, etc.) or attempting to create an attribute with the same name as a member is not allowed.
    11031165
    11041166\subsection{Ensuring unique enumeration values}
     
    11451207>>> list(Shape)
    11461208[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
    1147 >>> list(Week)
    1148 [<Week.MONDAY: 1>, <Week.TUESDAY: 2>, <Week.WEDNESDAY: 4>, <Week.THURSDAY: 8>,
    1149 <Week.FRIDAY: 16>, <Week.SATURDAY: 32>, <Week.SUNDAY: 64>]
    1150 \end{python}
    1151 Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Week.WEEKEND@ aren't shown.
     1209>>> list(Weekday)
     1210[<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>,
     1211<Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]
     1212\end{python}
     1213Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Weekday.WEEKEND@ aren't shown.
    11521214
    11531215The special attribute @__members__@ is a read-only ordered mapping of names to members.
     
    21502212
    21512213\section{OCaml}
     2214\lstnewenvironment{ocaml}[1][]{\lstset{language=OCaml,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    21522215
    21532216% https://ocaml.org/docs/basic-data-types#enumerated-data-types
     
    21552218
    21562219OCaml provides a variant (union) type, where multiple heterogeneously-typed objects share the same storage.
    2157 The simplest form of the variant type is a list of nullary datatype constructors, which is like an unscoped, opaque enumeration.
    2158 
     2220The simplest form of the variant type is a list of nullary datatype constructors, which is like an unscoped, pure enumeration.
     2221
     2222(I think the value of a ocaml variants are types not object, so I am not sure about this line)
    21592223OCaml provides a variant (union) type, which is an aggregation of heterogeneous types.
    2160 A basic variant is a list of nullary datatype constructors, which is like an unscoped, opaque enumeration.
     2224A basic variant is a list of nullary datatype constructors, which is like an unscoped, pure enumeration.
    21612225\begin{ocaml}
    21622226type weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun
     
    21822246type colour = Red | Green of @string@ | Blue of @int * float@
    21832247\end{ocaml}
    2184 A variant with parameter is stored in a memory block, prefixed by an int tag and has its parameters stores as words in the block.
     2248A variant with parameter is stored in a memory block, prefixed by an int tag and has its parameters stores as words in the block. 
    21852249@colour@ is a summation of a nullary type, a unary product type of @string@, and a cross product of @int@ and @float@.
    21862250(Mathematically, a @Blue@ value is a Cartesian product of the types @int@ type and @float@.)
     
    21952259@Red, abc, 1 1.5@
    21962260\end{ocaml}
     2261
    21972262
    21982263A variant type can have a recursive definition.
     
    22152280
    22162281In summary, an OCaml variant is a singleton value rather than a set of possibly ordered values, and hence, has no notion of enumerabilty.
    2217 Therefore it is not an enumeration, except for the simple opaque (nullary) case.
     2282Therefore it is not an enumeration, except for the simple pure (nullary) case.
    22182283
    22192284\begin{comment}
     
    24012466With valediction,
    24022467  - Gregor Richards
    2403 
    2404 
    2405 Date: Tue, 16 Apr 2024 11:04:51 -0400
    2406 Subject: Re: C unnamed enumeration
    2407 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
    2408 CC: <ajbeach@uwaterloo.ca>, <j82liang@uwaterloo.ca>, <mlbrooks@uwaterloo.ca>,
    2409         <f37yu@uwaterloo.ca>
    2410 From: Gregor Richards <gregor.richards@uwaterloo.ca>
    2411 
    2412 On 4/16/24 09:55, Peter A. Buhr wrote:
    2413 > So what is a variant? Is it a set of tag names, which might be a union or is it
    2414 > a union, which might have tag names?
    2415 
    2416 Your tagless variant bears no resemblance to variants in any functional
    2417 programming language. A variant is a tag AND a union. You might not need to put
    2418 anything in the union, in which case it's a pointless union, but the named tag
    2419 is absolutely mandatory. That's the thing that varies.
    2420 
    2421 I was unaware of std::variant. As far as functional languages are concerned,
    2422 std::variant IS NOT A VARIANT. Perhaps it would be best to use the term ADT for
    2423 the functional language concept, because that term has no other meanings.
    2424 
    2425 An ADT cannot not have a named tag. That's meaningless. The tag is the data
    2426 constructor, which is the thing you actually define when you define an ADT. It
    2427 is strictly the union that's optional.
    2428 
    2429 With valediction,
    2430   - Gregor Richards
    24312468\end{comment}
    24322469
     
    24502487\hline
    24512488\hline
    2452 opaque                  &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
     2489pure                    &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
    24532490\hline
    24542491typed                   &               &               &               &               &               &               &               &               &               &               & @int@ & integral      & @T@   \\
  • doc/theses/jiada_liang_MMath/uw-ethesis.bib

    r7042c60 rcf191ac  
    22% For use with BibTeX
    33
    4 Oxford English Dictionary, s.v. ``enumerate (v.), sense 3,'' September 2023, https://doi.org/10.1093/OED/1113960777.
    5 @misc{OEDenumerate,
    6     keywords    = {enumerate},
    7     key         = {enumerate},
    8     title       = {enumerate (v.), sense 3},
    9     author      = {Oxford English Dictionary},
    10     howpublished= {\url{https://doi.org/10.1093/OED/1113960777}},
    11     month       = sep,
    12     year        = 2023,
    13 }
  • doc/theses/jiada_liang_MMath/uw-ethesis.tex

    r7042c60 rcf191ac  
    9595\CFAStyle                                               % CFA code-style
    9696\lstset{language=cfa,belowskip=-1pt} % set default language to CFA
    97 \lstnewenvironment{ada}[1][]{\lstset{language=[2005]Ada,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},literate={'}{\ttfamily'\!}1}\lstset{#1}}{}
    98 \lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    99 \lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    100 \lstnewenvironment{csharp}[1][]{\lstset{language=[Sharp]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    101 \lstnewenvironment{clang}[1][]{\lstset{language=[ANSI]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    102 \lstnewenvironment{Go}[1][]{\lstset{language=Go,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    103 \lstnewenvironment{haskell}[1][]{\lstset{language=Haskell,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    104 \lstnewenvironment{Java}[1][]{\lstset{language=Java,morekeywords={enum,assert,strictfp},
    105         escapechar=\$,moredelim=**[is][\color{red}]{!}{!},}\lstset{#1}}{}
    106 \lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    107 \lstnewenvironment{swift}[1][]{\lstset{language=Swift,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    108 \lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    109 \lstnewenvironment{ocaml}[1][]{\lstset{language=OCaml,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    110 
    111 \newsavebox{\myboxA}
    112 \newsavebox{\myboxB}
    11397
    11498\newcommand{\newtermFont}{\emph}
  • doc/uC++toCFA/Makefile

    r7042c60 rcf191ac  
    5656        dvips ${Build}/$< -o $@
    5757
    58 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${Macros}/common.tex ${Macros}/common.sty \
    59                 ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
     58${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \
     59                ${Macros}/common.sty ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
    6060        # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run.
    6161        if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi
  • doc/uC++toCFA/uC++toCFA.tex

    r7042c60 rcf191ac  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sat Apr 13 11:11:39 2024
    14 %% Update Count     : 5969
     13%% Last Modified On : Thu Jan 11 14:46:14 2024
     14%% Update Count     : 5942
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    141141\CFA uses parametric polymorphism and allows overloading of variables and routines:
    142142\begin{cfa}
    143 int i;  char i;  double i;      $\C[2in]{// overload name i}$
     143int i;  char i;  double i;              // overload name i
    144144int i();  double i();  char i();
    145 i += 1;                                         $\C{// int i}$
    146 i += 1.0;                                       $\C{// double i}$
    147 i += 'a';                                       $\C{// char i}$
    148 int j = i();                            $\C{// int i()}$
    149 double j = i();                         $\C{// double i();}$
    150 char j = i();                           $\C{// char i()}\CRT$
     145i += 1;                 $\C[1.5in]{// int i}$
     146i += 1.0;               $\C{// double i}$
     147i += 'a';               $\C{// char i}$
     148int j = i();    $\C{// int i()}$
     149double j = i(); $\C{// double i();}$
     150char j = i();   $\C{// char i()}\CRT$
    151151\end{cfa}
    152152\CFA has rebindable references.
    153 \begin{cquote}
    154 \begin{tabular}{@{}l|l@{}}
    155 \multicolumn{2}{@{}l}{\lstinline{       int x = 1, y = 2, * p1x = &x, * p1y = &y, ** p2i = &p1x,}} \\
    156 \multicolumn{2}{@{}l}{\lstinline{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ && r1x = x, & r1y = y, && r2i = r1x;}} \\
     153
     154\begin{cquote}
     155\begin{tabular}{l|l}
     156\multicolumn{2}{l}{\lstinline{  int x = 1, y = 2, * p1x = &x, * p1y = &y, ** p2i = &p1x,}} \\
     157\multicolumn{2}{l}{\lstinline{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ && r1x = x, & r1y = y, && r2i = r1x;}} \\
    157158\begin{uC++}
    158159**p2i = 3;
     
    200201
    201202\CFA output streams automatically separate values and insert a newline at the end of the print.
    202 \begin{cquote}
    203 \begin{tabular}{@{}l|l@{}}
     203
     204\begin{cquote}
     205\begin{tabular}{l|l}
    204206\begin{uC++}
    205207#include <@iostream@>
     
    224226
    225227\begin{cquote}
    226 \begin{tabular}{@{}l|l@{}}
     228\begin{tabular}{l|l}
    227229\begin{uC++}
    228230for ( @;;@ ) { ... }  /  while ( @true@ ) { ... }
     
    278280Currently, \CFA uses macros @ExceptionDecl@ and @ExceptionInst@ to declare and instantiate an exception.
    279281\begin{cquote}
    280 \begin{tabular}{@{}l|ll@{}}
     282\begin{tabular}{l|ll}
    281283\begin{uC++}
    282284
     
    319321
    320322\begin{cquote}
    321 \begin{tabular}{@{}l|ll@{}}
     323\begin{tabular}{l|ll}
    322324\begin{uC++}
    323325
     
    358360
    359361\begin{cquote}
    360 \begin{tabular}{@{}l|l@{}}
     362\begin{tabular}{l|l}
    361363\begin{uC++}
    362364struct S {
     
    381383
    382384\begin{cquote}
    383 \begin{tabular}{@{}l|l@{}}
    384 \multicolumn{2}{@{}l@{}}{\lstinline{string s1, s2;}} \\
     385\begin{tabular}{l|l}
     386\multicolumn{2}{l}{\lstinline{string s1, s2;}} \\
    385387\begin{uC++}
    386388s1 = "hi";
     
    423425
    424426\begin{cquote}
    425 \begin{tabular}{@{}l|l@{}}
     427\begin{tabular}{l|l}
    426428\begin{uC++}
    427429struct S {
     
    454456
    455457\begin{cquote}
    456 \begin{tabular}{@{}l|l@{}}
     458\begin{tabular}{l|l}
    457459\begin{uC++}
    458460
     
    491493
    492494\begin{cquote}
    493 \begin{tabular}{@{}l|ll@{}}
     495\begin{tabular}{l|ll}
    494496\begin{uC++}
    495497
     
    530532
    531533\begin{cquote}
    532 \begin{tabular}{@{}l|ll@{}}
     534\begin{tabular}{l|ll}
    533535\begin{uC++}
    534536
     
    565567
    566568\begin{cquote}
    567 \begin{tabular}{@{}l|ll@{}}
     569\begin{tabular}{l|ll}
    568570\begin{uC++}
    569571
     
    602604
    603605\begin{cquote}
    604 \begin{tabular}{@{}l|ll@{}}
     606\begin{tabular}{l|ll}
    605607\begin{uC++}
    606608
  • doc/user/Makefile

    r7042c60 rcf191ac  
    6060        dvips ${Build}/$< -o $@
    6161
    62 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} ${Macros}/common.tex ${Macros}/common.sty \
    63                 ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
     62${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \
     63                ${Macros}/common.sty ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
    6464        # Conditionally create an empty *.ind (index) file for inclusion until makeindex is run.
    6565        if [ ! -r ${basename $@}.ind ] ; then touch ${Build}/${basename $@}.ind ; fi
     
    7373        makeindex -s ${Macros}/indexstyle ${Build}/${basename $@}.idx
    7474        # Run again to finish citations
    75 #       ${LaTeX} ${basename $@}.tex
     75        ${LaTeX} ${basename $@}.tex
    7676        # Run again to get index title into table of contents
    7777#       ${LaTeX} ${basename $@}.tex
  • doc/user/user.tex

    r7042c60 rcf191ac  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Tue Apr 23 14:13:10 2024
    14 %% Update Count     : 6623
     13%% Last Modified On : Mon Feb 12 11:50:26 2024
     14%% Update Count     : 6199
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    6969\lstset{language=CFA}                                                                   % CFA default lnaguage
    7070\lstnewenvironment{C++}[1][]                            % use C++ style
    71 {\lstset{language=C++,escapechar=§,moredelim=**[is][\protect\color{red}]{®}{®},#1}}
     71{\lstset{language=C++,moredelim=**[is][\protect\color{red}]{®}{®},#1}}
    7272{}
    7373
     
    130130\vspace*{\fill}
    131131\noindent
    132 \copyright\,2016, 2018, 2021, 2024 \CFA Project \\ \\
     132\copyright\,2016, 2018, 2021 \CFA Project \\ \\
    133133\noindent
    134134This work is licensed under the Creative Commons Attribution 4.0 International License.
     
    312312For example, it is possible to write a type-safe \CFA wrapper ©malloc© based on the C ©malloc©:
    313313\begin{cfa}
    314 forall( T & | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); }
     314forall( dtype T | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); }
    315315int * ip = malloc(); §\C{// select type and size from left-hand side}§
    316316double * dp = malloc();
     
    10231023while () { sout | "empty"; break; }
    10241024do { sout | "empty"; break; } while ();
    1025 for () { sout | "empty"; break; }                               §\C[3in]{sout | nl | nlOff;}§
    1026 
    1027 for ( 0 ) { sout | "A"; } sout | "zero";                §\C{sout | nl;}§
    1028 for ( 1 ) { sout | "A"; }                                               §\C{sout | nl;}§
    1029 for ( 10 ) { sout | "A"; }                                              §\C{sout | nl;}§
    1030 for ( ~= 10 ) { sout | "A"; }                                   §\C{sout | nl;}§
    1031 for ( 1 ~= 10 ~ 2 ) { sout | "B"; }                             §\C{sout | nl;}§
    1032 for ( 1 -~= 10 ~ 2 ) { sout | "C"; }                    §\C{sout | nl;}§
    1033 for ( 0.5 ~ 5.5 ) { sout | "D"; }                               §\C{sout | nl;}§
    1034 for ( 0.5 -~ 5.5 ) { sout | "E"; }                              §\C{sout | nl;}§
    1035 for ( i; 10 ) { sout | i; }                                             §\C{sout | nl;}§
    1036 for ( i; ~= 10 ) { sout | i; }                                  §\C{sout | nl;}§
    1037 for ( i; 1 ~= 10 ~ 2 ) { sout | i; }                    §\C{sout | nl;}§
    1038 for ( i; 1 -~= 10 ~ 2 ) { sout | i; }                   §\C{sout | nl;}§
    1039 for ( i; 0.5 ~ 5.5 ) { sout | i; }                              §\C{sout | nl;}§
    1040 for ( i; 0.5 -~ 5.5 ) { sout | i; }                             §\C{sout | nl;}§
    1041 for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; }               §\C{sout | nl;}§
    1042 for ( ui; 2u -~= 10u ~ 2u ) { sout | ui; }              §\C{sout | nl | nl | nl;}§
     1025for () { sout | "empty"; break; }                                                       §\C{sout | nl | nlOff;}§
     1026
     1027for ( 0 ) { sout | "A"; } sout | "zero";                                        §\C{sout | nl;}§
     1028for ( 1 ) { sout | "A"; }                                                                       §\C{sout | nl;}§
     1029for ( 10 ) { sout | "A"; }                                                                      §\C{sout | nl;}§
     1030for ( ~= 10 ) { sout | "A"; }                                                           §\C{sout | nl;}§
     1031for ( 1 ~= 10 ~ 2 ) { sout | "B"; }                                                     §\C{sout | nl;}§
     1032for ( 1 -~= 10 ~ 2 ) { sout | "C"; }                                            §\C{sout | nl;}§
     1033for ( 0.5 ~ 5.5 ) { sout | "D"; }                                                       §\C{sout | nl;}§
     1034for ( 0.5 -~ 5.5 ) { sout | "E"; }                                                      §\C{sout | nl;}§
     1035for ( i; 10 ) { sout | i; }                                                                     §\C{sout | nl;}§
     1036for ( i; ~= 10 ) { sout | i; }                                                          §\C{sout | nl;}§
     1037for ( i; 1 ~= 10 ~ 2 ) { sout | i; }                                            §\C{sout | nl;}§
     1038for ( i; 1 -~= 10 ~ 2 ) { sout | i; }                                           §\C{sout | nl;}§
     1039for ( i; 0.5 ~ 5.5 ) { sout | i; }                                                      §\C{sout | nl;}§
     1040for ( i; 0.5 -~ 5.5 ) { sout | i; }                                                     §\C{sout | nl;}§
     1041for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; }                                       §\C{sout | nl;}§
     1042for ( ui; 2u -~= 10u ~ 2u ) { sout | ui; }                                      §\C{sout | nl | nl | nl;}§
    10431043
    10441044enum { N = 10 };
    1045 for ( N ) { sout | "N"; }                                               §\C{sout | nl;}§
    1046 for ( i; N ) { sout | i; }                                              §\C{sout | nl;}§
    1047 for ( i; -~ N ) { sout | i; }                                   §\C{sout | nl | nl | nl;}§
     1045for ( N ) { sout | "N"; }                                                                       §\C{sout | nl;}§
     1046for ( i; N ) { sout | i; }                                                                      §\C{sout | nl;}§
     1047for ( i; -~ N ) { sout | i; }                                                           §\C{sout | nl | nl | nl;}§
    10481048
    10491049const int low = 3, high = 10, inc = 2;
    1050 for ( i; low ~ high ~ inc + 1 ) { sout | i; }   §\C{sout | nl;}§
    1051 for ( i; 1 ~ @ ) { if ( i > 10 ) break; sout | i; } §\C{sout | nl;}§
    1052 for ( i; @ -~ 10 ) { if ( i < 0 ) break; sout | i; } §\C{sout | nl;}§
    1053 for ( i; 2 ~ @ ~ 2 ) { if ( i > 10 ) break; sout | i; } §\C{sout | nl;}§
     1050for ( i; low ~ high ~ inc + 1 ) { sout | i; }                           §\C{sout | nl;}§
     1051for ( i; 1 ~ @ ) { if ( i > 10 ) break; sout | i; }                     §\C{sout | nl;}§
     1052for ( i; @ -~ 10 ) { if ( i < 0 ) break; sout | i; }            §\C{sout | nl;}§
     1053for ( i; 2 ~ @ ~ 2 ) { if ( i > 10 ) break; sout | i; }         §\C{sout | nl;}§
    10541054for ( i; 2.1 ~ @ ~ @ ) { if ( i > 10.5 ) break; sout | i; i += 1.7; } §\C{sout | nl;}§
    10551055for ( i; @ -~ 10 ~ 2 ) { if ( i < 0 ) break; sout | i; }        §\C{sout | nl;}§
    10561056for ( i; 12.1 ~ @ ~ @ ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; } §\C{sout | nl;}§
    1057 for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }              §\C{sout | nl;}§
    1058 for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }             §\C{sout | nl;}§
    1059 for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }  §\C{sout | nl;}§
    1060 for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; } §\C{sout | nl;}§
    1061 for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }              §\C{sout | nl;}§
    1062 for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }             §\C{sout | nl;}§
    1063 for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }  §\C{sout | nl;}§
    1064 for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; } §\C{sout | nl;}§
     1057for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }                                      §\C{sout | nl;}§
     1058for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }                                     §\C{sout | nl;}§
     1059for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }                          §\C{sout | nl;}§
     1060for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }                         §\C{sout | nl;}§
     1061for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }                                      §\C{sout | nl;}§
     1062for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }                                     §\C{sout | nl;}§
     1063for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }                          §\C{sout | nl;}§
     1064for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }                         §\C{sout | nl;}§
    10651065for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } §\C{sout | nl;}§
    10661066for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } §\C{sout | nl;}§
    1067 for ( i; 5 : k; 1.5 ~ @ : j; @ -~ -5 ~ 2 ) { sout | i | j | k; } §\C{sout | nl;}\CRT§
     1067for ( i; 5 : k; 1.5 ~ @ : j; @ -~ -5 ~ 2 ) { sout | i | j | k; } §\C{sout | nl;}§
    10681068\end{cfa}
    10691069&
     
    29602960The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter ©x© of type array of 5 integers.
    29612961Since the strings overlap starting with the open bracket, ©[©, there is an ambiguous interpretation for the string.
    2962 
    29632962As well, \CFA-style declarations cannot be used to declare parameters for C-style routine-definitions because of the following ambiguity:
    29642963\begin{cfa}
     
    29662965int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§
    29672966\end{cfa}
    2968 The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to ©foo©.
     2967The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to foo.
    29692968The redefinition of a type name in a parameter list is the only context in C where the character ©*© can appear to the left of a type name, and \CFA relies on all type qualifier characters appearing to the right of the type name.
    29702969The inability to use \CFA declarations in these two contexts is probably a blessing because it precludes programmers from arbitrarily switching between declarations forms within a declaration contexts.
     
    30563055static [ int ] g ( int );
    30573056\end{cfa}
    3058 
    3059 
    3060 \subsection{Postfix Function}
    3061 \label{s:PostfixFunction}
    3062 \index{postfix function}
    3063 
    3064 \CFA provides an alternative call syntax where the argument appears before the function name.
    3065 The syntax uses the backquote ©`© to separate the parameters/arguments and function name: ©?`© denotes a postfix-function name, \eg ©int ?`h( int s )© and ©`© denotes a postfix-function call, \eg ©0`h© meaning ©h( 0 )©.
    3066 \begin{cquote}
    3067 \begin{tabular}{@{}l|l|l|l@{}}
    3068 postfix function & constant argument call & variable argument call & postfix function pointer \\
    3069 \hline
    3070 \begin{cfa}
    3071 int ?`h( int s );
    3072 int ?`h( double s );
    3073 int ?`m( char c );
    3074 int ?`m( const char * s );
    3075 int ?`t( int a, int b, int c );
    3076 \end{cfa}
    3077 &       
    3078 \begin{cfa}
    3079 0`h;
    3080 3.5`h;
    3081 '1'`m;
    3082 "123" "456"`m;
    3083 [1, 2, 3]`t;
    3084 \end{cfa}
    3085 &       
    3086 \begin{cfa}
    3087 int i = 7;
    3088 i`h;
    3089 (i + 3)`h;
    3090 (i + 3.5)`h;
    3091 \end{cfa}
    3092 &       
    3093 \begin{cfa}
    3094 int (* ?`p)( int i );
    3095 ?`p = ?`h;
    3096 3`p;
    3097 i`p;
    3098 (i + 3)`p;
    3099 \end{cfa}
    3100 \end{tabular}
    3101 \end{cquote}
    3102 Note, to pass \emph{multiple} arguments to a postfix function requires a \Index{tuple}, \eg ©[1, 2, 3]`t©, which forms a single argument that is flattened into the multiple arguments \see{\VRef{s:Tuple}}.
    3103 Similarly, if the argument is an expression, it must be parenthesized, \eg ©(i + 3)`h©, or only the last operand of the expression is the argument, \eg ©i + (3`h)©.
    3104 
    3105 \VRef[Figure]{f:UnitsComparison} shows a common usage for postfix functions: converting basic literals into user literals.
    3106 \see*{\VRef{s:DynamicStorageManagement} for other uses for postfix functions.}
    3107 The \CFA example (left) stores a mass in units of stones (1 stone = 14 lb or 6.35 kg) and provides an addition operator (imagine a full set of arithmetic operators).
    3108 The three postfixing function names ©st©, ©lb©, and ©kg©, represent units stones, pounds, and kilograms, respectively.
    3109 Each name has two forms that bidirectional convert: a value of a specified unit to stones, \eg ©w = 14`lb© $\Rightarrow$ ©w == 1© stone or a ©Weight© from stones back to specific units, \eg ©w`lb© (1 stone) to ©14©.
    3110 All arithmetic operations manipulate stones and the postfix operations convert to the different units.
    3111 A similar group of postfix functions provide user constants for converting time units into nanoseconds, which is the basic time unit, \eg ©ns©, ©us©, ©ms©, ©s©, ©m©, ©h©, ©d©, and ©w©, for nanosecond, microsecond, millisecond, second, minute, hour, day, and week, respectively.
    3112 (Note, month is not a fixed period of time nor is year because of leap years.)
    3113 
    3114 \begin{figure}
    3115 \centering
    3116 \begin{tabular}{@{}l|l@{}}
    3117 \multicolumn{1}{@{}c|}{\textbf{\CFA Postfix Routine}} & \multicolumn{1}{c@{}}{\textbf{\CC User Literals}} \\
    3118 \hline
    3119 \begin{cfa}
    3120 struct Weight {
    3121         double stones;
    3122 };
    3123 
    3124 
    3125 Weight ?+?( Weight l, Weight r ) {
    3126         return l.stones + r.stones;
    3127 }
    3128 Weight ®?`st®( double w ) { return w; }
    3129 double ®?`st®( Weight w ) { return w.stones; }
    3130 Weight ®?`lb®( double w ) { return w / 14.0; }
    3131 double ®?`lb®( Weight w ) { return w.stones * 14.0; }
    3132 Weight ®?`kg®( double w ) { return w / 6.35; }
    3133 double ®?`kg®( Weight w ) { return w.stones * 6.35; }
    3134 int main() {
    3135         Weight w, heavy = { 20 }; // stones
    3136         w = 155®`lb®;
    3137         w = 0b_1111®`st®;
    3138         w = 0_233®`lb®;
    3139         w = 0x_9b®`kg®;
    3140         w = 5.5®`st® + 8®`kg® + 25.01®`lb® + heavy;
    3141 }
    3142 \end{cfa}
    3143 &
    3144 \begin{C++}
    3145 struct Weight {
    3146         double stones;
    3147         Weight() {}
    3148         Weight( double w ) { stones = w; }
    3149 };
    3150 Weight operator+( Weight l, Weight r ) {
    3151         return l.stones + r.stones;
    3152 }
    3153 Weight operator®""_st®( long double w ) { return w; }
    3154 Weight operator®""_lb®( long double w ) { return w / 14.0; }
    3155 Weight operator®""_kg®( long double w ) { return w / 6.35; }
    3156 Weight operator®""_st®( unsigned long long int w ) { return w; }
    3157 Weight operator®""_lb®( unsigned long long int w ) { return w / 14.0; }
    3158 Weight operator®""_kg®( unsigned long long int w ) { return w / 6.35; }
    3159 int main() {
    3160         Weight w, heavy = { 20 }; // stones
    3161         w = 155®_lb®;
    3162         w = 0b1111®_st®;
    3163         w = 0'233®_lb®;         // quote separator
    3164         w = 0x9b®_kg®;
    3165         w = 5.5®_st® + 8®_kg® + 25.01®_lb® + heavy;
    3166 }
    3167 \end{C++}
    3168 \end{tabular}
    3169 
    3170 \begin{comment}
    3171 Time : comparison of time units. \\
    3172 \begin{tabular}{@{}ll@{}}
    3173 \CFA & \CC \\
    3174 \begin{cfa}
    3175 #include <fstream.hfa>
    3176 #include <time.hfa>
    3177 
    3178 
    3179 Duration s = 1`h + 2 * 10`m + 70`s / 10;
    3180 sout | "1 hour + 2*10 min + 70/10 sec = " | s | "seconds";
    3181 sout | "Dividing that by 2 minutes gives" | s / 2`m;
    3182 sout | "Dividing that by 2 gives" | s / 2 | "seconds\n";
    3183 sout | s | "seconds is"
    3184           | s`h | "hours,"
    3185           | (s % 1`h)`m | "minutes,"
    3186           | (s % 1`m)`s | "seconds";
    3187 \end{cfa}
    3188 &       
    3189 \begin{C++}
    3190 #include <iostream>
    3191 #include <chrono>
    3192 using namespace std;
    3193 using namespace std::chrono;
    3194 seconds s = hours(1) + 2 * minutes(10) + seconds(70) / 10;
    3195 cout << "1 hour + 2*10 min + 70/10 sec = " << s.count() << " seconds\n";
    3196 cout << "Dividing that by 2 minutes gives " << s / minutes(2) << '\n';
    3197 cout << "Dividing that by 2 gives " << (s / 2).count() << " seconds\n";
    3198 cout << s.count() << " seconds is "
    3199           << duration_cast<hours>( s ).count() << " hours, "
    3200           << duration_cast<minutes>( s % hours(1) ).count() << " minutes, "
    3201           << duration_cast<seconds>( s % minutes(1) ).count() << " seconds\n";
    3202 \end{C++}
    3203 \end{tabular}
    3204 \end{comment}
    3205 
    3206 \caption{Units: Stone, Pound, Kilogram Comparison}
    3207 \label{f:UnitsComparison}
    3208 \end{figure}
    3209 
    3210 The \CC example (right) provides a \emph{restricted} capability via user literals.
    3211 The \lstinline[language=C++]{operator ""} only takes a constant argument (\ie no variable argument), and the constant type must be the highest-level constant-type, \eg ©long double© for all floating-point constants.
    3212 As well, there is no constant conversion, \ie ©int© to ©double© constants, so integral constants are handled by a separate set of routines, with maximal integral type ©unsigned long long int©.
    3213 Finally, there is no mechanism to use this syntax for a bidirectional conversion because \lstinline[language=C++]{operator ""} does not accept variable arguments.
    32143057
    32153058
     
    35463389
    35473390\section{Tuple}
    3548 \label{s:Tuple}
    35493391
    35503392In C and \CFA, lists of elements appear in several contexts, such as the parameter list of a routine call.
     
    39673809\subsection{Polymorphism}
    39683810
    3969 Due to the implicit flattening and structuring conversions involved in argument passing, object and opaque parameters are restricted to matching only with non-tuple types.
     3811Due to the implicit flattening and structuring conversions involved in argument passing, ©otype© and ©dtype© parameters are restricted to matching only with non-tuple types.
    39703812The integration of polymorphism, type assertions, and monomorphic specialization of tuple-assertions are a primary contribution of this thesis to the design of tuples.
    39713813\begin{cfa}
    3972 forall(T, U &)
     3814forall(T, dtype U)
    39733815void f(T x, U * y);
    39743816
     
    42054047[ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = §\emph{expr}§;
    42064048\end{cfa}
    4207 The left-hand side is a tuple of \LstBasicStyle{\emph{\Index{lvalue}}}s, which is a list of expressions each yielding an address, \ie any data object that can appear on the left-hand side of a conventional assignment statement.
     4049\index{lvalue}
     4050The left-hand side is a tuple of \LstBasicStyle{\emph{lvalues}}, which is a list of expressions each yielding an address, \ie any data object that can appear on the left-hand side of a conventional assignment statement.
    42084051\LstBasicStyle{\emph{expr}} is any standard arithmetic expression.
    42094052Clearly, the types of the entities being assigned must be type compatible with the value of the expression.
     
    42434086Multiple assignment has the following form:
    42444087\begin{cfa}
    4245 [ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = [ §\emph{expr}§, ... , §\emph{expr}§ ];§
    4246 \end{cfa}
    4247 The left-hand side is a tuple of \LstBasicStyle{\emph{\Index{lvalue}}}s, and the right-hand side is a tuple of \LstBasicStyle{\emph{expr}}s.
    4248 Each \LstBasicStyle{\emph{expr}} appearing on the right-hand side of a multiple assignment statement is assigned to the corresponding \LstBasicStyle{\emph{lvalues}} on the left-hand side of the statement using parallel semantics for each assignment.
     4088[ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = [ §\emph{expr}§, ... , §\emph{expr}§ ];
     4089\end{cfa}
     4090\index{lvalue}
     4091The left-hand side is a tuple of \emph{lvalues}, and the right-hand side is a tuple of \emph{expr}s.
     4092Each \emph{expr} appearing on the right-hand side of a multiple assignment statement is assigned to the corresponding \emph{lvalues} on the left-hand side of the statement using parallel semantics for each assignment.
    42494093An example of multiple assignment is:
    42504094\begin{cfa}
     
    50814925        sout | '1' | '2' | '3';
    50824926        sout | 1 | "" | 2 | "" | 3;
    5083         sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x £" | 6 | "x ¥"
    5084                 | 7 | "x ¡" | 8 | "x ¿" | 9 | "x «" | 10;
     4927        sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x £" | 6 | "x Â¥"
     4928                | 7 | "x ¡" | 8 | "x ¿" | 9 | "x «" | 10;
    50854929        sout | 1 | ", x" | 2 | ". x" | 3 | "; x" | 4 | "! x" | 5 | "? x" | 6 | "% x"
    5086                 | 7 | "¢ x" | 8 | "» x" | 9 | ") x" | 10 | "] x" | 11 | "} x";
     4930                | 7 | "¢ x" | 8 | "» x" | 9 | ") x" | 10 | "] x" | 11 | "} x";
    50874931        sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x:" | 4 | ":x " | 5 | " x\t" | 6 | "\tx";
    50884932        sout | "x ( " | 1 | " ) x" | 2 | " , x" | 3 | " :x: " | 4;
     
    79317775\item[Rationale:] increase type safety
    79327776\item[Effect on original feature:] deletion of semantically well-defined feature.
    7933 \item[Difficulty of converting:] requires adding a cast \see{\VRef{s:DynamicStorageManagement} for better alternatives}:
     7777\item[Difficulty of converting:] requires adding a cast \see{\VRef{s:StorageManagement} for better alternatives}:
    79347778\begin{cfa}
    79357779        int * b = (int *)malloc( sizeof(int) );
     
    81437987\section{Standard Library}
    81447988\label{s:StandardLibrary}
    8145 \index{standard library}
    8146 
    8147 The \CFA standard-library extends existing C library routines by adding new function, wrapping existing explicitly-polymorphic C routines into implicitly-polymorphic versions, and adding new \CFA extensions.
    8148 
    8149 
    8150 \subsection{Dynamic Storage-Management}
    8151 \label{s:DynamicStorageManagement}
    8152 \index{dynamic storage-management}\index{storage management}
    8153 
    8154 Dynamic storage-management in C is based on explicit allocation and deallocation (©malloc©/©free©).
    8155 Programmer's must manage all allocated storage via its address (pointer) and subsequently deallocate the storage via this address.
    8156 Storage that is not deallocated becomes inaccessible, called a \newterm{memory leak}, which can only be detected at program termination.
    8157 Storage freed twice is an error, called a \newterm{duplicate free}, which can sometimes be detected.
    8158 Storage used after it is deallocated is an error, called using a \newterm{dangling pointer}, which can sometimes be detected.
    8159 
    8160 
    8161 \subsubsection{C Interface}
    8162 
    8163 C dynamic storage-management provides the following properties.
    8164 \begin{description}[leftmargin=*]
    8165 \item[fill]
    8166 storage after an allocation with a specified character or value.
     7989
     7990The \CFA standard-library wraps explicitly-polymorphic C routines into implicitly-polymorphic versions.
     7991
     7992
     7993\subsection{Storage Management}
     7994\label{s:StorageManagement}
     7995
     7996The storage-management routines extend their C equivalents by overloading, alternate names, providing shallow type-safety, and removing the need to specify the allocation size for non-array types.
     7997
     7998C storage management provides the following capabilities:
     7999\begin{description}
     8000\item[filled]
     8001after allocation with a specified character or value.
     8002\item[resize]
     8003an existing allocation to decreased or increased its size.
     8004In either case, new storage may or may not be allocated and, if there is a new allocation, as much data from the existing allocation is copied into the new allocation.
     8005For an increase in storage size, new storage after the copied data may be filled.
    81678006\item[align]
    81688007an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
    8169 \item[scale]
    8170 an allocation size to the specified number of array elements.
     8008\item[array]
     8009the allocation size is scaled to the specified number of array elements.
    81718010An array may be filled, resized, or aligned.
    8172 \item[resize]
    8173 an existing allocation to decreased or increased its size.
    8174 In either direction, new storage may or may not be allocated, but if there is a new allocation, as much data from the existing allocation is copied into the new allocation.
    8175 When new storage is allocated, it may be aligned and storage after copied data may be filled.
    81768011\end{description}
    8177 \VRef[Table]{t:AllocationVersusProperties} shows different combinations of storage-management properties provided by the C and \CFA allocation routines.
    8178 
     8012\VRef[Table]{t:AllocationVersusCapabilities} shows allocation routines supporting different combinations of storage-management capabilities.
    81798013\begin{table}
    8180 \caption{Allocation Routines versus Storage-Management Properties}
    8181 \label{t:AllocationVersusProperties}
    81828014\centering
    81838015\begin{minipage}{0.75\textwidth}
    81848016\begin{tabular}{@{}r|l|l|l|l|l@{}}
    8185                 & \multicolumn{1}{c|}{routine} & \multicolumn{1}{c|}{\textbf{fill}} & \textbf{alignment}        & \textbf{scale}        & \textbf{resize} \\
     8017\multicolumn{1}{c}{}&           & \multicolumn{1}{c|}{fill}     & resize        & alignment     & array \\
    81868018\hline
    81878019C               & ©malloc©                      & no                    & no            & no            & no    \\
    8188                 & ©calloc©                      & yes (0 only)  & no            & yes           & no    \\
    8189                 & ©realloc©                     & copy                  & no            & no            & yes   \\
    8190                 & ©reallocarray©        & copy                  & no            & yes           & yes   \\
    8191                 & ©memalign©            & no                    & yes           & no            & no    \\
    8192                 & ©aligned_alloc©\footnote{Same as ©memalign© but size is an integral multiple of alignment.}
    8193                                                         & no                    & yes           & no            & no    \\
    8194                 & ©posix_memalign©      & no                    & yes           & no            & no    \\
    8195                 & ©valloc©                      & no                    & yes (page size)& no   & no    \\
     8020                & ©calloc©                      & yes (0 only)  & no            & no            & yes   \\
     8021                & ©realloc©                     & copy                  & yes           & no            & no    \\
     8022                & ©memalign©            & no                    & no            & yes           & no    \\
     8023                & ©aligned_alloc©\footnote{Same as ©memalign© but size is an integral multiple of alignment, which is universally ignored.}
     8024                                                        & no                    & no            & yes           & no    \\
     8025                & ©posix_memalign©      & no                    & no            & yes           & no    \\
     8026                & ©valloc©                      & no                    & no            & yes (page size)& no   \\
    81968027                & ©pvalloc©\footnote{Same as ©valloc© but rounds size to multiple of page size.}
    8197                                                         & no                    & yes (page size)& no   & no    \\
    8198 \hline                                                                                                                                 
    8199 \CFA    & ©cmemalign©           & yes (0 only)  & yes           & yes           & no    \\
    8200                 & ©resize©                      & no copy               & yes           & no            & yes   \\
    8201                 & ©realloc©                     & copy                  & yes           & no            & yes   \\
    8202                 & ©alloc©\footnote{Multiple overloads with different parameters.}
    8203                                                         & yes                   & yes           & yes           & yes
     8028                                                        & no                    & no            & yes (page size)& no   \\
     8029\hline
     8030\CFA    & ©cmemalign©           & yes (0 only)  & no            & yes           & yes   \\
     8031                & ©realloc©                     & copy                  & yes           & yes           & no    \\
     8032                & ©alloc©                       & no                    & yes           & no            & yes   \\
     8033                & ©alloc_set©           & yes                   & yes           & no            & yes   \\
     8034                & ©alloc_align©         & no                    & yes           & yes           & yes   \\
     8035                & ©alloc_align_set©     & yes                   & yes           & yes           & yes   \\
    82048036\end{tabular}
    82058037\end{minipage}
    8206 \vspace*{-10pt}
     8038\caption{Allocation Routines versus Storage-Management Capabilities}
     8039\label{t:AllocationVersusCapabilities}
    82078040\end{table}
    82088041
    8209 
    8210 \subsubsection{\CFA Interface}
    8211 
    8212 \CFA dynamic memory management:
    8213 \begin{enumerate}[leftmargin=\parindent]
    8214 \item
    8215 extends type safety of all allocation routines by using the left-hand assignment type to determine the allocation size and alignment, and return a matching type for the new storage, which removes many common allocation errors.
    8216 \begin{cfa}
    8217 int * ip = (int *)malloc( sizeof(int) ); §\C[2.3in]{// C}§
    8218 int * ip = malloc();                                    §\C{// \CFA type-safe call of C malloc}§
    8219 int * ip = calloc();                                    §\C{// \CFA type-safe call of C calloc}§
    8220 struct __attribute__(( aligned(128) )) spinlock { ... }; // cache alignment
    8221 spinlock * slp = malloc();                              §\C{// correct size, alignment, and return type}\CRT§
    8222 \end{cfa}
    8223 Here, the alignment of the ©ip© storage is 16 (default) and 128 for ©slp©.
    8224 
    8225 \item
    8226 introduces the notion of \newterm{sticky properties} used in resizing.
    8227 All initial allocation properties are remembered and maintained for use should resize require new storage.
    8228 For example, the initial alignment and fill properties in the initial allocation
    8229 \begin{cfa}
    8230 struct __attribute__(( aligned(4096) )) S { ... };
    8231 S * sp = calloc( 10 );                                  §\C{// align 4K and zero fill}§
    8232 sp = reallocarray( sp, 100 );                   §\C{// preserve 4K alignment and zero fill new storage}§
    8233 \end{cfa}
    8234 are preserved in the resize so the new storage has the same alignment and extra storage after the data copy is zero filled.
    8235 Without sticky properties it is dangerous to resize, resulting in the C idiom of manually performing the reallocation to maintain correctness, which is error prone.
    8236 
    8237 \item
    8238 provides resizing without data copying, which is useful to repurpose an existing block of storage, rather than freeing the old storage and performing a new allocation.
    8239 A resize can take advantage of unused storage after the data to preventing a free/reallocation step altogether.
    8240 
    8241 \item
    8242 provides ©free©/©delete© functions that delete a variable number of allocations.
    8243 \begin{cfa}
    8244 int * ip = malloc(), * jp = malloc(), * kp = malloc();
    8245 double * xp = malloc(), * yp = malloc(), * zp = malloc();
    8246 free( ®ip, jp, kp, xp, yp, zp® );               §\C{// multiple deallocations}§
    8247 \end{cfa}
    8248 
    8249 \item
    8250 supports constructors for initialization of allocated storage and destructors for deallocation (like \CC).
    8251 \begin{cfa}
    8252 struct S { int v; };                                    §\C{// default constructors}§
    8253 void ^?{}( S & ) { ... }                                §\C{// destructor}§
    8254 S & sp = *®new®( 3 );                                   §\C{// allocate and call constructor}§
    8255 sout | sp.v;
    8256 ®delete®( &sp );                                                §\C{// call destructor}§
    8257 S * spa1 = ®anew®( 10, 5 ), * spa2 = ®anew®( 10, 8 ); §\C{// allocate array and call constructor for each array element}§
    8258 for ( i; 10 ) sout | spa1[i].v | spa2[i].v | nonl; sout | nl;
    8259 ®adelete®( spa1, spa2 );                                §\C{// call destructors on all array objects}§
    8260 
    8261 3
    8262 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8
     8042\CFA memory management extends the type safety of all allocations by using the type of the left-hand-side type to determine the allocation size and return a matching type for the new storage.
     8043Type-safe allocation is provided for all C allocation routines and new \CFA allocation routines, \eg in
     8044\begin{cfa}
     8045int * ip = (int *)malloc( sizeof(int) ); §\C{// C}§
     8046int * ip = malloc();                                    §\C{// \CFA type-safe version of C malloc}§
     8047int * ip = alloc();                                             §\C{// \CFA type-safe uniform alloc}§
     8048\end{cfa}
     8049the latter two allocations determine the allocation size from the type of ©p© (©int©) and cast the pointer to the allocated storage to ©int *©.
     8050
     8051\CFA memory management extends allocation safety by implicitly honouring all alignment requirements, \eg in
     8052\begin{cfa}
     8053struct S { int i; } __attribute__(( aligned( 128 ) )); // cache-line alignment
     8054S * sp = malloc();                                              §\C{// honour type alignment}§
     8055\end{cfa}
     8056the storage allocation is implicitly aligned to 128 rather than the default 16.
     8057The alignment check is performed at compile time so there is no runtime cost.
     8058
     8059\CFA memory management extends the resize capability with the notion of \newterm{sticky properties}.
     8060Hence, initial allocation capabilities are remembered and maintained when resize requires copying.
     8061For example, an initial alignment and fill capability are preserved during a resize copy so the copy has the same alignment and extended storage is filled.
     8062Without sticky properties it is dangerous to use ©realloc©, resulting in an idiom of manually performing the reallocation to maintain correctness.
     8063\begin{cfa}
     8064
     8065\end{cfa}
     8066
     8067\CFA memory management extends allocation to support constructors for initialization of allocated storage, \eg in
     8068\begin{cfa}
     8069struct S { int i; };                                    §\C{// cache-line alignment}§
     8070void ?{}( S & s, int i ) { s.i = i; }
     8071// assume ?|? operator for printing an S
     8072
     8073S & sp = *®new®( 3 );                                   §\C{// call constructor after allocation}§
     8074sout | sp.i;
     8075®delete®( &sp );
     8076
     8077S * spa = ®anew®( 10, 5 );                              §\C{// allocate array and initialize each array element}§
     8078for ( i; 10 ) sout | spa[i] | nonl;
     8079sout | nl;
     8080®adelete®( 10, spa );
    82638081\end{cfa}
    82648082Allocation routines ©new©/©anew© allocate a variable/array and initialize storage using the allocated type's constructor.
    82658083Note, the matching deallocation routines ©delete©/©adelete©.
    8266 \CC only supports the default constructor for intializing array elements.
    8267 \begin{C++}
    8268 S * sp = new S[10]®{5}®;                                §\C{// disallowed}§
    8269 \end{C++}
    8270 \end{enumerate}
    8271 
    8272 In addition, \CFA provides a new allocator interface to further increase orthogonality and usability of dynamic-memory allocation.
    8273 This interface helps programmers in three ways.
    8274 \begin{enumerate}
    8275 \item
    8276 naming: \CFA regular and ©ttype© polymorphism (similar to \CC variadic templates) is used to encapsulate a wide range of allocation functionality into a single routine name, so programmers do not have to remember multiple routine names for different kinds of dynamic allocations.
    8277 \item
    8278 named arguments: individual allocation properties are specified using postfix function call \see{\VRef{s:PostfixFunction}}, so programmers do not have to remember parameter positions in allocation calls.
    8279 \item
    8280 safe usage: like the \CFA's C-interface, programmers do not have to specify object size or cast allocation results.
    8281 \end{enumerate}
    8282 
    8283 The polymorphic functions
    8284 \begin{cfa}
    8285 T * alloc( ... );
    8286 T * alloc( size_t dim, ... );
    8287 \end{cfa}
    8288 are overloaded with a variable number of allocation properties.
    8289 These allocation properties can be passed as named arguments when calling the \Indexc{alloc} routine.
    8290 A call without parameters returns an uninitialized dynamically allocated object of type ©T© (\Indexc{malloc}).
    8291 A call with only the dimension (dim) parameter returns an uninitialized dynamically allocated array of objects with type ©T© (\Indexc{aalloc}).
    8292 The variable number of arguments consist of allocation properties to specialize the allocation.
    8293 The properties ©resize© and ©realloc© are associated with an existing allocation variable indicating how its storage is modified.
    8294 
    8295 The following allocation property functions may be combined and appear in any order as arguments to ©alloc©,
    8296 \begin{itemize}
    8297 \item
    8298 ©T_align ?`align( size_t alignment )© to align an allocation.
    8299 The alignment parameter must be $\ge$ the default alignment (©libAlign()© in \CFA) and a power of two, \eg the following return a dynamic object and object array aligned on a 256 and 4096-byte boundary.
    8300 \begin{cfa}
    8301 int * i0 = alloc( ®256`align® );  sout | i0 | nl;
    8302 int * i1 = alloc( 3, ®4096`align® );  for (i; 3 ) sout | &i1[i] | nonl;  sout | nl;
    8303 free( i0, i1 );
    8304 
    8305 0x5555565699®00®  // 256 alignment
    8306 0x55555656c®000® 0x5656c004 0x5656c008  // 4K array alignment
    8307 \end{cfa}
    8308 
    8309 \item
    8310 ©T_fill(T) ?`fill( /* various types */ )© to initialize storage.
    8311 There are three ways to fill storage:
    8312 \begin{enumerate}
    8313 \item
    8314 A ©char© fills every byte of each object.
    8315 \item
    8316 An object of the returned type fills each object.
    8317 \item
    8318 An object array pointer fills some or all of the corresponding object array.
    8319 \end{enumerate}
    8320 For example:
    8321 \begin{cfa}[numbers=left]
    8322 int * i0 = alloc( ®0n`fill® );  sout | *i0 | nl;  // 0n disambiguates 0p
    8323 int * i1 = alloc( ®5`fill® );  sout | *i1 | nl;
    8324 int * i2 = alloc( ®'\xfe'`fill® ); sout | hex( *i2 ) | nl;
    8325 int * i3 = alloc( 5, ®5`fill® );  for ( i; 5 ) sout | i3[i] | nonl; sout | nl;
    8326 int * i4 = alloc( 5, ®0xdeadbeefN`fill® );  for ( i; 5 ) sout | hex( i4[i] ) | nonl; sout | nl;
    8327 int * i5 = alloc( 5, ®i3`fill® );  for ( i; 5 ) sout | i5[i] | nonl; sout | nl; // completely fill from i3
    8328 int * i6 = alloc( 5, ®[i3, 3]`fill® );  for ( i; 5 ) sout | i6[i] | nonl; sout | nl; // partial fill from i3
    8329 free( i0, i1, i2, i3, i4, i5, i6 );
    8330 \end{cfa}
    8331 \begin{lstlisting}[numbers=left]
    8332 0
    8333 5
    8334 0xfefefefe
    8335 5 5 5 5 5
    8336 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    8337 5 5 5 5 5
    8338 5 5 5 -555819298 -555819298  // two undefined values
    8339 \end{lstlisting}
    8340 Examples 1 to 3 fill an object with a value or characters.
    8341 Examples 4 to 7 fill an array of objects with values, another array, or part of an array.
    8342 
    8343 \item
    8344 ©S_resize(T) ?`resize( void * oaddr )© used to resize, realign, and fill, where the old object data is not copied to the new object.
    8345 The old object type may be different from the new object type, since the values are not used.
    8346 For example:
    8347 \begin{cfa}[numbers=left]
    8348 int * ip = alloc( ®5`fill® );  sout | ip | *ip;
    8349 ip = alloc( ®ip`resize®, ®256`align®, ®7`fill® );  sout | ip | *ip;
    8350 double * dp = alloc( ®ip`resize®, ®4096`align®, ®13.5`fill® );  sout | dp | *dp;
    8351 free( dp );  // DO NOT FREE ip AS ITS STORAGE IS MOVED TO dp
    8352 \end{cfa}
    8353 \begin{lstlisting}[numbers=left]
    8354 0x555555580a80 5
    8355 0x555555581100 7
    8356 0x555555587000 13.5
    8357 \end{lstlisting}
    8358 Examples 2 to 3 change the alignment, fill, and size for the initial storage of ©i©.
    8359 
    8360 \begin{cfa}[numbers=left]
    8361 int * ia = alloc( 5, ®5`fill® );  sout | ia | nonl;  for ( i; 5 ) sout | ia[i] | nonl; sout | nl;
    8362 ia = alloc( 10, ®ia`resize®, ®7`fill® );  sout | ia | nonl;  for ( i; 10 ) sout | ia[i] | nonl; sout | nl;
    8363 ia = alloc( 5, ®ia`resize®, ®512`align®, ®13`fill® ); sout | ia | nonl; for ( i; 5 ) sout | ia[i] | nonl; sout | nl;;
    8364 ia = alloc( 3, ®ia`resize®, ®4096`align®, ®2`fill® );  for ( i; 3 ) sout | &ia[i] | ia[i] | nonl; sout | nl;
    8365 free( ia );
    8366 \end{cfa}
    8367 \begin{lstlisting}[numbers=left]
    8368 0x55555656d540 5 5 5 5 5
    8369 0x55555656d480 7 7 7 7 7 7 7 7 7 7
    8370 0x55555656fe00 13 13 13 13 13
    8371 0x555556570000 2 0x555556570004 2 0x555556570008 2
    8372 \end{lstlisting}
    8373 Examples 2 to 4 change the array size, alignment, and fill initializes all storage because no data is copied.
    8374 
    8375 \item
    8376 ©S_realloc(T) ?`realloc( T * a ))©
    8377 used to resize, realign, and fill, where the old object data is copied to the new object.
    8378 The old object type must be the same as the new object type, since the value is used.
    8379 Note, for ©fill©, only the extra space after copying the data from the old object is filled with the given parameter.
    8380 For example:
    8381 \begin{cfa}[numbers=left]
    8382 int * ip = alloc( ®5`fill® );  sout | ip | *ip;
    8383 ip = alloc( ®ip`realloc®, ®256`align® );  sout | ip | *ip;
    8384 ip = alloc( ®ip`realloc®, ®4096`align®, ®13`fill® );  sout | ip | *ip;
    8385 free( ip );
    8386 \end{cfa}
    8387 \begin{lstlisting}[numbers=left]
    8388 0x55555556d5c0 5
    8389 0x555555570000 5
    8390 0x555555571000 5
    8391 \end{lstlisting}
    8392 Examples 2 to 3 change the alignment for the initial storage of ©i©.
    8393 The ©13`fill© in example 3 does nothing because no new storage is added.
    8394 
    8395 \begin{cfa}[numbers=left]
    8396 int * ia = alloc( 5, ®5`fill® );  sout | ia | nonl;  for ( i; 5 ) sout | ia[i] | nonl; sout | nl;
    8397 ia = alloc( 10, ®ia`realloc®, ®7`fill® );  sout | ia | nonl;  for ( i; 10 ) sout | ia[i] | nonl; sout | nl;
    8398 ia = alloc( 5, ®ia`realloc®, ®512`align®, ®13`fill® );  sout | ia | nonl; for ( i; 5 ) sout | ia[i] | nonl; sout | nl;;
    8399 ia = alloc( 3, ®ia`realloc®, ®4096`align®, ®2`fill® );  for ( i; 3 ) sout | &ia[i] | ia[i] | nonl; sout | nl;
    8400 free( ia );
    8401 \end{cfa}
    8402 \begin{lstlisting}[numbers=left]
    8403 0x55555656d540 5 5 5 5 5
    8404 0x55555656d480 7 7 7 7 7 7 7 7 7 7
    8405 0x555556570e00 5 5 5 5 5
    8406 0x5555556571000 5 0x555556571004 5 0x555556571008 5
    8407 \end{lstlisting}
    8408 Examples 2 to 4 change the array size, alignment, and fill does no initialization after the copied data, as no new storage is added.
    8409 \end{itemize}
    8410 
    8411 \medskip
     8084
     8085\leavevmode
    84128086\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    84138087extern "C" {
    8414         // New C allocation operations.
    8415         void * aalloc( size_t dim, size_t elemSize );§\indexc{aalloc}§
    8416         void * resize( void * oaddr, size_t size );§\indexc{resize}§
    8417         void * amemalign( size_t align, size_t dim, size_t elemSize );§\indexc{amemalign}§
    8418         void * cmemalign( size_t align, size_t dim, size_t elemSize );§\indexc{cmemalign}§
    8419         size_t malloc_alignment( void * addr );§\indexc{malloc_alignment}§
    8420         bool malloc_zero_fill( void * addr );§\indexc{malloc_zero_fill}§
    8421         size_t malloc_size( void * addr );§\indexc{malloc_size}§
    8422         int malloc_stats_fd( int fd );§\indexc{malloc_stats_fd}§
    8423         size_t malloc_expansion();§\indexc{malloc_expansion}§ §\C{// heap expansion size (bytes)}§
    8424         size_t malloc_mmap_start();§\indexc{malloc_mmap_start}§ §\C{// crossover allocation size from sbrk to mmap}§
    8425         size_t malloc_unfreed();§\indexc{malloc_unfreed()}§     §\C{// heap unfreed size (bytes)}§
    8426         void malloc_stats_clear();§\indexc{malloc_stats_clear}§ §\C{// clear heap statistics}§
    8427 }
    8428 
    8429 // New allocation operations.
    8430 void * resize( void * oaddr, size_t alignment, size_t size );
    8431 void * realloc( void * oaddr, size_t alignment, size_t size );
    8432 void * reallocarray( void * oaddr, size_t nalign, size_t dim, size_t elemSize );
    8433 
    8434 forall( T & | sized(T) ) {
    8435         // §\CFA§ safe equivalents, i.e., implicit size specification, eliminate return-type cast
    8436         T * malloc( void );§\indexc{malloc}§
    8437         T * aalloc( size_t dim );§\indexc{aalloc}§
    8438         T * calloc( size_t dim );§\indexc{calloc}§
    8439         T * resize( T * ptr, size_t size );§\indexc{resize}§
    8440         T * resize( T * ptr, size_t alignment, size_t size );
    8441         T * realloc( T * ptr, size_t size );§\indexc{realloc}§
    8442         T * realloc( T * ptr, size_t alignment, size_t size );
    8443         T * reallocarray( T * ptr, size_t dim );§\indexc{reallocarray}§
    8444         T * reallocarray( T * ptr, size_t alignment, size_t dim );
    8445         T * memalign( size_t align );§\indexc{memalign}§
    8446         T * amemalign( size_t align, size_t dim );§\indexc{amemalign}§
    8447         T * cmemalign( size_t align, size_t dim );§\indexc{aalloc}§
    8448         T * aligned_alloc( size_t align );§\indexc{aligned_alloc}§
    8449         int posix_memalign( T ** ptr, size_t align );§\indexc{posix_memalign}§
    8450         T * valloc( void );§\indexc{valloc}§
    8451         T * pvalloc( void );§\indexc{pvalloc}§
     8088        // C unsafe allocation
     8089        void * malloc( size_t size );§\indexc{malloc}§
     8090        void * calloc( size_t dim, size_t size );§\indexc{calloc}§
     8091        void * realloc( void * ptr, size_t size );§\indexc{realloc}§
     8092        void * memalign( size_t align, size_t size );§\indexc{memalign}§
     8093        void * aligned_alloc( size_t align, size_t size );§\indexc{aligned_alloc}§
     8094        int posix_memalign( void ** ptr, size_t align, size_t size );§\indexc{posix_memalign}§
     8095        void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize );§\indexc{cmemalign}§ // CFA
     8096
     8097        // C unsafe initialization/copy
     8098        void * memset( void * dest, int c, size_t size );§\indexc{memset}§
     8099        void * memcpy( void * dest, const void * src, size_t size );§\indexc{memcpy}§
     8100}
     8101
     8102void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap
     8103
     8104forall( dtype T | sized(T) ) {
     8105        // §\CFA§ safe equivalents, i.e., implicit size specification
     8106        T * malloc( void );
     8107        T * calloc( size_t dim );
     8108        T * realloc( T * ptr, size_t size );
     8109        T * memalign( size_t align );
     8110        T * cmemalign( size_t align, size_t dim  );
     8111        T * aligned_alloc( size_t align );
     8112        int posix_memalign( T ** ptr, size_t align );
    84528113
    84538114        // §\CFA§ safe general allocation, fill, resize, alignment, array
    8454         T * alloc( ... );§\indexc{alloc}§                                       §\C{// variable, T size}§
    8455         T * alloc( size_t dim, ... );
    8456         T_align ?`align( size_t alignment );§\indexc{align}§
    8457         T_fill(T) ?`fill( /* various types */ );§\indexc{fill}§
    8458         T_resize ?`resize( void * oaddr );§\indexc{resize}§
    8459         T_realloc ?`realloc( void * oaddr ));§\indexc{realloc}§
    8460 }
    8461 
    8462 forall( T &, List ... ) void free( T * ptr, ... ) // deallocation list
     8115        T * alloc( void );§\indexc{alloc}§                                      §\C[3.5in]{// variable, T size}§
     8116        T * alloc( size_t dim );                                                        §\C{// array[dim], T size elements}§
     8117        T * alloc( T ptr[], size_t dim );                                       §\C{// realloc array[dim], T size elements}§
     8118
     8119        T * alloc_set( char fill );§\indexc{alloc_set}§         §\C{// variable, T size, fill bytes with value}§
     8120        T * alloc_set( T fill );                                                        §\C{// variable, T size, fill with value}§
     8121        T * alloc_set( size_t dim, char fill );                         §\C{// array[dim], T size elements, fill bytes with value}§
     8122        T * alloc_set( size_t dim, T fill );                            §\C{// array[dim], T size elements, fill elements with value}§
     8123        T * alloc_set( size_t dim, const T fill[] );            §\C{// array[dim], T size elements, fill elements with array}§
     8124        T * alloc_set( T ptr[], size_t dim, char fill );        §\C{// realloc array[dim], T size elements, fill bytes with value}§
     8125
     8126        T * alloc_align( size_t align );                                        §\C{// aligned variable, T size}§
     8127        T * alloc_align( size_t align, size_t dim );            §\C{// aligned array[dim], T size elements}§
     8128        T * alloc_align( T ptr[], size_t align );                       §\C{// realloc new aligned array}§
     8129        T * alloc_align( T ptr[], size_t align, size_t dim ); §\C{// realloc new aligned array[dim]}§
     8130
     8131        T * alloc_align_set( size_t align, char fill );         §\C{// aligned variable, T size, fill bytes with value}§
     8132        T * alloc_align_set( size_t align, T fill );            §\C{// aligned variable, T size, fill with value}§
     8133        T * alloc_align_set( size_t align, size_t dim, char fill ); §\C{// aligned array[dim], T size elements, fill bytes with value}§
     8134        T * alloc_align_set( size_t align, size_t dim, T fill ); §\C{// aligned array[dim], T size elements, fill elements with value}§
     8135        T * alloc_align_set( size_t align, size_t dim, const T fill[] ); §\C{// aligned array[dim], T size elements, fill elements with array}§
     8136        T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ); §\C{// realloc new aligned array[dim], fill new bytes with value}§
     8137
     8138        // §\CFA§ safe initialization/copy, i.e., implicit size specification
     8139        T * memset( T * dest, char fill );§\indexc{memset}§
     8140        T * memcpy( T * dest, const T * src );§\indexc{memcpy}§
     8141
     8142        // §\CFA§ safe initialization/copy, i.e., implicit size specification, array types
     8143        T * amemset( T dest[], char fill, size_t dim );
     8144        T * amemcpy( T dest[], const T src[], size_t dim );
     8145}
    84638146
    84648147// §\CFA§ allocation/deallocation and constructor/destructor, non-array types
    8465 forall( T &, Parms ... | { void ?{}( T &, Parms ); } ) T * new( Parms ... );§\indexc{new}§
    8466 forall( T &, List ... | { void ^?{}( T & ); void delete( List ... ); } );§\indexc{delete}§
     8148forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p );§\indexc{new}§
     8149forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void delete( T * ptr );§\indexc{delete}§
     8150forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } )
     8151  void delete( T * ptr, Params rest );
     8152
    84678153// §\CFA§ allocation/deallocation and constructor/destructor, array types
    8468 forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } ) T * anew( size_t dim, Parms ... );§\indexc{anew}§
    8469 forall( T & | sized(T) | { void ^?{}( T & ); }, List ... } ) void adelete( T arr[], List ... );§\indexc{adelete}§
    8470 \end{cfa}
    8471 
    8472 
    8473 \subsection{Memory Set and Copy}
    8474 
    8475 Like safe memory allocation, \CFA provides safe block initialization and copy.
    8476 While objects should be initialized/copied with constructors/assignment, block operations can be very performant.
    8477 In certain cases the compiler generates block copy operations, such as assigning structures ©s = t©, however C arrays cannot be assigned.
    8478 \begin{cquote}
    8479 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    8480 struct S { int i, j, k; };
    8481 S s, t, *sp = &s, * tp = &t, sa[10], ta[10];
    8482 \end{cfa}
    8483 \noindent
    8484 \begin{tabular}{@{}l|l@{}}
    8485 \multicolumn{1}{@{}c|}{\textbf{\CFA}} & \multicolumn{1}{c@{}}{\textbf{C}} \\
    8486 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    8487 memset( s, '\0' );
    8488 memset( sp, '\0' );
    8489 
    8490 memcpy( s, t );
    8491 memcpy( sp, tp );
    8492 
    8493 amemset( sa, '\0', 10 );
    8494 amemcpy( sa, ta, 10 );
    8495 \end{cfa}
    8496 &
    8497 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    8498 memset( &s, '\0', sizeof(s) );
    8499 memset( sp, '\0', sizeof(s) );
    8500 
    8501 memcpy( &s, &t, sizeof(s) );
    8502 memcpy( sp, tp, sizeof(s) );
    8503 
    8504 memset( sa, '\0', sizeof(sa) );
    8505 memcpy( sa, ta, sizeof(sa) );
    8506 \end{cfa}
    8507 \end{tabular}
    8508 \end{cquote}
    8509 These operations provide uniformity between reference and pointer, so object dereferencing, '©&©', is unnecessary.
    8510 
    8511 \begin{cfa}
    8512 static inline forall( T & | sized(T) ) {
    8513         // CFA safe initialization/copy, i.e., implicit size specification, non-array types
    8514         T * memset( T * dest, char fill );§\indexc{memset}§     §\C{// all combinations of pointer/reference}§
    8515         T * memset( T & dest, char fill );
    8516 
    8517         T * memcpy( T * dest, const T * src );§\indexc{memcpy}§ §\C{// all combinations of pointer/reference}§
    8518         T * memcpy( T & dest, const T & src );
    8519         T * memcpy( T * dest, const T & src );
    8520         T * memcpy( T & dest, const T * src );
    8521 
    8522         // CFA safe initialization/copy, i.e., implicit size specification, array types
    8523         T * amemset( T dest[], char fill, size_t dim );§\indexc{memcpy}§
    8524         T * amemcpy( T dest[], const T src[], size_t dim );
    8525 }
     8154forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p );§\indexc{anew}§
     8155forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );§\indexc{adelete}§
     8156forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } )
     8157  void adelete( size_t dim, T arr[], Params rest );
    85268158\end{cfa}
    85278159
     
    96589290Int sqrt( Int oper );
    96599291
    9660 forall( istype & | istream( istype ) ) istype * ?|?( istype * is, Int * mp );  §\C{// I/O}§
    9661 forall( ostype & | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
     9292forall( dtype istype | istream( istype ) ) istype * ?|?( istype * is, Int * mp );  §\C{// I/O}§
     9293forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
    96629294\end{cfa}
    96639295\VRef[Figure]{f:MultiPrecisionFactorials} shows \CFA and C factorial programs using the GMP interfaces.
     
    96679299\begin{cquote}
    96689300\begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}}
    9669 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{C}}   \\
     9301\multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{C}}    & \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{\CFA}}        \\
    96709302\hline
    9671 \begin{cfa}
    9672 #include <gmp.hfa>§\indexc{gmp}§
    9673 int main( void ) {
    9674         sout | "Factorial Numbers";
    9675         ®Int® fact = 1;
    9676 
    9677         sout | 0 | fact;
    9678         for ( i; 40 ) {
    9679                 fact *= i;
    9680                 sout | i | fact;
    9681         }
    9682 }
    9683 \end{cfa}
    9684 &
    96859303\begin{cfa}
    96869304#include <gmp.h>§\indexc{gmp.h}§
     
    96939311                ®mpz_mul_ui®( fact, fact, i );
    96949312                ®gmp_printf®( "%d %Zd\n", i, fact );
     9313        }
     9314}
     9315\end{cfa}
     9316&
     9317\begin{cfa}
     9318#include <gmp.hfa>§\indexc{gmp}§
     9319int main( void ) {
     9320        sout | "Factorial Numbers";
     9321        Int fact = 1;
     9322
     9323        sout | 0 | fact;
     9324        for ( i; 40 ) {
     9325                fact *= i;
     9326                sout | i | fact;
    96959327        }
    96969328}
     
    97879419Rational narrow( double f, long int md );
    97889420
    9789 forall( istype & | istream( istype ) ) istype * ?|?( istype *, Rational * ); // I/O
    9790 forall( ostype & | ostream( ostype ) ) ostype * ?|?( ostype *, Rational );
     9421forall( dtype istype | istream( istype ) ) istype * ?|?( istype *, Rational * ); // I/O
     9422forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype *, Rational );
    97919423\end{cfa}
    97929424
     
    98089440\end{document}
    98099441
    9810 From: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>
    9811 To: Peter Buhr <pabuhr@uwaterloo.ca>,
    9812         Andrew James Beach
    9813         <ajbeach@uwaterloo.ca>,
    9814         Fangren Yu <f37yu@uwaterloo.ca>, Jiada Liang
    9815         <j82liang@uwaterloo.ca>
    9816 Subject: The White House on Memory-Safe programming
    9817 Date: Mon, 4 Mar 2024 16:49:53 +0000
    9818 
    9819 I heard tell of this announcement last night.  Haven't read the actual report yet.
    9820 
    9821 Most mainstream article I can find:  https://me.pcmag.com/en/security/22413/white-house-to-developers-using-c-or-c-invites-cybersecurity-risks
    9822 Less fluffy summary:  https://www.developer-tech.com/news/2024/feb/27/white-house-urges-adoption-memory-safe-programming-languages/
    9823 Horse's Mouth:  https://www.whitehouse.gov/wp-content/uploads/2024/02/Final-ONCD-Technical-Report.pdf
    9824 "This report focuses on the programming language as a primary building block, and explores hardware architecture and formal methods as complementary approaches"
    9825 
    9826 A contrary analysis:  https://hackaday.com/2024/02/29/the-white-house-memory-safety-appeal-is-a-security-red-herring/
    9827 
    98289442% Local Variables: %
    98299443% tab-width: 4 %
  • libcfa/src/concurrency/actor.hfa

    r7042c60 rcf191ac  
    299299
    300300        if ( seperate_clus ) {
    301                 this.cluster = alloc();
     301                cluster = alloc();
    302302                (*cluster){};
    303303        } else cluster = active_cluster();
     
    360360        adelete( worker_req_queues );
    361361        adelete( processors );
    362         if ( seperate_clus ) delete( this.cluster );
     362        if ( seperate_clus ) delete( cluster );
    363363
    364364        #ifdef ACTOR_STATS // print formatted stats
  • libcfa/src/concurrency/kernel/fwd.hfa

    r7042c60 rcf191ac  
    374374                                // since if that is the case, the oneshot was fulfilled (unparking this thread)
    375375                                // and the oneshot should not be needed any more
    376                                 struct oneshot * was __attribute__((unused)) = this.ptr; // used in option verify
     376                                __attribute__((unused)) struct oneshot * was = this.ptr;
    377377                                /* paranoid */ verifyf( was == future_FULFILLED, "Expected this.ptr to be 1p, was %p\n", was );
    378378
  • libcfa/src/device/cpu.cfa

    r7042c60 rcf191ac  
    239239// Returns a 2D array of instances of size [cpu count][cache levels]
    240240// where cache level doesn't include instruction caches
    241 raw_cache_instance ** build_raw_cache_table(unsigned cpus_c, idx_range_t cpus, unsigned idxs, unsigned cache_levels) {
     241raw_cache_instance ** build_raw_cache_table(unsigned cpus_c, idx_range_t cpus, unsigned idxs, unsigned cache_levels)
     242{
    242243        raw_cache_instance ** raw = alloc(cpus_c, '\0'`fill);
    243244
  • libcfa/src/iostream.hfa

    r7042c60 rcf191ac  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Apr 21 07:32:19 2024
    13 // Update Count     : 744
     12// Last Modified On : Tue Feb  6 18:35:54 2024
     13// Update Count     : 743
    1414//
    1515
     
    160160
    161161// tuples
    162 forall( ostype &, T, List ... | writeable( T, ostype ) | { ostype & ?|?( ostype &, List ); } ) {
    163         ostype & ?|?( ostype & os, T arg, List rest );
    164         void ?|?( ostype & os, T arg, List rest );
     162forall( ostype &, T, Params... | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) {
     163        ostype & ?|?( ostype & os, T arg, Params rest );
     164        void ?|?( ostype & os, T arg, Params rest );
    165165} // distribution
    166166
  • libcfa/src/stdlib.cfa

    r7042c60 rcf191ac  
    1010// Created On       : Thu Jan 28 17:10:29 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Apr 21 16:17:22 2024
    13 // Update Count     : 700
     12// Last Modified On : Sun Mar 17 08:25:32 2024
     13// Update Count     : 699
    1414//
    1515
     
    3131// Cforall allocation/deallocation and constructor/destructor, array types
    3232
    33 forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } )
    34 T * anew( size_t dim, Parms p ) {
     33forall( T & | sized(T), TT... | { void ?{}( T &, TT ); } )
     34T * anew( size_t dim, TT p ) {
    3535        T * arr = alloc( dim );
    3636        for ( i; dim ) {
     
    5151} // adelete
    5252
    53 forall( T & | sized(T) | { void ^?{}( T & ); }, List ... | { void adelete( List ); } )
    54 void adelete( T arr[], List rest ) {
     53forall( T & | sized(T) | { void ^?{}( T & ); }, TT... | { void adelete( TT ); } )
     54void adelete( T arr[], TT rest ) {
    5555        if ( arr ) {                                                                            // ignore null
    5656                size_t dim = malloc_size( arr ) / sizeof( T );
  • libcfa/src/stdlib.hfa

    r7042c60 rcf191ac  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 23 14:05:21 2024
    13 // Update Count     : 963
     12// Last Modified On : Mon Apr 15 22:11:51 2024
     13// Update Count     : 817
    1414//
    1515
     
    4747
    4848static inline forall( T & | sized(T) ) {
    49         // CFA safe equivalents, i.e., implicit size specification, eliminate return-type cast
     49        // CFA safe equivalents, i.e., implicit size specification
    5050
    5151        T * malloc( void ) {
     
    6464        } // calloc
    6565
    66         T * resize( T * ptr, size_t size ) {
    67                 if ( _Alignof(T) <= libAlign() ) return (T *)resize( (void *)ptr, size ); // C resize
     66        T * resize( T * ptr, size_t size ) {                            // CFA resize
     67                if ( _Alignof(T) <= libAlign() ) return (T *)resize( (void *)ptr, size ); // CFA resize
    6868                else return (T *)resize( (void *)ptr, _Alignof(T), size ); // CFA resize
    69         } // resize
    70 
    71         T * resize( T * ptr, size_t alignment, size_t size ) {
    72                 return (T *)resize( (void *)ptr, alignment, size ); // CFA resize
    7369        } // resize
    7470
     
    7874        } // realloc
    7975
    80         T * realloc( T * ptr, size_t alignment, size_t size ) {
    81                 return (T *)realloc( (void *)ptr, alignment, size ); // CFA realloc
    82         } // realloc
    83 
    8476        T * reallocarray( T * ptr, size_t dim ) {                       // CFA reallocarray
    8577                if ( _Alignof(T) <= libAlign() ) return (T *)reallocarray( (void *)ptr, dim, sizeof(T) ); // C reallocarray
     
    8779        } // realloc
    8880
    89         T * reallocarray( T * ptr, size_t alignment, size_t dim ) {
    90                 return (T *)reallocarray( (void *)ptr, alignment, dim ); // CFA reallocarray
    91         } // realloc
    92 
    9381        T * memalign( size_t align ) {
    9482                return (T *)memalign( align, sizeof(T) );               // C memalign
     
    9987        } // amemalign
    10088
    101         T * cmemalign( size_t align, size_t dim ) {
     89        T * cmemalign( size_t align, size_t dim  ) {
    10290                return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign
    10391        } // cmemalign
     
    121109
    122110/*
    123         FIX ME : fix alloc interface after Ticker Number 214 is resolved, define and add union to S_fill. Then, modify
    124         postfix-fill functions to support T * with nmemb, char, and T object of any size. Finally, change alloc_internal.
     111        FIX ME : fix alloc interface after Ticker Number 214 is resolved, define and add union to S_fill. Then, modify postfix-fill functions to support T * with nmemb, char, and T object of any size. Finally, change alloc_internal.
    125112        Or, just follow the instructions below for that.
    126113
     
    166153*/
    167154
    168 #pragma GCC diagnostic push
    169 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
    170 #pragma GCC diagnostic ignored "-Wuninitialized"
    171 
    172 struct T_align { size_t align; };
    173 struct T_resize { void * addr; };
    174 struct T_realloc { void * addr; };
    175 forall( T & ) struct T_fill {
    176         // 'N' => no fill, 'c' => fill with character c, 'a' => fill first N array elements from another array,
    177         // 'A' => fill all array elements from another array, 'T' => fill using a T value.
    178         char tag;
    179         size_t nelem;   // number of elements copied from "at" (used with tag 'a')
    180 //      union {
    181                 char c;
    182                 T * at;
    183                 char t[64]; // T t;
    184 //      };
    185 };
    186 
    187 #pragma GCC diagnostic pop
    188 
    189 static inline {
    190         T_align ?`align( size_t a ) { return (T_align){ a }; }
    191         T_resize ?`resize( void * a ) { return (T_resize){ a }; }
    192         T_realloc ?`realloc( void * a ) { return (T_realloc){ a }; }
     155typedef struct S_align { inline size_t;  } T_align;
     156typedef struct S_resize { inline void *;  }     T_resize;
     157
     158forall( T & ) {
     159        struct S_fill { char tag; char c; size_t size; T * at; char t[50]; };
     160        struct S_realloc { inline T *; };
    193161}
    194162
     163static inline T_align ?`align( size_t a ) { return (T_align){a}; }
     164static inline T_resize ?`resize( void * a )     { return (T_resize){a}; }
     165
     166extern "C" ssize_t write(int fd, const void *buf, size_t count);
    195167static inline forall( T & | sized(T) ) {
    196         T_fill(T) ?`fill( char c ) { return (T_fill(T)){ 'c', 0, c }; }
    197         T_fill(T) ?`fill( T t ) {
    198                 T_fill(T) ret = { 'T' };
     168        S_fill(T) ?`fill ( T t ) {
     169                S_fill(T) ret = { 't' };
    199170                size_t size = sizeof(T);
    200171                if ( size > sizeof(ret.t) ) {
     
    204175                return ret;
    205176        }
    206         T_fill(T) ?`fill( T a[] ) { return (T_fill(T)){ 'A', 0, '\0', a }; } // FIX ME: remove this once ticket 214 is resolved
    207         T_fill(T) ?`fill( T a[], size_t nelem ) { return (T_fill(T)){ 'a', nelem * sizeof(T), '\0', a }; }
    208 
    209         // private interface
    210         T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t Align, T_fill(T) Fill ) {
    211                 T * ptr;
    212                 size_t tsize = sizeof(T);
     177        S_fill(T) ?`fill ( zero_t ) = void; // FIX ME: remove this once ticket 214 is resolved
     178        S_fill(T) ?`fill ( T * a ) { return (S_fill(T)){ 'T', '0', 0, a }; } // FIX ME: remove this once ticket 214 is resolved
     179        S_fill(T) ?`fill ( char c ) { return (S_fill(T)){ 'c', c };     }
     180        S_fill(T) ?`fill ( T a[], size_t nmemb ) { return (S_fill(T)){ 'a', '0', nmemb * sizeof(T), a }; }
     181
     182        S_realloc(T) ?`realloc ( T * a ) { return (S_realloc(T)){a}; }
     183
     184        T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {
     185                T * ptr = NULL;
     186                size_t size = sizeof(T);
    213187                size_t copy_end = 0;
    214188
    215                 if ( Resize.addr ) {
    216                         ptr = (T *)(void *)resize( Resize.addr, Align, Dim * tsize );
    217                 } else if ( Realloc.addr ) {
    218                         if ( Fill.tag != 'N' ) copy_end = min(malloc_size( Realloc.addr ), Dim * tsize );
    219                         ptr = (T *)(void *)realloc( Realloc.addr, Align, Dim * tsize );
     189                if ( Resize ) {
     190                        ptr = (T*)(void *)resize( (void *)Resize, Align, Dim * size );
     191                } else if ( Realloc ) {
     192                        if ( Fill.tag != '0' ) copy_end = min(malloc_size( Realloc ), Dim * size );
     193                        ptr = (T *)(void *)realloc( (void *)Realloc, Align, Dim * size );
    220194                } else {
    221                         ptr = (T *)(void *)memalign( Align, Dim * tsize );
    222                 } // if
     195                        ptr = (T *)(void *) memalign( Align, Dim * size );
     196                }
    223197
    224198                if ( Fill.tag == 'c' ) {
    225                         memset( (char *)ptr + copy_end, (int)Fill.c, Dim * tsize - copy_end );
     199                        memset( (char *)ptr + copy_end, (int)Fill.c, Dim * size - copy_end );
     200                } else if ( Fill.tag == 't' ) {
     201                        for ( i; copy_end ~ Dim * size ~ size ) {
     202                                #pragma GCC diagnostic push
     203                                #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
     204                                assert( size <= sizeof(Fill.t) );
     205                                memcpy( (char *)ptr + i, &Fill.t, size );
     206                                #pragma GCC diagnostic pop
     207                        }
     208                } else if ( Fill.tag == 'a' ) {
     209                        memcpy( (char *)ptr + copy_end, Fill.at, min(Dim * size - copy_end, Fill.size) );
    226210                } else if ( Fill.tag == 'T' ) {
    227                         for ( i; copy_end ~ Dim * tsize ~ tsize ) {
    228                                 assert( tsize <= sizeof(Fill.t) );
    229                                 memcpy( (char *)ptr + i, &Fill.t, tsize );
    230                         } // for
    231                 } else if ( Fill.tag == 'a' ) {
    232                         memcpy( (char *)ptr + copy_end, Fill.at, min( Dim * tsize - copy_end, Fill.nelem ) );
    233                 } else if ( Fill.tag == 'A' ) {
    234                         memcpy( (char *)ptr + copy_end, Fill.at, Dim * tsize );
    235                 } // if
     211                        memcpy( (char *)ptr + copy_end, Fill.at, Dim * size );
     212                }
     213
    236214                return ptr;
    237215        } // alloc_internal$
    238216
    239         // Dim is a fixed (optional first) parameter, and hence is not set using a postfix function. A dummy parameter is
    240         // being overwritten by the postfix argument in the ttype.
    241         forall( List ... | { T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t Align, T_fill(T) Fill, List ); } ) {
    242                 // middle interface
    243                 T * alloc_internal$( size_t Dim, T_resize dummy, T_realloc Realloc, size_t Align, T_fill(T) Fill, T_resize Resize, List rest ) {
    244                 return alloc_internal$( Dim, Resize, (T_realloc){0p}, Align, Fill, rest );
    245                 }
    246                 T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc dummy, size_t Align, T_fill(T) Fill, T_realloc Realloc, List rest ) {
    247                 return alloc_internal$( Dim, (T_resize){0p}, Realloc, Align, Fill, rest );
    248                 }
    249                 T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t dummy, T_fill(T) Fill, T_align Align, List rest ) {
    250                 return alloc_internal$( Dim, Resize, Realloc, Align.align, Fill, rest );
    251                 }
    252                 T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t Align, T_fill(T) dummy, T_fill(T) Fill, List rest ) {
    253                 return alloc_internal$( Dim, Resize, Realloc, Align, Fill, rest );
    254                 }
    255                 // public interface
    256             T * alloc( List rest ) {
    257                 return alloc_internal$( (size_t)1, (T_resize){0p}, (T_realloc){0p}, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (T_fill(T)){'N'}, rest );
     217        forall( TT ... | { T * alloc_internal$( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {
     218                T * alloc_internal$( void *, T *, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest ) {
     219                return alloc_internal$( Resize, (T*)0p, Align, Dim, Fill, rest);
     220                }
     221
     222                T * alloc_internal$( void *, T *, size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest ) {
     223                return alloc_internal$( (void*)0p, Realloc, Align, Dim, Fill, rest);
     224                }
     225
     226                T * alloc_internal$( void * Resize, T * Realloc, size_t, size_t Dim, S_fill(T) Fill, T_align Align, TT rest ) {
     227                return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest);
     228                }
     229
     230                T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T), S_fill(T) Fill, TT rest ) {
     231                return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest );
     232                }
     233
     234            T * alloc( TT all ) {
     235                return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all );
    258236            }
    259             T * alloc( size_t Dim, List rest ) {
    260                 return alloc_internal$( Dim, (T_resize){0p}, (T_realloc){0p}, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (T_fill(T)){'N'}, rest );
     237
     238            T * alloc( size_t dim, TT all ) {
     239                return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all );
    261240            }
    262         } // distribution List
     241        } // distribution TT
    263242} // distribution T
    264243
    265244static inline forall( T & | sized(T) ) {
    266245        // CFA safe initialization/copy, i.e., implicit size specification, non-array types
    267         T * memset( T * dest, char fill ) {                                     // all combinations of pointer/reference
    268                 return (T *)memset( dest, fill, sizeof(T) );    // C memset
     246        T * memset( T * dest, char fill ) {
     247                return (T *)memset( dest, fill, sizeof(T) );
    269248        } // memset
    270         T * memset( T & dest, char fill ) {
    271                 return (T *)memset( &dest, fill, sizeof(T) );   // C memset
    272         } // memset
    273 
    274         T * memcpy( T * dest, const T * src ) {                         // all combinations of pointer/reference
    275                 return (T *)memcpy( dest, src, sizeof(T) );             // C memcpy
    276         } // memcpy
    277         T * memcpy( T & dest, const T & src ) {
    278                 return (T *)memcpy( &dest, &src, sizeof(T) );   // C memcpy
    279         } // memcpy
    280         T * memcpy( T * dest, const T & src ) {
    281                 return (T *)memcpy( dest, &src, sizeof(T) );    // C memcpy
    282         } // memcpy
    283         T * memcpy( T & dest, const T * src ) {
    284                 return (T *)memcpy( &dest, src, sizeof(T) );    // C memcpy
     249
     250        T * memcpy( T * dest, const T * src ) {
     251                return (T *)memcpy( dest, src, sizeof(T) );
    285252        } // memcpy
    286253
     
    296263
    297264// CFA deallocation for multiple objects
    298 static inline forall( T & )
     265static inline forall( T & )                                                     // FIX ME, problems with 0p in list
    299266void free( T * ptr ) {
    300267        free( (void *)ptr );                                                            // C free
    301268} // free
    302 static inline forall( T &, List ... | { void free( List ); } )
    303 void free( T * ptr, List rest ) {
     269static inline forall( T &, TT ... | { void free( TT ); } )
     270void free( T * ptr, TT rest ) {
    304271        free( ptr );
    305272        free( rest );
     
    307274
    308275// CFA allocation/deallocation and constructor/destructor, non-array types
    309 static inline forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } )
    310 T * new( Parms p ) {
     276static inline forall( T & | sized(T), TT ... | { void ?{}( T &, TT ); } )
     277T * new( TT p ) {
    311278        return &(*(T *)malloc()){ p };                                          // run constructor
    312279} // new
     
    320287        free( ptr );                                                                            // always call free
    321288} // delete
    322 static inline forall( T &, List ... | { void ^?{}( T & ); void delete( List ); } )
    323 void delete( T * ptr, List rest ) {
     289static inline forall( T &, TT ... | { void ^?{}( T & ); void delete( TT ); } )
     290void delete( T * ptr, TT rest ) {
    324291        delete( ptr );
    325292        delete( rest );
     
    327294
    328295// CFA allocation/deallocation and constructor/destructor, array types
    329 forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } ) T * anew( size_t dim, Parms p );
     296forall( T & | sized(T), TT ... | { void ?{}( T &, TT ); } ) T * anew( size_t dim, TT p );
    330297forall( T & | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] );
    331 forall( T & | sized(T) | { void ^?{}( T & ); }, List ... | { void adelete( List ); } ) void adelete( T arr[], List rest );
    332 
     298forall( T & | sized(T) | { void ^?{}( T & ); }, TT ... | { void adelete( TT ); } ) void adelete( T arr[], TT rest );
    333299//---------------------------------------
    334300
  • src/AST/Pass.hpp

    r7042c60 rcf191ac  
    113113        static auto read( node_type const * node, Args&&... args ) {
    114114                Pass<core_t> visitor( std::forward<Args>( args )... );
     115                auto const * temp = node->accept( visitor );
     116                assert( temp == node );
     117                return visitor.get_result();
     118        }
     119
     120        // Versions of the above for older compilers.
     121        template< typename... Args >
     122        static void run( TranslationUnit & decls ) {
     123                Pass<core_t> visitor;
     124                accept_all( decls, visitor );
     125        }
     126
     127        template< typename node_type, typename... Args >
     128        static auto read( node_type const * node ) {
     129                Pass<core_t> visitor;
    115130                auto const * temp = node->accept( visitor );
    116131                assert( temp == node );
  • src/AST/Print.cpp

    r7042c60 rcf191ac  
    15791579                preprint( node );
    15801580                os << "enum attr ";
    1581                 if ( node->attr == ast::EnumAttribute::Label ) {
    1582                         os << "Label ";
    1583                 } else if ( node->attr == ast::EnumAttribute::Value ) {
    1584                         os << "Value ";
    1585                 } else {
    1586                         os << "Posn ";
    1587                 }
     1581        if ( node->attr == ast::EnumAttribute::Label ) {
     1582            os << "Label ";
     1583        } else if ( node->attr == ast::EnumAttribute::Value ) {
     1584            os << "Value ";
     1585        } else {
     1586            os << "Posn ";
     1587        }
    15881588                (*(node->instance)).accept( *this );
    15891589                return node;
  • src/AST/Type.hpp

    r7042c60 rcf191ac  
    3131// Must be included in *all* AST classes; should be #undef'd at the end of the file
    3232#define MUTATE_FRIEND \
    33         template<typename node_t> friend node_t * mutate(const node_t * node); \
     33    template<typename node_t> friend node_t * mutate(const node_t * node); \
    3434        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3535
     
    322322public:
    323323        readonly<EnumInstType> instance;
    324         EnumAttribute attr;
     324    EnumAttribute attr;
    325325        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    326326        EnumAttrType( const EnumInstType * instance, EnumAttribute attr = EnumAttribute::Posn )
    327327                : instance(instance), attr(attr) {}
    328 
    329         bool match( const ast::EnumAttrType * other) const {
    330                 return instance->base->name == other->instance->base->name && attr == other->attr;
    331         }
     328       
     329    bool match( const ast::EnumAttrType * other) const {
     330        return instance->base->name == other->instance->base->name && attr == other->attr;
     331    }
    332332private:
    333333        EnumAttrType * clone() const override { return new EnumAttrType{ *this }; }
  • src/BasicTypes-gen.cc

    r7042c60 rcf191ac  
    415415        code << "\t" << BYMK << endl;
    416416        code << "\t#define BT ast::BasicKind::" << endl;
    417         code << "\tstatic const ast::BasicKind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl
     417        code << "\tstatic const BT Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl
    418418             << "\t\t/*\t\t ";
    419419        for ( int r = 0; r < NUMBER_OF_BASIC_TYPES; r += 1 ) { // titles
  • src/CodeGen/CodeGenerator.cpp

    r7042c60 rcf191ac  
    167167        ast::Pass<CodeGenerator> subCG( acc, subOptions );
    168168        // Add the forall clause.
     169        // TODO: These probably should be removed by now and the assert used.
    169170        if ( !decl->type_params.empty() ) {
    170171                assertf( !options.genC, "FunctionDecl forall should not reach code generation." );
     
    173174                acc << ")" << std::endl;
    174175        }
    175         // The forall clause should be printed early as part of the preamble.
    176         output << acc.str();
    177         acc.str("");
    178176
    179177        acc << mangleName( decl );
  • src/Common/PersistentMap.h

    r7042c60 rcf191ac  
    2323#include <utility>        // for forward, move
    2424
    25 /// Wraps a hash table in a persistent data structure, using a technique based
    26 /// on the persistent array in Conchon & Filliatre "A Persistent Union-Find
     25/// Wraps a hash table in a persistent data structure, using a technique based 
     26/// on the persistent array in Conchon & Filliatre "A Persistent Union-Find 
    2727/// Data Structure"
    2828
    2929template<typename Key, typename Val,
    30                 typename Hash = std::hash<Key>, typename Eq = std::equal_to<Key>>
    31 class PersistentMap
     30         typename Hash = std::hash<Key>, typename Eq = std::equal_to<Key>>
     31class PersistentMap 
    3232        : public std::enable_shared_from_this<PersistentMap<Key, Val, Hash, Eq>> {
    3333public:
     
    3838
    3939        /// Types of version nodes
    40         enum Mode {
     40        enum Mode { 
    4141                BASE,  ///< Root node of version tree
    4242                REM,   ///< Key removal node
     
    6363                Ptr base;  ///< Modified map
    6464                Key key;   ///< Key removed
    65 
     65               
    6666                template<typename P, typename K>
    6767                Rem(P&& p, K&& k) : base(std::forward<P>(p)), key(std::forward<K>(k)) {}
     
    155155                                auto it = base_map.find( self.key );
    156156
    157                                 base->template init<Ins>(
     157                                base->template init<Ins>( 
    158158                                                mut_this->shared_from_this(), std::move(self.key), std::move(it->second) );
    159159                                base->mode = INS;
     
    175175                                auto it = base_map.find( self.key );
    176176
    177                                 base->template init<Ins>(
     177                                base->template init<Ins>( 
    178178                                                mut_this->shared_from_this(), std::move(self.key), std::move(it->second) );
    179179                                base->mode = UPD;
     
    267267        Ptr erase(const Key& k) {
    268268                reroot();
    269 
     269               
    270270                // exit early if key does not exist in map
    271271                if ( ! as<Base>().count( k ) ) return this->shared_from_this();
  • src/Common/VectorMap.h

    r7042c60 rcf191ac  
    3636        typedef const value_type* pointer;
    3737        typedef const const_value_type* const_pointer;
    38 
    39         class iterator : public std::iterator<
    40                         std::random_access_iterator_tag,
    41                         value_type, difference_type, pointer, reference > {
    42                 friend class VectorMap;
    43                 friend class const_iterator;
    44 
     38       
     39        class iterator : public std::iterator< std::random_access_iterator_tag,
     40                                               value_type,
     41                                                                                   difference_type,
     42                                                                                   pointer,
     43                                                                                   reference > {
     44        friend class VectorMap;
     45        friend class const_iterator;
     46       
    4547                value_type data;
    4648
     
    9799                        return data.first == o.data.first && &data.second == &o.data.second;
    98100                }
    99 
     101               
    100102                bool operator!= (const iterator& that) const { return !(*this == that); }
    101103
     
    109111        };
    110112
    111         class const_iterator : public std::iterator<
    112                         std::bidirectional_iterator_tag,
    113                         const_value_type, difference_type, const_pointer, const_reference > {
    114                 friend class VectorMap;
     113        class const_iterator : public std::iterator< std::bidirectional_iterator_tag,
     114                                                     const_value_type,
     115                                                                                                  difference_type,
     116                                                                                                  const_pointer,
     117                                                                                                  const_reference  > {
     118        friend class VectorMap;
    115119                const_value_type data;
    116120
     
    177181                        return data.first == o.data.first && &data.second == &o.data.second;
    178182                }
    179 
     183               
    180184                bool operator!= (const const_iterator& that) const { return !(*this == that); }
    181185
     
    229233
    230234template<typename T>
    231 typename VectorMap<T>::iterator operator+(
    232                 typename VectorMap<T>::difference_type i,
    233                 const typename VectorMap<T>::iterator& it) {
     235typename VectorMap<T>::iterator operator+ (typename VectorMap<T>::difference_type i,
     236                                           const typename VectorMap<T>::iterator& it) {
    234237        return it + i;
    235238}
    236239
    237240template<typename T>
    238 typename VectorMap<T>::const_iterator operator+(
    239                 typename VectorMap<T>::difference_type i,
    240                 const typename VectorMap<T>::const_iterator& it) {
     241typename VectorMap<T>::const_iterator operator+ (typename VectorMap<T>::difference_type i,
     242                                                 const typename VectorMap<T>::const_iterator& it) {
    241243        return it + i;
    242244}
  • src/Concurrency/Actors.cpp

    r7042c60 rcf191ac  
    2828
    2929struct CollectactorStructDecls : public ast::WithGuards {
    30         unordered_set<const StructDecl *> & actorStructDecls;
    31         unordered_set<const StructDecl *>  & messageStructDecls;
    32         const StructDecl ** requestDecl;
    33         const EnumDecl ** allocationDecl;
    34         const StructDecl ** actorDecl;
    35         const StructDecl ** msgDecl;
    36         StructDecl * parentDecl;
    37         bool insideStruct = false;
    38         bool namedDecl = false;
    39 
    40         // finds and sets a ptr to the allocation enum, which is needed in the next pass
    41         void previsit( const EnumDecl * decl ) {
    42                 if( decl->name == "allocation" ) *allocationDecl = decl;
     30    unordered_set<const StructDecl *> & actorStructDecls;
     31    unordered_set<const StructDecl *>  & messageStructDecls;
     32    const StructDecl ** requestDecl;
     33    const EnumDecl ** allocationDecl;
     34    const StructDecl ** actorDecl;
     35    const StructDecl ** msgDecl;
     36    StructDecl * parentDecl;
     37    bool insideStruct = false;
     38    bool namedDecl = false;
     39
     40    // finds and sets a ptr to the allocation enum, which is needed in the next pass
     41    void previsit( const EnumDecl * decl ) {
     42        if( decl->name == "allocation" ) *allocationDecl = decl;
     43    }
     44
     45    // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
     46    void previsit( const StructDecl * decl ) {
     47        if ( !decl->body ) return;
     48        if ( decl->name == "actor" ) {
     49            actorStructDecls.insert( decl ); // skip inserting fwd decl
     50            *actorDecl = decl;
     51        } else if( decl->name == "message" ) {
     52            messageStructDecls.insert( decl ); // skip inserting fwd decl
     53            *msgDecl = decl;
     54        } else if( decl->name == "request" ) *requestDecl = decl;
     55        else {
     56            GuardValue(insideStruct);
     57            insideStruct = true;
     58            parentDecl = mutate( decl );
     59        }
    4360        }
    4461
    45         // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
    46         void previsit( const StructDecl * decl ) {
    47                 if ( !decl->body ) return;
    48                 if ( decl->name == "actor" ) {
    49                         actorStructDecls.insert( decl ); // skip inserting fwd decl
    50                         *actorDecl = decl;
    51                 } else if( decl->name == "message" ) {
    52                         messageStructDecls.insert( decl ); // skip inserting fwd decl
    53                         *msgDecl = decl;
    54                 } else if( decl->name == "request" ) *requestDecl = decl;
    55                 else {
    56                         GuardValue(insideStruct);
    57                         insideStruct = true;
    58                         parentDecl = mutate( decl );
    59                 }
     62    // this catches structs of the form:
     63    //     struct dummy_actor { actor a; };
     64    // since they should be:
     65    //     struct dummy_actor { inline actor; };
     66    void previsit ( const ObjectDecl * decl ) {
     67        if ( insideStruct && ! decl->name.empty() ) {
     68            GuardValue(namedDecl);
     69            namedDecl = true;
     70        }
     71    }
     72
     73    // this collects the derived actor and message struct decl ptrs
     74    void postvisit( const StructInstType * node ) {
     75        if ( ! *actorDecl || ! *msgDecl ) return;
     76        if ( insideStruct && !namedDecl ) {
     77            auto actorIter = actorStructDecls.find( node->aggr() );   
     78            if ( actorIter != actorStructDecls.end() ) {
     79                actorStructDecls.insert( parentDecl );
     80                return;
     81            }
     82            auto messageIter = messageStructDecls.find( node->aggr() );
     83            if ( messageIter != messageStructDecls.end() ) {
     84                messageStructDecls.insert( parentDecl );
     85            }
     86        }
    6087        }
    6188
    62         // this catches structs of the form:
    63         //     struct dummy_actor { actor a; };
    64         // since they should be:
    65         //     struct dummy_actor { inline actor; };
    66         void previsit ( const ObjectDecl * decl ) {
    67                 if ( insideStruct && ! decl->name.empty() ) {
    68                         GuardValue(namedDecl);
    69                         namedDecl = true;
    70                 }
    71         }
    72 
    73         // this collects the derived actor and message struct decl ptrs
    74         void postvisit( const StructInstType * node ) {
    75                 if ( ! *actorDecl || ! *msgDecl ) return;
    76                 if ( insideStruct && !namedDecl ) {
    77                         auto actorIter = actorStructDecls.find( node->aggr() );
    78                         if ( actorIter != actorStructDecls.end() ) {
    79                                 actorStructDecls.insert( parentDecl );
    80                                 return;
    81                         }
    82                         auto messageIter = messageStructDecls.find( node->aggr() );
    83                         if ( messageIter != messageStructDecls.end() ) {
    84                                 messageStructDecls.insert( parentDecl );
    85                         }
    86                 }
    87         }
    88 
    8989  public:
    90         CollectactorStructDecls( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
    91                 const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl )
    92                 : actorStructDecls( actorStructDecls ), messageStructDecls( messageStructDecls ), requestDecl( requestDecl ),
    93                 allocationDecl( allocationDecl ), actorDecl(actorDecl), msgDecl(msgDecl) {}
     90    CollectactorStructDecls( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
     91        const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl )
     92        : actorStructDecls( actorStructDecls ), messageStructDecls( messageStructDecls ), requestDecl( requestDecl ),
     93        allocationDecl( allocationDecl ), actorDecl(actorDecl), msgDecl(msgDecl) {}
    9494};
    9595
     
    9797class FwdDeclTable {
    9898
    99         // tracks which decls we have seen so that we can hoist the FunctionDecl to the highest point possible
    100         struct FwdDeclData {
    101                 const StructDecl * actorDecl;
    102                 const StructDecl * msgDecl;
    103                 FunctionDecl * fwdDecl;
    104                 bool actorFound;
    105                 bool msgFound;
    106 
    107                 bool readyToInsert() { return actorFound && msgFound; }
    108                 bool foundActor() { actorFound = true; return readyToInsert(); }
    109                 bool foundMsg() { msgFound = true; return readyToInsert(); }
    110 
    111                 FwdDeclData( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) :
    112                         actorDecl(actorDecl), msgDecl(msgDecl), fwdDecl(fwdDecl), actorFound(false), msgFound(false) {}
    113         };
    114 
    115         // map indexed by actor struct ptr
    116         // value is map of all FwdDeclData that contains said actor struct ptr
    117         // inner map is indexed by the message struct ptr of FwdDeclData
    118         unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> actorMap;
    119 
    120         // this map is the same except the outer map is indexed by message ptr and the inner is indexed by actor ptr
    121         unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> msgMap;
    122 
    123         void insert( const StructDecl * decl, const StructDecl * otherDecl, unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map, FwdDeclData * data ) {
    124                 auto iter = map.find( decl );
    125                 if ( iter != map.end() ) { // if decl exists in map append data to existing inner map
    126                         iter->second.emplace( make_pair( otherDecl, data ) );
    127                 } else { // else create inner map for key
    128                         map.emplace( make_pair( decl, unordered_map<const StructDecl *, FwdDeclData *>( { make_pair( otherDecl, data ) } ) ) );
    129                 }
    130         }
     99    // tracks which decls we have seen so that we can hoist the FunctionDecl to the highest point possible
     100    struct FwdDeclData {
     101        const StructDecl * actorDecl;
     102        const StructDecl * msgDecl;
     103        FunctionDecl * fwdDecl;
     104        bool actorFound;
     105        bool msgFound;
     106
     107        bool readyToInsert() { return actorFound && msgFound; }
     108        bool foundActor() { actorFound = true; return readyToInsert(); }
     109        bool foundMsg() { msgFound = true; return readyToInsert(); }
     110
     111        FwdDeclData( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) :
     112            actorDecl(actorDecl), msgDecl(msgDecl), fwdDecl(fwdDecl), actorFound(false), msgFound(false) {}
     113    };
     114
     115    // map indexed by actor struct ptr
     116    // value is map of all FwdDeclData that contains said actor struct ptr
     117    // inner map is indexed by the message struct ptr of FwdDeclData
     118    unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> actorMap;
     119
     120    // this map is the same except the outer map is indexed by message ptr and the inner is indexed by actor ptr
     121    unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> msgMap;
     122
     123    void insert( const StructDecl * decl, const StructDecl * otherDecl, unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map, FwdDeclData * data ) {
     124        auto iter = map.find( decl );
     125        if ( iter != map.end() ) { // if decl exists in map append data to existing inner map
     126            iter->second.emplace( make_pair( otherDecl, data ) );
     127        } else { // else create inner map for key
     128            map.emplace( make_pair( decl, unordered_map<const StructDecl *, FwdDeclData *>( { make_pair( otherDecl, data ) } ) ) );
     129        }
     130    }
    131131
    132132  public:
    133         // insert decl into table so that we can fwd declare it later (average cost: O(1))
    134         void insertDecl( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) {
    135                 FwdDeclData * declToInsert = new FwdDeclData( actorDecl, msgDecl, fwdDecl );
    136                 insert( actorDecl, msgDecl, actorMap, declToInsert );
    137                 insert( msgDecl, actorDecl, msgMap, declToInsert );
    138         }
    139 
    140         // returns list of decls to insert after current struct decl
    141         // Over the entire pass the runtime of this routine is O(r) where r is the # of receive routines
    142         list<FunctionDecl *> updateDecl( const StructDecl * decl, bool isMsg ) {
    143                 unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map = isMsg ? msgMap : actorMap;
    144                 unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & otherMap =  isMsg ? actorMap : msgMap;
    145                 auto iter = map.find( decl );
    146                 list<FunctionDecl *> toInsertAfter; // this is populated with decls that are ready to insert
    147                 if ( iter == map.end() ) return toInsertAfter;
    148 
    149                 // iterate over inner map
    150                 unordered_map<const StructDecl *, FwdDeclData *> & currInnerMap = iter->second;
    151                 for ( auto innerIter = currInnerMap.begin(); innerIter != currInnerMap.end(); ) {
    152                         FwdDeclData * currentDatum = innerIter->second;
    153                         bool readyToInsert = isMsg ? currentDatum->foundMsg() : currentDatum->foundActor();
    154                         if ( ! readyToInsert ) { ++innerIter; continue; }
    155 
    156                         // readyToInsert is true so we are good to insert the forward decl of the message fn
    157                         toInsertAfter.push_back( currentDatum->fwdDecl );
    158 
    159                         // need to remove from other map before deleting
    160                         // find inner map in other map ( other map is actor map if original is msg map and vice versa )
    161                         const StructDecl * otherDecl = isMsg ? currentDatum->actorDecl : currentDatum->msgDecl;
    162                         auto otherMapIter = otherMap.find( otherDecl );
    163 
    164                         unordered_map<const StructDecl *, FwdDeclData *> & otherInnerMap = otherMapIter->second;
    165 
    166                         // find the FwdDeclData we need to remove in the other inner map
    167                         auto otherInnerIter = otherInnerMap.find( decl );
    168 
    169                         // remove references to deleted FwdDeclData from current inner map
    170                         innerIter = currInnerMap.erase( innerIter ); // this does the increment so no explicit inc needed
    171 
    172                         // remove references to deleted FwdDeclData from other inner map
    173                         otherInnerMap.erase( otherInnerIter );
    174 
    175                         // if other inner map is now empty, remove key from other outer map
    176                         if ( otherInnerMap.empty() )
    177                                 otherMap.erase( otherDecl );
    178 
    179                         // now we are safe to delete the FwdDeclData since we are done with it
    180                         // and we have removed all references to it from our data structures
    181                         delete currentDatum;
    182                 }
    183 
    184                 // if current inner map is now empty, remove key from outer map.
    185                 // Have to do this after iterating for safety
    186                 if ( currInnerMap.empty() )
    187                         map.erase( decl );
    188 
    189                 return toInsertAfter;
    190         }
     133    // insert decl into table so that we can fwd declare it later (average cost: O(1))
     134    void insertDecl( const StructDecl * actorDecl, const StructDecl * msgDecl, FunctionDecl * fwdDecl ) {
     135        FwdDeclData * declToInsert = new FwdDeclData( actorDecl, msgDecl, fwdDecl );
     136        insert( actorDecl, msgDecl, actorMap, declToInsert );
     137        insert( msgDecl, actorDecl, msgMap, declToInsert );
     138    }
     139
     140    // returns list of decls to insert after current struct decl
     141    // Over the entire pass the runtime of this routine is O(r) where r is the # of receive routines
     142    list<FunctionDecl *> updateDecl( const StructDecl * decl, bool isMsg ) {
     143        unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & map = isMsg ? msgMap : actorMap;
     144        unordered_map<const StructDecl *, unordered_map<const StructDecl *, FwdDeclData *>> & otherMap =  isMsg ? actorMap : msgMap;
     145        auto iter = map.find( decl );
     146        list<FunctionDecl *> toInsertAfter; // this is populated with decls that are ready to insert
     147        if ( iter == map.end() ) return toInsertAfter;
     148       
     149        // iterate over inner map
     150        unordered_map<const StructDecl *, FwdDeclData *> & currInnerMap = iter->second;
     151        for ( auto innerIter = currInnerMap.begin(); innerIter != currInnerMap.end(); ) {
     152            FwdDeclData * currentDatum = innerIter->second;
     153            bool readyToInsert = isMsg ? currentDatum->foundMsg() : currentDatum->foundActor();
     154            if ( ! readyToInsert ) { ++innerIter; continue; }
     155           
     156            // readyToInsert is true so we are good to insert the forward decl of the message fn
     157            toInsertAfter.push_back( currentDatum->fwdDecl );
     158
     159            // need to remove from other map before deleting
     160            // find inner map in other map ( other map is actor map if original is msg map and vice versa )
     161            const StructDecl * otherDecl = isMsg ? currentDatum->actorDecl : currentDatum->msgDecl;
     162            auto otherMapIter = otherMap.find( otherDecl );
     163
     164            unordered_map<const StructDecl *, FwdDeclData *> & otherInnerMap = otherMapIter->second;
     165
     166            // find the FwdDeclData we need to remove in the other inner map
     167            auto otherInnerIter = otherInnerMap.find( decl );
     168
     169            // remove references to deleted FwdDeclData from current inner map
     170            innerIter = currInnerMap.erase( innerIter ); // this does the increment so no explicit inc needed
     171
     172            // remove references to deleted FwdDeclData from other inner map
     173            otherInnerMap.erase( otherInnerIter );
     174           
     175            // if other inner map is now empty, remove key from other outer map
     176            if ( otherInnerMap.empty() )
     177                otherMap.erase( otherDecl );
     178
     179            // now we are safe to delete the FwdDeclData since we are done with it
     180            // and we have removed all references to it from our data structures
     181            delete currentDatum;
     182        }
     183
     184        // if current inner map is now empty, remove key from outer map.
     185        // Have to do this after iterating for safety
     186        if ( currInnerMap.empty() )
     187            map.erase( decl );
     188
     189        return toInsertAfter;
     190    }
    191191};
    192192
    193193// generates the definitions of send operators for actors
    194 // collects data needed for next pass that does the circular defn resolution
     194// collects data needed for next pass that does the circular defn resolution 
    195195//     for message send operators (via table above)
    196196struct GenFuncsCreateTables : public ast::WithDeclsToAdd<> {
    197         unordered_set<const StructDecl *> & actorStructDecls;
    198         unordered_set<const StructDecl *>  & messageStructDecls;
    199         const StructDecl ** requestDecl;
    200         const EnumDecl ** allocationDecl;
    201         const StructDecl ** actorDecl;
    202         const StructDecl ** msgDecl;
    203         FwdDeclTable & forwardDecls;
    204 
    205         // generates the operator for actor message sends
     197    unordered_set<const StructDecl *> & actorStructDecls;
     198    unordered_set<const StructDecl *>  & messageStructDecls;
     199    const StructDecl ** requestDecl;
     200    const EnumDecl ** allocationDecl;
     201    const StructDecl ** actorDecl;
     202    const StructDecl ** msgDecl;
     203    FwdDeclTable & forwardDecls;
     204
     205    // generates the operator for actor message sends
    206206        void postvisit( const FunctionDecl * decl ) {
    207                 // return if not of the form receive( param1, param2 ) or if it is a forward decl
    208                 if ( decl->name != "receive" || decl->params.size() != 2 || !decl->stmts ) return;
    209 
    210                 // the params should be references
    211                 const ReferenceType * derivedActorRef = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
    212                 const ReferenceType * derivedMsgRef = dynamic_cast<const ReferenceType *>(decl->params.at(1)->get_type());
    213                 if ( !derivedActorRef || !derivedMsgRef ) return;
    214 
    215                 // the references should be to struct instances
    216                 const StructInstType * arg1InstType = dynamic_cast<const StructInstType *>(derivedActorRef->base.get());
    217                 const StructInstType * arg2InstType = dynamic_cast<const StructInstType *>(derivedMsgRef->base.get());
    218                 if ( !arg1InstType || !arg2InstType ) return;
    219 
    220                 // If the struct instances are derived actor and message types then generate the message send routine
    221                 auto actorIter = actorStructDecls.find( arg1InstType->aggr() );
    222                 auto messageIter = messageStructDecls.find( arg2InstType->aggr() );
    223                 if ( actorIter != actorStructDecls.end() && messageIter != messageStructDecls.end() ) {
    224                         //////////////////////////////////////////////////////////////////////
    225                         // The following generates this wrapper for all receive(derived_actor &, derived_msg &) functions
    226                         /* base_actor and base_msg are output params
    227                         static inline allocation __CFA_receive_wrap( derived_actor & receiver, derived_msg & msg, actor ** base_actor, message ** base_msg ) {
    228                                 base_actor = &receiver;
    229                                 base_msg = &msg;
    230                                 return receive( receiver, msg );
    231                         }
    232                         */
    233                         CompoundStmt * wrapBody = new CompoundStmt( decl->location );
    234 
    235                         // generates: base_actor = &receiver;
    236                         wrapBody->push_back( new ExprStmt( decl->location,
    237                                 UntypedExpr::createAssign( decl->location,
    238                                         UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_actor" ) ),
    239                                         new AddressExpr( decl->location, new NameExpr( decl->location, "receiver" ) )
    240                                 )
    241                         ));
    242 
    243                         // generates: base_msg = &msg;
    244                         wrapBody->push_back( new ExprStmt( decl->location,
    245                                 UntypedExpr::createAssign( decl->location,
    246                                         UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_msg" ) ),
    247                                         new AddressExpr( decl->location, new NameExpr( decl->location, "msg" ) )
    248                                 )
    249                         ));
    250 
    251                         // generates: return receive( receiver, msg );
    252                         wrapBody->push_back( new ReturnStmt( decl->location,
    253                                 new UntypedExpr ( decl->location,
    254                                         new NameExpr( decl->location, "receive" ),
     207        // return if not of the form receive( param1, param2 ) or if it is a forward decl
     208        if ( decl->name != "receive" || decl->params.size() != 2 || !decl->stmts ) return;
     209
     210        // the params should be references
     211        const ReferenceType * derivedActorRef = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
     212        const ReferenceType * derivedMsgRef = dynamic_cast<const ReferenceType *>(decl->params.at(1)->get_type());
     213        if ( !derivedActorRef || !derivedMsgRef ) return;
     214
     215        // the references should be to struct instances
     216        const StructInstType * arg1InstType = dynamic_cast<const StructInstType *>(derivedActorRef->base.get());
     217        const StructInstType * arg2InstType = dynamic_cast<const StructInstType *>(derivedMsgRef->base.get());
     218        if ( !arg1InstType || !arg2InstType ) return;
     219
     220        // If the struct instances are derived actor and message types then generate the message send routine
     221        auto actorIter = actorStructDecls.find( arg1InstType->aggr() );
     222        auto messageIter = messageStructDecls.find( arg2InstType->aggr() );
     223        if ( actorIter != actorStructDecls.end() && messageIter != messageStructDecls.end() ) {
     224            //////////////////////////////////////////////////////////////////////
     225            // The following generates this wrapper for all receive(derived_actor &, derived_msg &) functions
     226            /* base_actor and base_msg are output params
     227            static inline allocation __CFA_receive_wrap( derived_actor & receiver, derived_msg & msg, actor ** base_actor, message ** base_msg ) {
     228                base_actor = &receiver;
     229                base_msg = &msg;
     230                return receive( receiver, msg );
     231            }
     232            */
     233            CompoundStmt * wrapBody = new CompoundStmt( decl->location );
     234
     235            // generates: base_actor = &receiver;
     236            wrapBody->push_back( new ExprStmt( decl->location,
     237                UntypedExpr::createAssign( decl->location,
     238                    UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_actor" ) ),
     239                    new AddressExpr( decl->location, new NameExpr( decl->location, "receiver" ) )
     240                )
     241            ));
     242
     243            // generates: base_msg = &msg;
     244            wrapBody->push_back( new ExprStmt( decl->location,
     245                UntypedExpr::createAssign( decl->location,
     246                    UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "base_msg" ) ),
     247                    new AddressExpr( decl->location, new NameExpr( decl->location, "msg" ) )
     248                )
     249            ));
     250
     251            // generates: return receive( receiver, msg );
     252            wrapBody->push_back( new ReturnStmt( decl->location,
     253                new UntypedExpr ( decl->location,
     254                    new NameExpr( decl->location, "receive" ),
     255                    {
     256                        new NameExpr( decl->location, "receiver" ),
     257                        new NameExpr( decl->location, "msg" )
     258                    }
     259                )
     260            ));
     261
     262            // create receive wrapper to extract base message and actor pointer
     263            // put it all together into the complete function decl from above
     264            FunctionDecl * receiveWrapper = new FunctionDecl(
     265                decl->location,
     266                "__CFA_receive_wrap",
     267                {
     268                    new ObjectDecl(
     269                        decl->location,
     270                        "receiver",
     271                        ast::deepCopy( derivedActorRef )
     272                    ),
     273                    new ObjectDecl(
     274                        decl->location,
     275                        "msg",
     276                        ast::deepCopy( derivedMsgRef )
     277                    ),
     278                    new ObjectDecl(
     279                        decl->location,
     280                        "base_actor",
     281                        new PointerType( new PointerType( new StructInstType( *actorDecl ) ) )
     282                    ),
     283                    new ObjectDecl(
     284                        decl->location,
     285                        "base_msg",
     286                        new PointerType( new PointerType( new StructInstType( *msgDecl ) ) )
     287                    )
     288                },                      // params
     289                {
     290                    new ObjectDecl(
     291                        decl->location,
     292                        "__CFA_receive_wrap_ret",
     293                        new EnumInstType( *allocationDecl )
     294                    )
     295                },
     296                wrapBody,               // body
     297                { Storage::Static },    // storage
     298                Linkage::Cforall,       // linkage
     299                {},                     // attributes
     300                { Function::Inline }
     301            );
     302
     303            declsToAddAfter.push_back( receiveWrapper );
     304
     305            //////////////////////////////////////////////////////////////////////
     306            // The following generates this send message operator routine for all receive(derived_actor &, derived_msg &) functions
     307            /*
     308                static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) {
     309                    request new_req;
     310                    allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
     311                    __receive_fn fn = (__receive_fn)my_work_fn;
     312                    new_req{ &receiver, &msg, fn };
     313                    send( receiver, new_req );
     314                    return receiver;
     315                }
     316            */
     317            CompoundStmt * sendBody = new CompoundStmt( decl->location );
     318
     319            // Generates: request new_req;
     320            sendBody->push_back( new DeclStmt(
     321                decl->location,
     322                new ObjectDecl(
     323                    decl->location,
     324                    "new_req",
     325                    new StructInstType( *requestDecl )
     326                )
     327            ));
     328           
     329            // Function type is: allocation (*)( derived_actor &, derived_msg &, actor **, message ** )
     330            FunctionType * derivedReceive = new FunctionType();
     331            derivedReceive->params.push_back( ast::deepCopy( derivedActorRef ) );
     332            derivedReceive->params.push_back( ast::deepCopy( derivedMsgRef ) );
     333            derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
     334            derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
     335            derivedReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
     336
     337            // Generates: allocation (*my_work_fn)( derived_actor &, derived_msg &, actor **, message ** ) = receive;
     338            sendBody->push_back( new DeclStmt(
     339                decl->location,
     340                new ObjectDecl(
     341                    decl->location,
     342                    "my_work_fn",
     343                    new PointerType( derivedReceive ),
     344                    new SingleInit( decl->location, new NameExpr( decl->location, "__CFA_receive_wrap" ) )
     345                )
     346            ));
     347
     348            // Function type is: allocation (*)( actor &, message & )
     349            FunctionType * genericReceive = new FunctionType();
     350            genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) );
     351            genericReceive->params.push_back( new ReferenceType( new StructInstType( *msgDecl ) ) );
     352            genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
     353            genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
     354            genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
     355
     356            // Generates: allocation (*fn)( actor &, message & ) = (allocation (*)( actor &, message & ))my_work_fn;
     357            // More readable synonymous code:
     358            //     typedef allocation (*__receive_fn)(actor &, message &);
     359            //     __receive_fn fn = (__receive_fn)my_work_fn;
     360            sendBody->push_back( new DeclStmt(
     361                decl->location,
     362                new ObjectDecl(
     363                    decl->location,
     364                    "fn",
     365                    new PointerType( genericReceive ),
     366                    new SingleInit( decl->location,
     367                        new CastExpr( decl->location, new NameExpr( decl->location, "my_work_fn" ), new PointerType( genericReceive ), ExplicitCast )
     368                    )
     369                )
     370            ));
     371
     372            // Generates: new_req{ (actor *)&receiver, (message *)&msg, fn };
     373            sendBody->push_back( new ExprStmt(
     374                decl->location,
     375                                new UntypedExpr (
     376                    decl->location,
     377                                        new NameExpr( decl->location, "?{}" ),
    255378                                        {
    256                                                 new NameExpr( decl->location, "receiver" ),
    257                                                 new NameExpr( decl->location, "msg" )
     379                                                new NameExpr( decl->location, "new_req" ),
     380                        new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "receiver" ) ), new PointerType( new StructInstType( *actorDecl ) ), ExplicitCast ),
     381                        new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "msg" ) ), new PointerType( new StructInstType( *msgDecl ) ), ExplicitCast ),
     382                        new NameExpr( decl->location, "fn" )
    258383                                        }
    259384                                )
    260385                        ));
    261386
    262                         // create receive wrapper to extract base message and actor pointer
    263                         // put it all together into the complete function decl from above
    264                         FunctionDecl * receiveWrapper = new FunctionDecl(
    265                                 decl->location,
    266                                 "__CFA_receive_wrap",
    267                                 {
    268                                         new ObjectDecl(
    269                                                 decl->location,
    270                                                 "receiver",
    271                                                 ast::deepCopy( derivedActorRef )
    272                                         ),
    273                                         new ObjectDecl(
    274                                                 decl->location,
    275                                                 "msg",
    276                                                 ast::deepCopy( derivedMsgRef )
    277                                         ),
    278                                         new ObjectDecl(
    279                                                 decl->location,
    280                                                 "base_actor",
    281                                                 new PointerType( new PointerType( new StructInstType( *actorDecl ) ) )
    282                                         ),
    283                                         new ObjectDecl(
    284                                                 decl->location,
    285                                                 "base_msg",
    286                                                 new PointerType( new PointerType( new StructInstType( *msgDecl ) ) )
    287                                         )
    288                                 },                      // params
    289                                 {
    290                                         new ObjectDecl(
    291                                                 decl->location,
    292                                                 "__CFA_receive_wrap_ret",
    293                                                 new EnumInstType( *allocationDecl )
    294                                         )
    295                                 },
    296                                 wrapBody,               // body
    297                                 { Storage::Static },    // storage
    298                                 Linkage::Cforall,       // linkage
    299                                 {},                     // attributes
    300                                 { Function::Inline }
    301                         );
    302 
    303                         declsToAddAfter.push_back( receiveWrapper );
    304 
    305                         //////////////////////////////////////////////////////////////////////
    306                         // The following generates this send message operator routine for all receive(derived_actor &, derived_msg &) functions
    307                         /*
    308                                 static inline derived_actor & ?|?( derived_actor & receiver, derived_msg & msg ) {
    309                                         request new_req;
    310                                         allocation (*my_work_fn)( derived_actor &, derived_msg & ) = receive;
    311                                         __receive_fn fn = (__receive_fn)my_work_fn;
    312                                         new_req{ &receiver, &msg, fn };
    313                                         send( receiver, new_req );
    314                                         return receiver;
    315                                 }
    316                         */
    317                         CompoundStmt * sendBody = new CompoundStmt( decl->location );
    318 
    319                         // Generates: request new_req;
    320                         sendBody->push_back( new DeclStmt(
    321                                 decl->location,
    322                                 new ObjectDecl(
    323                                         decl->location,
    324                                         "new_req",
    325                                         new StructInstType( *requestDecl )
    326                                 )
    327                         ));
    328 
    329                         // Function type is: allocation (*)( derived_actor &, derived_msg &, actor **, message ** )
    330                         FunctionType * derivedReceive = new FunctionType();
    331                         derivedReceive->params.push_back( ast::deepCopy( derivedActorRef ) );
    332                         derivedReceive->params.push_back( ast::deepCopy( derivedMsgRef ) );
    333                         derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
    334                         derivedReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
    335                         derivedReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
    336 
    337                         // Generates: allocation (*my_work_fn)( derived_actor &, derived_msg &, actor **, message ** ) = receive;
    338                         sendBody->push_back( new DeclStmt(
    339                                 decl->location,
    340                                 new ObjectDecl(
    341                                         decl->location,
    342                                         "my_work_fn",
    343                                         new PointerType( derivedReceive ),
    344                                         new SingleInit( decl->location, new NameExpr( decl->location, "__CFA_receive_wrap" ) )
    345                                 )
    346                         ));
    347 
    348                         // Function type is: allocation (*)( actor &, message & )
    349                         FunctionType * genericReceive = new FunctionType();
    350                         genericReceive->params.push_back( new ReferenceType( new StructInstType( *actorDecl ) ) );
    351                         genericReceive->params.push_back( new ReferenceType( new StructInstType( *msgDecl ) ) );
    352                         genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *actorDecl ) ) ) );
    353                         genericReceive->params.push_back( new PointerType( new PointerType( new StructInstType( *msgDecl ) ) ) );
    354                         genericReceive->returns.push_back( new EnumInstType( *allocationDecl ) );
    355 
    356                         // Generates: allocation (*fn)( actor &, message & ) = (allocation (*)( actor &, message & ))my_work_fn;
    357                         // More readable synonymous code:
    358                         //     typedef allocation (*__receive_fn)(actor &, message &);
    359                         //     __receive_fn fn = (__receive_fn)my_work_fn;
    360                         sendBody->push_back( new DeclStmt(
    361                                 decl->location,
    362                                 new ObjectDecl(
    363                                         decl->location,
    364                                         "fn",
    365                                         new PointerType( genericReceive ),
    366                                         new SingleInit( decl->location,
    367                                                 new CastExpr( decl->location, new NameExpr( decl->location, "my_work_fn" ), new PointerType( genericReceive ), ExplicitCast )
    368                                         )
    369                                 )
    370                         ));
    371 
    372                         // Generates: new_req{ (actor *)&receiver, (message *)&msg, fn };
    373                         sendBody->push_back( new ExprStmt(
    374                                 decl->location,
     387            // Generates: send( receiver, new_req );
     388            sendBody->push_back( new ExprStmt(
     389                decl->location,
    375390                                new UntypedExpr (
    376                                         decl->location,
    377                                         new NameExpr( decl->location, "?{}" ),
     391                    decl->location,
     392                                        new NameExpr( decl->location, "send" ),
    378393                                        {
    379                                                 new NameExpr( decl->location, "new_req" ),
    380                                                 new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "receiver" ) ), new PointerType( new StructInstType( *actorDecl ) ), ExplicitCast ),
    381                                                 new CastExpr( decl->location, new AddressExpr( new NameExpr( decl->location, "msg" ) ), new PointerType( new StructInstType( *msgDecl ) ), ExplicitCast ),
    382                                                 new NameExpr( decl->location, "fn" )
     394                                                {
     395                            new NameExpr( decl->location, "receiver" ),
     396                            new NameExpr( decl->location, "new_req" )
     397                        }
    383398                                        }
    384399                                )
    385400                        ));
    386401
    387                         // Generates: send( receiver, new_req );
    388                         sendBody->push_back( new ExprStmt(
    389                                 decl->location,
    390                                 new UntypedExpr (
    391                                         decl->location,
    392                                         new NameExpr( decl->location, "send" ),
    393                                         {
    394                                                 {
    395                                                         new NameExpr( decl->location, "receiver" ),
    396                                                         new NameExpr( decl->location, "new_req" )
    397                                                 }
    398                                         }
    399                                 )
    400                         ));
    401 
    402                         // Generates: return receiver;
    403                         sendBody->push_back( new ReturnStmt( decl->location, new NameExpr( decl->location, "receiver" ) ) );
    404 
    405                         // put it all together into the complete function decl from above
    406                         FunctionDecl * sendOperatorFunction = new FunctionDecl(
    407                                 decl->location,
    408                                 "?|?",
    409                                 {
    410                                         new ObjectDecl(
    411                                                 decl->location,
    412                                                 "receiver",
    413                                                 ast::deepCopy( derivedActorRef )
    414                                         ),
    415                                         new ObjectDecl(
    416                                                 decl->location,
    417                                                 "msg",
    418                                                 ast::deepCopy( derivedMsgRef )
    419                                         )
    420                                 },                      // params
    421                                 {
    422                                         new ObjectDecl(
    423                                                 decl->location,
    424                                                 "receiver_ret",
    425                                                 ast::deepCopy( derivedActorRef )
    426                                         )
    427                                 },
    428                                 nullptr,               // body
    429                                 { Storage::Static },    // storage
    430                                 Linkage::Cforall,       // linkage
    431                                 {},                     // attributes
    432                                 { Function::Inline }
    433                         );
    434 
    435                         // forward decls to resolve use before decl problem for '|' routines
    436                         forwardDecls.insertDecl( *actorIter, *messageIter , ast::deepCopy( sendOperatorFunction ) );
    437 
    438                         sendOperatorFunction->stmts = sendBody;
    439                         declsToAddAfter.push_back( sendOperatorFunction );
    440                 }
     402            // Generates: return receiver;
     403            sendBody->push_back( new ReturnStmt( decl->location, new NameExpr( decl->location, "receiver" ) ) );
     404
     405            // put it all together into the complete function decl from above
     406            FunctionDecl * sendOperatorFunction = new FunctionDecl(
     407                decl->location,
     408                "?|?",
     409                {
     410                    new ObjectDecl(
     411                        decl->location,
     412                        "receiver",
     413                        ast::deepCopy( derivedActorRef )
     414                    ),
     415                    new ObjectDecl(
     416                        decl->location,
     417                        "msg",
     418                        ast::deepCopy( derivedMsgRef )
     419                    )
     420                },                      // params
     421                {
     422                    new ObjectDecl(
     423                        decl->location,
     424                        "receiver_ret",
     425                        ast::deepCopy( derivedActorRef )
     426                    )
     427                },
     428                nullptr,               // body
     429                { Storage::Static },    // storage
     430                Linkage::Cforall,       // linkage
     431                {},                     // attributes
     432                { Function::Inline }
     433            );
     434
     435            // forward decls to resolve use before decl problem for '|' routines
     436            forwardDecls.insertDecl( *actorIter, *messageIter , ast::deepCopy( sendOperatorFunction ) );
     437
     438            sendOperatorFunction->stmts = sendBody;
     439            declsToAddAfter.push_back( sendOperatorFunction );
     440        }
    441441        }
    442442
    443443  public:
    444         GenFuncsCreateTables( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
    445                 const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl,
    446                 FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls),
    447                 requestDecl(requestDecl), allocationDecl(allocationDecl), actorDecl(actorDecl), msgDecl(msgDecl), forwardDecls(forwardDecls) {}
     444    GenFuncsCreateTables( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
     445        const StructDecl ** requestDecl, const EnumDecl ** allocationDecl, const StructDecl ** actorDecl, const StructDecl ** msgDecl,
     446        FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls),
     447        requestDecl(requestDecl), allocationDecl(allocationDecl), actorDecl(actorDecl), msgDecl(msgDecl), forwardDecls(forwardDecls) {}
    448448};
    449449
     
    452452// generates the forward declarations of the send operator for actor routines
    453453struct FwdDeclOperator : public ast::WithDeclsToAdd<> {
    454         unordered_set<const StructDecl *> & actorStructDecls;
    455         unordered_set<const StructDecl *>  & messageStructDecls;
    456         FwdDeclTable & forwardDecls;
    457 
    458         // handles forward declaring the message operator
    459         void postvisit( const StructDecl * decl ) {
    460                 list<FunctionDecl *> toAddAfter;
    461                 auto actorIter = actorStructDecls.find( decl );
    462                 if ( actorIter != actorStructDecls.end() ) { // this is a derived actor decl
    463                         // get list of fwd decls that we can now insert
    464                         toAddAfter = forwardDecls.updateDecl( decl, false );
    465 
    466                         // get rid of decl from actorStructDecls since we no longer need it
    467                         actorStructDecls.erase( actorIter );
    468                 } else {
    469                         auto messageIter = messageStructDecls.find( decl );
    470                         if ( messageIter == messageStructDecls.end() ) return;
    471 
    472                         toAddAfter = forwardDecls.updateDecl( decl, true );
    473 
    474                         // get rid of decl from messageStructDecls since we no longer need it
    475                         messageStructDecls.erase( messageIter );
    476                 }
    477 
    478                 // add the fwd decls to declsToAddAfter
    479                 for ( FunctionDecl * func : toAddAfter ) {
    480                         declsToAddAfter.push_back( func );
    481                 }
    482         }
     454    unordered_set<const StructDecl *> & actorStructDecls;
     455    unordered_set<const StructDecl *>  & messageStructDecls;
     456    FwdDeclTable & forwardDecls;
     457
     458    // handles forward declaring the message operator
     459    void postvisit( const StructDecl * decl ) {
     460        list<FunctionDecl *> toAddAfter;
     461        auto actorIter = actorStructDecls.find( decl );
     462        if ( actorIter != actorStructDecls.end() ) { // this is a derived actor decl
     463            // get list of fwd decls that we can now insert
     464            toAddAfter = forwardDecls.updateDecl( decl, false );
     465
     466            // get rid of decl from actorStructDecls since we no longer need it
     467            actorStructDecls.erase( actorIter );
     468        } else {
     469            auto messageIter = messageStructDecls.find( decl );
     470            if ( messageIter == messageStructDecls.end() ) return;
     471
     472            toAddAfter = forwardDecls.updateDecl( decl, true );
     473
     474            // get rid of decl from messageStructDecls since we no longer need it
     475            messageStructDecls.erase( messageIter );
     476        }
     477
     478        // add the fwd decls to declsToAddAfter
     479        for ( FunctionDecl * func : toAddAfter ) {
     480            declsToAddAfter.push_back( func );
     481        }
     482    }
    483483
    484484  public:
    485         FwdDeclOperator( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
    486                 FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls), forwardDecls(forwardDecls) {}
     485    FwdDeclOperator( unordered_set<const StructDecl *> & actorStructDecls, unordered_set<const StructDecl *> & messageStructDecls,
     486        FwdDeclTable & forwardDecls ) : actorStructDecls(actorStructDecls), messageStructDecls(messageStructDecls), forwardDecls(forwardDecls) {}
    487487};
    488488
    489489void implementActors( TranslationUnit & translationUnit ) {
    490         // unordered_maps to collect all derived actor and message types
    491         unordered_set<const StructDecl *> actorStructDecls;
    492         unordered_set<const StructDecl *> messageStructDecls;
    493         FwdDeclTable forwardDecls;
    494 
    495         // for storing through the passes
    496         // these are populated with various important struct decls
    497         const StructDecl * requestDeclPtr = nullptr;
    498         const EnumDecl * allocationDeclPtr = nullptr;
    499         const StructDecl * actorDeclPtr = nullptr;
    500         const StructDecl * msgDeclPtr = nullptr;
    501 
    502         // double pointer to modify local ptrs above
    503         const StructDecl ** requestDecl = &requestDeclPtr;
    504         const EnumDecl ** allocationDecl = &allocationDeclPtr;
    505         const StructDecl ** actorDecl = &actorDeclPtr;
    506         const StructDecl ** msgDecl = &msgDeclPtr;
    507 
    508         // first pass collects ptrs to allocation enum, request type, and generic receive fn typedef
    509         // also populates maps of all derived actors and messages
    510         Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
    511                 allocationDecl, actorDecl, msgDecl );
    512 
    513         // check that we have found all the decls we need from <actor.hfa>, if not no need to run the rest of this pass
    514         if ( !allocationDeclPtr || !requestDeclPtr || !actorDeclPtr || !msgDeclPtr )
    515                 return;
    516 
    517         // second pass locates all receive() routines that overload the generic receive fn
    518         // it then generates the appropriate operator '|' send routines for the receive routines
    519         Pass<GenFuncsCreateTables>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
    520                 allocationDecl, actorDecl, msgDecl, forwardDecls );
    521 
    522         // The third pass forward declares operator '|' send routines
    523         Pass<FwdDeclOperator>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );
     490    // unordered_maps to collect all derived actor and message types
     491    unordered_set<const StructDecl *> actorStructDecls;
     492    unordered_set<const StructDecl *> messageStructDecls;
     493    FwdDeclTable forwardDecls;
     494
     495    // for storing through the passes
     496    // these are populated with various important struct decls
     497    const StructDecl * requestDeclPtr = nullptr;
     498    const EnumDecl * allocationDeclPtr = nullptr;
     499    const StructDecl * actorDeclPtr = nullptr;
     500    const StructDecl * msgDeclPtr = nullptr;
     501
     502    // double pointer to modify local ptrs above
     503    const StructDecl ** requestDecl = &requestDeclPtr;
     504    const EnumDecl ** allocationDecl = &allocationDeclPtr;
     505    const StructDecl ** actorDecl = &actorDeclPtr;
     506    const StructDecl ** msgDecl = &msgDeclPtr;
     507
     508    // first pass collects ptrs to allocation enum, request type, and generic receive fn typedef
     509    // also populates maps of all derived actors and messages
     510    Pass<CollectactorStructDecls>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
     511        allocationDecl, actorDecl, msgDecl );
     512
     513    // check that we have found all the decls we need from <actor.hfa>, if not no need to run the rest of this pass
     514    if ( !allocationDeclPtr || !requestDeclPtr || !actorDeclPtr || !msgDeclPtr )
     515        return;
     516
     517    // second pass locates all receive() routines that overload the generic receive fn
     518    // it then generates the appropriate operator '|' send routines for the receive routines
     519    Pass<GenFuncsCreateTables>::run( translationUnit, actorStructDecls, messageStructDecls, requestDecl,
     520        allocationDecl, actorDecl, msgDecl, forwardDecls );
     521
     522    // The third pass forward declares operator '|' send routines
     523    Pass<FwdDeclOperator>::run( translationUnit, actorStructDecls, messageStructDecls, forwardDecls );
    524524}
     525
    525526
    526527} // namespace Concurrency
  • src/Concurrency/Corun.cpp

    r7042c60 rcf191ac  
    2626
    2727struct CorunKeyword : public WithDeclsToAdd<>, public WithStmtsToAdd<> {
    28         UniqueName CorunFnNamer = "__CFA_corun_lambda_"s;
    29         UniqueName CoforFnNamer = "__CFA_cofor_lambda_"s;
    30         // UniqueName CoforFnVarNamer = "__CFA_cofor_lambda_var"s;
    31         UniqueName RunnerBlockNamer = "__CFA_corun_block_"s;
    32 
    33         string coforArgName = "__CFA_cofor_lambda_arg";
    34         string numProcsName = "__CFA_cofor_num_procs";
    35         string currProcsName = "__CFA_cofor_curr_procs";
    36         string thdArrName = "__CFA_cofor_thread_array";
    37         string loopTempName = "__CFA_cofor_loop_temp";
    38 
    39 
    40         const StructDecl * runnerBlockDecl = nullptr;
    41         const StructDecl * coforRunnerDecl = nullptr;
    42 
    43         // Finds runner_block (corun task) and cofor_runner (cofor task) decls
    44         void previsit( const StructDecl * decl ) {
    45                 if ( !decl->body ) {
    46                         return;
    47                 } else if ( "runner_block" == decl->name ) {
    48                         assert( !runnerBlockDecl );
    49                         runnerBlockDecl = decl;
    50                 } else if ( "cofor_runner" == decl->name ) {
    51                         assert( !coforRunnerDecl );
    52                         coforRunnerDecl = decl;
    53                 }
    54         }
    55 
    56         // codegen for cofor statements
    57         Stmt * postvisit( const CoforStmt * stmt ) {
    58                 if ( !runnerBlockDecl || !coforRunnerDecl )
    59                         SemanticError( stmt->location, "To use cofor statements add #include <cofor.hfa>" );
    60 
    61                 if ( stmt->inits.size() != 1 )
    62                         SemanticError( stmt->location, "Cofor statements must have a single initializer in the loop control" );
    63 
    64                 if ( !stmt->body )
    65                         return nullptr;
    66 
    67                 const CodeLocation & loc = stmt->location;
    68                 const string fnName = CoforFnNamer.newName();
    69 
    70                 CompoundStmt * body = new CompoundStmt( loc );
    71 
    72                 // push back cofor initializer to generated body
    73                 body->push_back( deepCopy( stmt->inits.at(0) ) );
    74 
    75                 CompoundStmt * fnBody = new CompoundStmt( loc );
    76 
    77                 const DeclStmt * declStmtPtr = dynamic_cast<const DeclStmt *>(stmt->inits.at(0).get());
    78                 if ( ! declStmtPtr )
    79                         SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl statement?" );
    80 
    81                 const Decl * declPtr = dynamic_cast<const Decl *>(declStmtPtr->decl.get());
    82                 if ( ! declPtr )
    83                         SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl?" );
    84 
    85                 Type * initType = new TypeofType( new NameExpr( loc, declPtr->name ) );
    86 
    87                 // Generates:
    88                 // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
    89                 fnBody->push_back( new DeclStmt( loc,
    90                         new ObjectDecl( loc,
    91                                 declPtr->name,
    92                                 initType,
    93                                 new SingleInit( loc,
    94                                         UntypedExpr::createDeref( loc,
    95                                                 new CastExpr( loc,
    96                                                         new NameExpr( loc, coforArgName ),
    97                                                         new PointerType( initType ), ExplicitCast
    98                                                 )
    99                                         )
    100                                 )
    101                         )
    102                 ));
    103 
    104                 // push rest of cofor body into loop lambda
    105                 fnBody->push_back( deepCopy( stmt->body ) );
    106 
    107                 // Generates:
    108                 // void __CFA_cofor_lambda_() {
    109                 //    typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
    110                 //    stmt->body;
    111                 // }
    112                 Stmt * coforLambda = new DeclStmt( loc,
    113                         new FunctionDecl( loc,
    114                                 fnName,                                             // name
    115                                 {
    116                                         new ObjectDecl( loc,
    117                                                 coforArgName,
    118                                                 new ast::PointerType( new ast::VoidType() )
    119                                         )
    120                                 },                                                  // params
    121                                 {},                                                 // return
    122                                 fnBody   // body
    123                         )
    124                 );
    125                 body->push_back( coforLambda );
    126 
    127                 // Generates:
    128                 // unsigned __CFA_cofor_num_procs = get_proc_count();
    129                 body->push_back( new DeclStmt( loc,
    130                                 new ObjectDecl( loc,
    131                                         numProcsName,
    132                                         new BasicType( BasicKind::UnsignedInt ),
    133                                         new SingleInit( loc,
    134                                                 new UntypedExpr( loc,
    135                                                         new NameExpr( loc, "get_proc_count" ),
    136                                                         {}
    137                                                 )
    138                                         )
    139                                 )
    140                         )
    141                 );
    142 
    143                 // Generates:
    144                 // unsigned __CFA_cofor_curr_procs = 0;
    145                 body->push_back( new DeclStmt( loc,
    146                                 new ObjectDecl( loc,
    147                                         currProcsName,
    148                                         new BasicType( BasicKind::UnsignedInt ),
    149                                         new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
    150                                 )
    151                         )
    152                 );
    153 
    154                 // Generates:
    155                 // unsigned cofor_runner __CFA_cofor_thread_array[nprocs];
    156                 body->push_back( new DeclStmt( loc,
    157                                 new ObjectDecl( loc,
    158                                         thdArrName,
    159                                         new ast::ArrayType(
    160                                                 new StructInstType( coforRunnerDecl ),
    161                                                 new NameExpr( loc, numProcsName ),
    162                                                 ast::FixedLen,
    163                                                 ast::DynamicDim
    164                                         )
    165                                 )
    166                         )
    167                 );
    168 
    169                 // Generates:
    170                 // start_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs, __CFA_cofor_lambda_ );
    171                 body->push_back( new ExprStmt( loc,
    172                         new UntypedExpr( loc,
    173                                 new NameExpr( loc, "start_runners" ),
    174                                 {
    175                                         new NameExpr( loc, thdArrName ),
    176                                         new NameExpr( loc, numProcsName ),
    177                                         new NameExpr( loc, fnName )
    178                                 }
    179                         )
    180                 ));
    181 
    182                 // Generates:
    183                 // typeof(initializer) * __CFA_cofor_loop_temp = malloc();
    184                 CompoundStmt * forLoopBody = new CompoundStmt( loc );
    185                 forLoopBody->push_back( new DeclStmt( loc,
    186                                 new ObjectDecl( loc,
    187                                         loopTempName,
    188                                         new PointerType( initType ),
    189                                         new SingleInit( loc,
    190                                                 new UntypedExpr( loc,
    191                                                         new NameExpr( loc, "malloc" ),
    192                                                         {}
    193                                                 )
    194                                         )
    195                                 )
    196                         )
    197                 );
    198 
    199                 // Generates:
    200                 // *__CFA_cofor_loop_temp = initializer;
    201                 forLoopBody->push_back( new ExprStmt( loc,
    202                         UntypedExpr::createAssign( loc,
    203                                 UntypedExpr::createDeref( loc, new NameExpr( loc, loopTempName ) ),
    204                                 new NameExpr( loc, declPtr->name )
    205                         )
    206                 ));
    207 
    208                 // Generates:
    209                 // send_work( __CFA_cofor_thread_array, __CFA_cofor_num_procs,
    210                 //     __CFA_cofor_curr_procs, __CFA_cofor_loop_temp );
    211                 forLoopBody->push_back( new ExprStmt( loc,
    212                         new UntypedExpr( loc,
    213                                 new NameExpr( loc, "send_work" ),
    214                                 {
    215                                         new NameExpr( loc, thdArrName ),
    216                                         new NameExpr( loc, numProcsName ),
    217                                         new NameExpr( loc, currProcsName ),
    218                                         new NameExpr( loc, loopTempName )
    219                                 }
    220                         )
    221                 ));
    222 
    223                 body->push_back( new ForStmt( loc,
    224                         {},
    225                         deepCopy( stmt->cond ),
    226                         deepCopy( stmt->inc ),
    227                         forLoopBody
    228                 ));
    229 
    230                 // Generates:
    231                 // end_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs );
    232                 body->push_back( new ExprStmt( loc,
    233                         new UntypedExpr( loc,
    234                                 new NameExpr( loc, "end_runners" ),
    235                                 {
    236                                         new NameExpr( loc, thdArrName ),
    237                                         new NameExpr( loc, numProcsName )
    238                                 }
    239                         )
    240                 ));
    241 
    242                 return body;
    243         }
    244 
    245         // codegen for corun statements
    246         Stmt * postvisit( const CorunStmt * stmt ) {
    247                 if ( !runnerBlockDecl || !coforRunnerDecl )
    248                         SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>" );
    249 
    250                 if ( !stmt->stmt )
    251                         return nullptr;
    252 
    253                 const CodeLocation & loc = stmt->location;
    254                 const string fnName = CorunFnNamer.newName();
    255                 const string objName = RunnerBlockNamer.newName();
    256 
    257                 // Generates:
    258                 // void __CFA_corun_lambda_() { ... stmt->stmt ... }
    259                 Stmt * runnerLambda = new DeclStmt( loc,
    260                         new FunctionDecl( loc,
    261                                 fnName,                                             // name
    262                                 {},                                                 // params
    263                                 {},                                                 // return
    264                                 new CompoundStmt( loc, { deepCopy(stmt->stmt) } )   // body
    265                         )
    266                 );
    267 
    268                 // Generates:
    269                 // runner_block __CFA_corun_block_;
    270                 Stmt * objDecl = new DeclStmt( loc,
    271                         new ObjectDecl( loc,
    272                                 objName,
    273                                 new StructInstType( runnerBlockDecl )
    274                         )
    275                 );
    276 
    277                 // Generates:
    278                 // __CFA_corun_block_{ __CFA_corun_lambda_ };
    279                 Stmt * threadStart = new ExprStmt( loc,
    280                         new UntypedExpr ( loc,
    281                                 new NameExpr( loc, "?{}" ),
    282                                 {
    283                                         new NameExpr( loc, objName ),
    284                                         new NameExpr( loc, fnName )
    285                                 }
    286                         )
    287                 );
    288 
    289                 stmtsToAddBefore.push_back( runnerLambda );
    290                 stmtsToAddBefore.push_back( objDecl );
    291 
    292                 return threadStart;
    293         }
     28    UniqueName CorunFnNamer = "__CFA_corun_lambda_"s;
     29    UniqueName CoforFnNamer = "__CFA_cofor_lambda_"s;
     30    // UniqueName CoforFnVarNamer = "__CFA_cofor_lambda_var"s;
     31    UniqueName RunnerBlockNamer = "__CFA_corun_block_"s;
     32   
     33    string coforArgName = "__CFA_cofor_lambda_arg";
     34    string numProcsName = "__CFA_cofor_num_procs";
     35    string currProcsName = "__CFA_cofor_curr_procs";
     36    string thdArrName = "__CFA_cofor_thread_array";
     37    string loopTempName = "__CFA_cofor_loop_temp";
     38   
     39
     40    const StructDecl * runnerBlockDecl = nullptr;
     41    const StructDecl * coforRunnerDecl = nullptr;
     42
     43    // Finds runner_block (corun task) and cofor_runner (cofor task) decls
     44    void previsit( const StructDecl * decl ) {
     45        if ( !decl->body ) {
     46            return;
     47        } else if ( "runner_block" == decl->name ) {
     48            assert( !runnerBlockDecl );
     49            runnerBlockDecl = decl;
     50        } else if ( "cofor_runner" == decl->name ) {
     51            assert( !coforRunnerDecl );
     52            coforRunnerDecl = decl;
     53        }
     54    }
     55
     56    // codegen for cofor statements
     57    Stmt * postvisit( const CoforStmt * stmt ) {
     58        if ( !runnerBlockDecl || !coforRunnerDecl )
     59            SemanticError( stmt->location, "To use cofor statements add #include <cofor.hfa>" );
     60
     61        if ( stmt->inits.size() != 1 )
     62            SemanticError( stmt->location, "Cofor statements must have a single initializer in the loop control" );
     63
     64        if ( !stmt->body )
     65            return nullptr;
     66
     67        const CodeLocation & loc = stmt->location;
     68        const string fnName = CoforFnNamer.newName();
     69
     70        CompoundStmt * body = new CompoundStmt( loc );
     71
     72        // push back cofor initializer to generated body
     73        body->push_back( deepCopy( stmt->inits.at(0) ) );
     74
     75        CompoundStmt * fnBody = new CompoundStmt( loc );
     76
     77        const DeclStmt * declStmtPtr = dynamic_cast<const DeclStmt *>(stmt->inits.at(0).get());
     78        if ( ! declStmtPtr )
     79            SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl statement?" );
     80
     81        const Decl * declPtr = dynamic_cast<const Decl *>(declStmtPtr->decl.get());
     82        if ( ! declPtr )
     83            SemanticError( stmt->location, "Cofor statement initializer is somehow not a decl?" );
     84
     85        Type * initType = new TypeofType( new NameExpr( loc, declPtr->name ) );
     86
     87        // Generates:
     88        // typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
     89        fnBody->push_back( new DeclStmt( loc,
     90            new ObjectDecl( loc,
     91                declPtr->name,
     92                initType,
     93                new SingleInit( loc,
     94                    UntypedExpr::createDeref( loc,
     95                        new CastExpr( loc,
     96                            new NameExpr( loc, coforArgName ),
     97                            new PointerType( initType ), ExplicitCast
     98                        )
     99                    )
     100                )
     101            )
     102        ));
     103
     104        // push rest of cofor body into loop lambda
     105        fnBody->push_back( deepCopy( stmt->body ) );
     106
     107        // Generates:
     108        // void __CFA_cofor_lambda_() {
     109        //    typeof(init) __CFA_cofor_lambda_var = *((typeof(init) *)val);
     110        //    stmt->body;
     111        // }
     112        Stmt * coforLambda = new DeclStmt( loc,
     113            new FunctionDecl( loc,
     114                fnName,                                             // name
     115                {
     116                    new ObjectDecl( loc,
     117                        coforArgName,
     118                        new ast::PointerType( new ast::VoidType() )
     119                    )
     120                },                                                  // params
     121                {},                                                 // return
     122                fnBody   // body
     123            )
     124        );
     125        body->push_back( coforLambda );
     126
     127        // Generates:
     128        // unsigned __CFA_cofor_num_procs = get_proc_count();
     129        body->push_back( new DeclStmt( loc,
     130                new ObjectDecl( loc,
     131                    numProcsName,
     132                    new BasicType( BasicKind::UnsignedInt ),
     133                    new SingleInit( loc,
     134                        new UntypedExpr( loc,
     135                            new NameExpr( loc, "get_proc_count" ),
     136                            {}
     137                        )
     138                    )
     139                )
     140            )
     141        );
     142
     143        // Generates:
     144        // unsigned __CFA_cofor_curr_procs = 0;
     145        body->push_back( new DeclStmt( loc,
     146                new ObjectDecl( loc,
     147                    currProcsName,
     148                    new BasicType( BasicKind::UnsignedInt ),
     149                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     150                )
     151            )
     152        );
     153
     154        // Generates:
     155        // unsigned cofor_runner __CFA_cofor_thread_array[nprocs];
     156        body->push_back( new DeclStmt( loc,
     157                new ObjectDecl( loc,
     158                    thdArrName,
     159                    new ast::ArrayType(
     160                        new StructInstType( coforRunnerDecl ),
     161                        new NameExpr( loc, numProcsName ),
     162                        ast::FixedLen,
     163                        ast::DynamicDim
     164                    )
     165                )
     166            )
     167        );
     168
     169        // Generates:
     170        // start_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs, __CFA_cofor_lambda_ );
     171        body->push_back( new ExprStmt( loc,
     172            new UntypedExpr( loc,
     173                new NameExpr( loc, "start_runners" ),
     174                {
     175                    new NameExpr( loc, thdArrName ),
     176                    new NameExpr( loc, numProcsName ),
     177                    new NameExpr( loc, fnName )
     178                }
     179            )
     180        ));
     181
     182        // Generates:
     183        // typeof(initializer) * __CFA_cofor_loop_temp = malloc();
     184        CompoundStmt * forLoopBody = new CompoundStmt( loc );
     185        forLoopBody->push_back( new DeclStmt( loc,
     186                new ObjectDecl( loc,
     187                    loopTempName,
     188                    new PointerType( initType ),
     189                    new SingleInit( loc,
     190                        new UntypedExpr( loc,
     191                            new NameExpr( loc, "malloc" ),
     192                            {}
     193                        )
     194                    )
     195                )
     196            )
     197        );
     198
     199        // Generates:
     200        // *__CFA_cofor_loop_temp = initializer;
     201        forLoopBody->push_back( new ExprStmt( loc,
     202            UntypedExpr::createAssign( loc,
     203                UntypedExpr::createDeref( loc, new NameExpr( loc, loopTempName ) ),
     204                new NameExpr( loc, declPtr->name )
     205            )
     206        ));
     207
     208        // Generates:
     209        // send_work( __CFA_cofor_thread_array, __CFA_cofor_num_procs,
     210        //     __CFA_cofor_curr_procs, __CFA_cofor_loop_temp );
     211        forLoopBody->push_back( new ExprStmt( loc,
     212            new UntypedExpr( loc,
     213                new NameExpr( loc, "send_work" ),
     214                {
     215                    new NameExpr( loc, thdArrName ),
     216                    new NameExpr( loc, numProcsName ),
     217                    new NameExpr( loc, currProcsName ),
     218                    new NameExpr( loc, loopTempName )
     219                }
     220            )
     221        ));
     222
     223        body->push_back( new ForStmt( loc,
     224            {},
     225            deepCopy( stmt->cond ),
     226            deepCopy( stmt->inc ),
     227            forLoopBody
     228        ));
     229
     230        // Generates:
     231        // end_runners( __CFA_cofor_thread_array, __CFA_cofor_num_procs );
     232        body->push_back( new ExprStmt( loc,
     233            new UntypedExpr( loc,
     234                new NameExpr( loc, "end_runners" ),
     235                {
     236                    new NameExpr( loc, thdArrName ),
     237                    new NameExpr( loc, numProcsName )
     238                }
     239            )
     240        ));
     241
     242        return body;
     243    }
     244
     245    // codegen for corun statements
     246    Stmt * postvisit( const CorunStmt * stmt ) {
     247        if ( !runnerBlockDecl || !coforRunnerDecl )
     248            SemanticError( stmt->location, "To use corun statements add #include <cofor.hfa>" );
     249
     250        if ( !stmt->stmt )
     251            return nullptr;
     252
     253        const CodeLocation & loc = stmt->location;
     254        const string fnName = CorunFnNamer.newName();
     255        const string objName = RunnerBlockNamer.newName();
     256
     257        // Generates:
     258        // void __CFA_corun_lambda_() { ... stmt->stmt ... }
     259        Stmt * runnerLambda = new DeclStmt( loc,
     260            new FunctionDecl( loc,
     261                fnName,                                             // name
     262                {},                                                 // params
     263                {},                                                 // return
     264                new CompoundStmt( loc, { deepCopy(stmt->stmt) } )   // body
     265            )
     266        );
     267
     268        // Generates:
     269        // runner_block __CFA_corun_block_;
     270        Stmt * objDecl = new DeclStmt( loc,
     271            new ObjectDecl( loc,
     272                objName,
     273                new StructInstType( runnerBlockDecl )
     274            )
     275        );
     276
     277        // Generates:
     278        // __CFA_corun_block_{ __CFA_corun_lambda_ };
     279        Stmt * threadStart = new ExprStmt( loc,
     280            new UntypedExpr ( loc,
     281                new NameExpr( loc, "?{}" ),
     282                {
     283                    new NameExpr( loc, objName ),
     284                    new NameExpr( loc, fnName )
     285                }
     286            )
     287        );
     288
     289        stmtsToAddBefore.push_back( runnerLambda );
     290        stmtsToAddBefore.push_back( objDecl );
     291
     292        return threadStart;
     293    }
    294294};
    295295
    296296void implementCorun( TranslationUnit & translationUnit ) {
    297         Pass<CorunKeyword>::run( translationUnit );
     297    Pass<CorunKeyword>::run( translationUnit );
    298298}
    299299
  • src/Concurrency/Keywords.cpp

    r7042c60 rcf191ac  
    991991        ast::CompoundStmt * body =
    992992                        new ast::CompoundStmt( stmt->location, { stmt->stmt } );
    993 
     993       
    994994        return addStatements( body, stmt->mutexObjs );;
    995995}
     
    11801180
    11811181// generates a cast to the void ptr to the appropriate lock type and dereferences it before calling lock or unlock on it
    1182 // used to undo the type erasure done by storing all the lock pointers as void
     1182// used to undo the type erasure done by storing all the lock pointers as void 
    11831183ast::ExprStmt * MutexKeyword::genVirtLockUnlockExpr( const std::string & fnName, ast::ptr<ast::Expr> expr, const CodeLocation & location, ast::Expr * param ) {
    11841184        return new ast::ExprStmt( location,
     
    11871187                                ast::UntypedExpr::createDeref(
    11881188                                        location,
    1189                                         new ast::CastExpr( location,
     1189                                        new ast::CastExpr( location, 
    11901190                                                param,
    11911191                                                new ast::PointerType( new ast::TypeofType( new ast::UntypedExpr(
     
    12081208        //adds an if/elif clause for each lock to assign type from void ptr based on ptr address
    12091209        for ( long unsigned int i = 0; i < args.size(); i++ ) {
    1210 
     1210               
    12111211                ast::UntypedExpr * ifCond = new ast::UntypedExpr( location,
    12121212                        new ast::NameExpr( location, "?==?" ), {
     
    12161216                );
    12171217
    1218                 ast::IfStmt * currLockIf = new ast::IfStmt(
     1218                ast::IfStmt * currLockIf = new ast::IfStmt( 
    12191219                        location,
    12201220                        ifCond,
    12211221                        genVirtLockUnlockExpr( fnName, args.at(i), location, ast::deepCopy( thisParam ) )
    12221222                );
    1223 
     1223               
    12241224                if ( i == 0 ) {
    12251225                        outerLockIf = currLockIf;
     
    12351235
    12361236void flattenTuple( const ast::UntypedTupleExpr * tuple, std::vector<ast::ptr<ast::Expr>> & output ) {
    1237         for ( auto & expr : tuple->exprs ) {
    1238                 const ast::UntypedTupleExpr * innerTuple = dynamic_cast<const ast::UntypedTupleExpr *>(expr.get());
    1239                 if ( innerTuple ) flattenTuple( innerTuple, output );
    1240                 else output.emplace_back( ast::deepCopy( expr ));
    1241         }
     1237    for ( auto & expr : tuple->exprs ) {
     1238        const ast::UntypedTupleExpr * innerTuple = dynamic_cast<const ast::UntypedTupleExpr *>(expr.get());
     1239        if ( innerTuple ) flattenTuple( innerTuple, output );
     1240        else output.emplace_back( ast::deepCopy( expr ));
     1241    }
    12421242}
    12431243
     
    12551255        // std::string unlockFnName = mutex_func_namer.newName();
    12561256
    1257         // If any arguments to the mutex stmt are tuples, flatten them
    1258         std::vector<ast::ptr<ast::Expr>> flattenedArgs;
    1259         for ( auto & arg : args ) {
    1260                 const ast::UntypedTupleExpr * tuple = dynamic_cast<const ast::UntypedTupleExpr *>(args.at(0).get());
    1261                 if ( tuple ) flattenTuple( tuple, flattenedArgs );
    1262                 else flattenedArgs.emplace_back( ast::deepCopy( arg ));
    1263         }
     1257    // If any arguments to the mutex stmt are tuples, flatten them
     1258    std::vector<ast::ptr<ast::Expr>> flattenedArgs;
     1259    for ( auto & arg : args ) {
     1260        const ast::UntypedTupleExpr * tuple = dynamic_cast<const ast::UntypedTupleExpr *>(args.at(0).get());
     1261        if ( tuple ) flattenTuple( tuple, flattenedArgs );
     1262        else flattenedArgs.emplace_back( ast::deepCopy( arg ));
     1263    }
    12641264
    12651265        // Make pointer to the monitors.
     
    13021302        // adds a nested try stmt for each lock we are locking
    13031303        for ( long unsigned int i = 0; i < flattenedArgs.size(); i++ ) {
    1304                 ast::UntypedExpr * innerAccess = new ast::UntypedExpr(
     1304                ast::UntypedExpr * innerAccess = new ast::UntypedExpr( 
    13051305                        location,
    13061306                        new ast::NameExpr( location,"?[?]" ), {
     
    14261426        //      );
    14271427
    1428         //      ast::IfStmt * currLockIf = new ast::IfStmt(
     1428        //      ast::IfStmt * currLockIf = new ast::IfStmt( 
    14291429        //              location,
    14301430        //              ast::deepCopy( ifCond ),
     
    14321432        //      );
    14331433
    1434         //      ast::IfStmt * currUnlockIf = new ast::IfStmt(
     1434        //      ast::IfStmt * currUnlockIf = new ast::IfStmt( 
    14351435        //              location,
    14361436        //              ifCond,
    14371437        //              genVirtLockUnlockExpr( "unlock", args.at(i), location, ast::deepCopy( thisParam ) )
    14381438        //      );
    1439 
     1439               
    14401440        //      if ( i == 0 ) {
    14411441        //              outerLockIf = currLockIf;
     
    14501450        //      lastUnlockIf = currUnlockIf;
    14511451        // }
    1452 
     1452       
    14531453        // // add pointer typing if/elifs to body of routines
    14541454        // lock_decl->stmts = new ast::CompoundStmt( location, { outerLockIf } );
  • src/Concurrency/Waituntil.cpp

    r7042c60 rcf191ac  
    3131/* So this is what this pass dones:
    3232{
    33         when ( condA ) waituntil( A ){ doA(); }
    34         or when ( condB ) waituntil( B ){ doB(); }
    35         and when ( condC ) waituntil( C ) { doC(); }
     33    when ( condA ) waituntil( A ){ doA(); }
     34    or when ( condB ) waituntil( B ){ doB(); }
     35    and when ( condC ) waituntil( C ) { doC(); }
    3636}
    3737                 ||
     
    4242Generates these two routines:
    4343static inline bool is_full_sat_1( int * clause_statuses ) {
    44         return clause_statuses[0]
    45                 || clause_statuses[1]
    46                 && clause_statuses[2];
     44    return clause_statuses[0]
     45        || clause_statuses[1]
     46        && clause_statuses[2];
    4747}
    4848
    4949static inline bool is_done_sat_1( int * clause_statuses ) {
    50         return has_run(clause_statuses[0])
    51                 || has_run(clause_statuses[1])
    52                 && has_run(clause_statuses[2]);
     50    return has_run(clause_statuses[0])
     51        || has_run(clause_statuses[1])
     52        && has_run(clause_statuses[2]);
    5353}
    5454
    5555Replaces the waituntil statement above with the following code:
    5656{
    57         // used with atomic_dec/inc to get binary semaphore behaviour
    58         int park_counter = 0;
    59 
    60         // status (one for each clause)
    61         int clause_statuses[3] = { 0 };
    62 
    63         bool whenA = condA;
    64         bool whenB = condB;
    65         bool whenC = condC;
    66 
    67         if ( !whenB ) clause_statuses[1] = __SELECT_RUN;
    68         if ( !whenC ) clause_statuses[2] = __SELECT_RUN;
    69 
    70         // some other conditional settors for clause_statuses are set here, see genSubtreeAssign and related routines
    71 
    72         // three blocks
    73         // for each block, create, setup, then register select_node
    74         select_node clause1;
    75         select_node clause2;
    76         select_node clause3;
    77 
    78         try {
    79                 if ( whenA ) { register_select(A, clause1); setup_clause( clause1, &clause_statuses[0], &park_counter ); }
    80                 ... repeat ^ for B and C ...
    81 
    82                 // if else clause is defined a separate branch can occur here to set initial values, see genWhenStateConditions
    83 
    84                 // loop & park until done
    85                 while( !is_full_sat_1( clause_statuses ) ) {
    86 
    87                         // binary sem P();
    88                         if ( __atomic_sub_fetch( &park_counter, 1, __ATOMIC_SEQ_CST) < 0 )
    89                                 park();
    90 
    91                         // execute any blocks available with status set to 0
    92                         for ( int i = 0; i < 3; i++ ) {
    93                                 if (clause_statuses[i] == __SELECT_SAT) {
    94                                     switch (i) {
    95                                         case 0:
    96                                             try {
    97                                                     on_selected( A, clause1 );
    98                                                     doA();
    99                                             }
    100                                             finally { clause_statuses[i] = __SELECT_RUN; unregister_select(A, clause1); }
    101                                             break;
    102                                         case 1:
    103                                             ... same gen as A but for B and clause2 ...
    104                                             break;
    105                                         case 2:
    106                                             ... same gen as A but for C and clause3 ...
    107                                             break;
    108                                     }
    109                                 }
    110                         }
    111                 }
    112 
    113                 // ensure that the blocks that triggered is_full_sat_1 are run
    114                 // by running every un-run block that is SAT from the start until
    115                 // the predicate is SAT when considering RUN status = true
    116                 for ( int i = 0; i < 3; i++ ) {
    117                         if (is_done_sat_1( clause_statuses )) break;
    118                         if (clause_statuses[i] == __SELECT_SAT)
    119                                 ... Same if body here as in loop above ...
    120                 }
    121         } finally {
    122                 // the unregister and on_selected calls are needed to support primitives where the acquire has side effects
    123                 // so the corresponding block MUST be run for those primitives to not lose state (example is channels)
    124                 if ( !has_run(clause_statuses[0]) && whenA && unregister_select(A, clause1) )
    125                         on_selected( A, clause1 )
    126                         doA();
    127                 ... repeat if above for B and C ...
    128         }
     57    // used with atomic_dec/inc to get binary semaphore behaviour
     58    int park_counter = 0;
     59
     60    // status (one for each clause)
     61    int clause_statuses[3] = { 0 };
     62
     63    bool whenA = condA;
     64    bool whenB = condB;
     65    bool whenC = condC;
     66
     67    if ( !whenB ) clause_statuses[1] = __SELECT_RUN;
     68    if ( !whenC ) clause_statuses[2] = __SELECT_RUN;
     69
     70    // some other conditional settors for clause_statuses are set here, see genSubtreeAssign and related routines
     71
     72    // three blocks
     73    // for each block, create, setup, then register select_node
     74    select_node clause1;
     75    select_node clause2;
     76    select_node clause3;
     77
     78    try {
     79        if ( whenA ) { register_select(A, clause1); setup_clause( clause1, &clause_statuses[0], &park_counter ); }
     80        ... repeat ^ for B and C ...
     81
     82        // if else clause is defined a separate branch can occur here to set initial values, see genWhenStateConditions
     83
     84        // loop & park until done
     85        while( !is_full_sat_1( clause_statuses ) ) {
     86           
     87            // binary sem P();
     88            if ( __atomic_sub_fetch( &park_counter, 1, __ATOMIC_SEQ_CST) < 0 )
     89                park();
     90           
     91            // execute any blocks available with status set to 0
     92            for ( int i = 0; i < 3; i++ ) {
     93                if (clause_statuses[i] == __SELECT_SAT) {
     94                    switch (i) {
     95                        case 0:
     96                            try {
     97                                    on_selected( A, clause1 );
     98                                    doA();
     99                            }
     100                            finally { clause_statuses[i] = __SELECT_RUN; unregister_select(A, clause1); }
     101                            break;
     102                        case 1:
     103                            ... same gen as A but for B and clause2 ...
     104                            break;
     105                        case 2:
     106                            ... same gen as A but for C and clause3 ...
     107                            break;
     108                    }
     109                }
     110            }
     111        }
     112
     113        // ensure that the blocks that triggered is_full_sat_1 are run
     114        // by running every un-run block that is SAT from the start until
     115        // the predicate is SAT when considering RUN status = true
     116        for ( int i = 0; i < 3; i++ ) {
     117            if (is_done_sat_1( clause_statuses )) break;
     118            if (clause_statuses[i] == __SELECT_SAT)
     119                ... Same if body here as in loop above ...
     120        }
     121    } finally {
     122        // the unregister and on_selected calls are needed to support primitives where the acquire has side effects
     123        // so the corresponding block MUST be run for those primitives to not lose state (example is channels)
     124        if ( !has_run(clause_statuses[0]) && whenA && unregister_select(A, clause1) )
     125            on_selected( A, clause1 )
     126            doA();
     127        ... repeat if above for B and C ...
     128    }
    129129}
    130130
     
    134134
    135135class GenerateWaitUntilCore final {
    136         vector<FunctionDecl *> & satFns;
     136    vector<FunctionDecl *> & satFns;
    137137        UniqueName namer_sat = "__is_full_sat_"s;
    138         UniqueName namer_run = "__is_run_sat_"s;
     138    UniqueName namer_run = "__is_run_sat_"s;
    139139        UniqueName namer_park = "__park_counter_"s;
    140140        UniqueName namer_status = "__clause_statuses_"s;
    141141        UniqueName namer_node = "__clause_"s;
    142         UniqueName namer_target = "__clause_target_"s;
    143         UniqueName namer_when = "__when_cond_"s;
    144         UniqueName namer_label = "__waituntil_label_"s;
    145 
    146         string idxName = "__CFA_clause_idx_";
    147 
    148         struct ClauseData {
    149                 string nodeName;
    150                 string targetName;
    151                 string whenName;
    152                 int index;
    153                 string & statusName;
    154                 ClauseData( int index, string & statusName ) : index(index), statusName(statusName) {}
    155         };
    156 
    157         const StructDecl * selectNodeDecl = nullptr;
    158 
    159         // This first set of routines are all used to do the complicated job of
    160         //    dealing with how to set predicate statuses with certain when_conds T/F
    161         //    so that the when_cond == F effectively makes that clause "disappear"
    162         void updateAmbiguousWhen( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool andBelow, bool orBelow );
    163         void paintWhenTree( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool & andBelow, bool & orBelow );
    164         bool paintWhenTree( WaitUntilStmt::ClauseNode * currNode );
    165         void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs, int & index, bool parentAmbig, bool parentAnd );
    166         void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs );
    167         void updateWhenState( WaitUntilStmt::ClauseNode * currNode );
    168         void genSubtreeAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, bool status, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
    169         void genStatusAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
    170         CompoundStmt * getStatusAssignment( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData );
    171         Stmt * genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx );
    172 
    173         // These routines are just code-gen helpers
    174         void addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName );
    175         void setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body );
    176         CompoundStmt * genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName );
    177         Expr * genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName );
    178         CompoundStmt * genStmtBlock( const WhenClause * clause, const ClauseData * data );
    179         Stmt * genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData );
    180         Stmt * genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData );
    181         void genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName );
    182         Stmt * recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName );
    183         Stmt * buildOrCaseSwitch( const WaitUntilStmt * stmt, string & statusName, vector<ClauseData *> & data );
    184         Stmt * genAllOr( const WaitUntilStmt * stmt );
     142    UniqueName namer_target = "__clause_target_"s;
     143    UniqueName namer_when = "__when_cond_"s;
     144    UniqueName namer_label = "__waituntil_label_"s;
     145
     146    string idxName = "__CFA_clause_idx_";
     147
     148    struct ClauseData {
     149        string nodeName;
     150        string targetName;
     151        string whenName;
     152        int index;
     153        string & statusName;
     154        ClauseData( int index, string & statusName ) : index(index), statusName(statusName) {}
     155    };
     156
     157    const StructDecl * selectNodeDecl = nullptr;
     158
     159    // This first set of routines are all used to do the complicated job of
     160    //    dealing with how to set predicate statuses with certain when_conds T/F
     161    //    so that the when_cond == F effectively makes that clause "disappear"
     162    void updateAmbiguousWhen( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool andBelow, bool orBelow );
     163    void paintWhenTree( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool & andBelow, bool & orBelow );
     164    bool paintWhenTree( WaitUntilStmt::ClauseNode * currNode );
     165    void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs, int & index, bool parentAmbig, bool parentAnd );
     166    void collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs );
     167    void updateWhenState( WaitUntilStmt::ClauseNode * currNode );
     168    void genSubtreeAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, bool status, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
     169    void genStatusAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData );
     170    CompoundStmt * getStatusAssignment( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData );
     171    Stmt * genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx );
     172
     173    // These routines are just code-gen helpers
     174    void addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName );
     175    void setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body );
     176    CompoundStmt * genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName );
     177    Expr * genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName );
     178    CompoundStmt * genStmtBlock( const WhenClause * clause, const ClauseData * data );
     179    Stmt * genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData );
     180    Stmt * genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData );
     181    void genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName );
     182    Stmt * recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName );
     183    Stmt * buildOrCaseSwitch( const WaitUntilStmt * stmt, string & statusName, vector<ClauseData *> & data );
     184    Stmt * genAllOr( const WaitUntilStmt * stmt );
    185185
    186186  public:
    187         void previsit( const StructDecl * decl );
     187    void previsit( const StructDecl * decl );
    188188        Stmt * postvisit( const WaitUntilStmt * stmt );
    189         GenerateWaitUntilCore( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
     189    GenerateWaitUntilCore( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
    190190};
    191191
    192192// Finds select_node decl
    193193void GenerateWaitUntilCore::previsit( const StructDecl * decl ) {
    194         if ( !decl->body ) {
     194    if ( !decl->body ) {
    195195                return;
    196196        } else if ( "select_node" == decl->name ) {
     
    201201
    202202void GenerateWaitUntilCore::updateAmbiguousWhen( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool andBelow, bool orBelow ) {
    203         // all children when-ambiguous
    204         if ( currNode->left->ambiguousWhen && currNode->right->ambiguousWhen )
    205                 // true iff an ancestor/descendant has a different operation
    206                 currNode->ambiguousWhen = (orAbove || orBelow) && (andBelow || andAbove);
    207         // ambiguousWhen is initially false so theres no need to set it here
     203    // all children when-ambiguous
     204    if ( currNode->left->ambiguousWhen && currNode->right->ambiguousWhen )
     205        // true iff an ancestor/descendant has a different operation
     206        currNode->ambiguousWhen = (orAbove || orBelow) && (andBelow || andAbove);
     207    // ambiguousWhen is initially false so theres no need to set it here
    208208}
    209209
     
    215215// - All of its descendent clauses are optional, i.e. they have a when_cond defined on the WhenClause
    216216void GenerateWaitUntilCore::paintWhenTree( WaitUntilStmt::ClauseNode * currNode, bool andAbove, bool orAbove, bool & andBelow, bool & orBelow ) {
    217         bool aBelow = false; // updated by child nodes
    218         bool oBelow = false; // updated by child nodes
    219         switch (currNode->op) {
    220                 case WaitUntilStmt::ClauseNode::AND:
    221                         paintWhenTree( currNode->left, true, orAbove, aBelow, oBelow );
    222                         paintWhenTree( currNode->right, true, orAbove, aBelow, oBelow );
    223 
    224                         // update currNode's when flag based on conditions listed in fn signature comment above
    225                         updateAmbiguousWhen(currNode, true, orAbove, aBelow, oBelow );
    226 
    227                         // set return flags to tell parents which decendant ops have been seen
    228                         andBelow = true;
    229                         orBelow = oBelow;
    230                         return;
    231                 case WaitUntilStmt::ClauseNode::OR:
    232                         paintWhenTree( currNode->left, andAbove, true, aBelow, oBelow );
    233                         paintWhenTree( currNode->right, andAbove, true, aBelow, oBelow );
    234 
    235                         // update currNode's when flag based on conditions listed in fn signature comment above
    236                         updateAmbiguousWhen(currNode, andAbove, true, aBelow, oBelow );
    237 
    238                         // set return flags to tell parents which decendant ops have been seen
    239                         andBelow = aBelow;
    240                         orBelow = true;
    241                         return;
    242                 case WaitUntilStmt::ClauseNode::LEAF:
    243                         if ( currNode->leaf->when_cond )
    244                                 currNode->ambiguousWhen = true;
    245                         return;
    246                 default:
    247                         assertf(false, "Unreachable waituntil clause node type. How did you get here???");
    248         }
     217    bool aBelow = false; // updated by child nodes
     218    bool oBelow = false; // updated by child nodes
     219    switch (currNode->op) {
     220        case WaitUntilStmt::ClauseNode::AND:
     221            paintWhenTree( currNode->left, true, orAbove, aBelow, oBelow );
     222            paintWhenTree( currNode->right, true, orAbove, aBelow, oBelow );
     223
     224            // update currNode's when flag based on conditions listed in fn signature comment above
     225            updateAmbiguousWhen(currNode, true, orAbove, aBelow, oBelow );
     226
     227            // set return flags to tell parents which decendant ops have been seen
     228            andBelow = true;
     229            orBelow = oBelow;
     230            return;
     231        case WaitUntilStmt::ClauseNode::OR:
     232            paintWhenTree( currNode->left, andAbove, true, aBelow, oBelow );
     233            paintWhenTree( currNode->right, andAbove, true, aBelow, oBelow );
     234
     235            // update currNode's when flag based on conditions listed in fn signature comment above
     236            updateAmbiguousWhen(currNode, andAbove, true, aBelow, oBelow );
     237
     238            // set return flags to tell parents which decendant ops have been seen
     239            andBelow = aBelow;
     240            orBelow = true;
     241            return;
     242        case WaitUntilStmt::ClauseNode::LEAF:
     243            if ( currNode->leaf->when_cond )
     244                currNode->ambiguousWhen = true;
     245            return;
     246        default:
     247            assertf(false, "Unreachable waituntil clause node type. How did you get here???");
     248    }
    249249}
    250250
     
    252252// returns true if entire tree is OR's (special case)
    253253bool GenerateWaitUntilCore::paintWhenTree( WaitUntilStmt::ClauseNode * currNode ) {
    254         bool aBelow = false, oBelow = false; // unused by initial call
    255         paintWhenTree( currNode, false, false, aBelow, oBelow );
    256         return !aBelow;
     254    bool aBelow = false, oBelow = false; // unused by initial call
     255    paintWhenTree( currNode, false, false, aBelow, oBelow );
     256    return !aBelow;
    257257}
    258258
    259259// Helper: returns Expr that represents arrName[index]
    260260Expr * genArrAccessExpr( const CodeLocation & loc, int index, string arrName ) {
    261         return new UntypedExpr ( loc,
    262                 new NameExpr( loc, "?[?]" ),
    263                 {
    264                         new NameExpr( loc, arrName ),
    265                         ConstantExpr::from_int( loc, index )
    266                 }
    267         );
     261    return new UntypedExpr ( loc,
     262        new NameExpr( loc, "?[?]" ),
     263        {
     264            new NameExpr( loc, arrName ),
     265            ConstantExpr::from_int( loc, index )
     266        }
     267    );
    268268}
    269269
     
    273273// - updates LEAF nodes to be when-ambiguous if their direct parent is when-ambiguous.
    274274void GenerateWaitUntilCore::collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs, int & index, bool parentAmbig, bool parentAnd ) {
    275         switch (currNode->op) {
    276                 case WaitUntilStmt::ClauseNode::AND:
    277                         collectWhens( currNode->left, ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
    278                         collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
    279                         return;
    280                 case WaitUntilStmt::ClauseNode::OR:
    281                         collectWhens( currNode->left,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
    282                         collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
    283                         return;
    284                 case WaitUntilStmt::ClauseNode::LEAF:
    285                         if ( parentAmbig ) {
    286                                 ambigIdxs.push_back(make_pair(index, currNode));
    287                         }
    288                         if ( parentAnd && currNode->leaf->when_cond ) {
    289                                 currNode->childOfAnd = true;
    290                                 andIdxs.push_back(index);
    291                         }
    292                         index++;
    293                         return;
    294                 default:
    295                         assertf(false, "Unreachable waituntil clause node type. How did you get here???");
    296         }
     275    switch (currNode->op) {
     276        case WaitUntilStmt::ClauseNode::AND:
     277            collectWhens( currNode->left, ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
     278            collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, true );
     279            return;
     280        case WaitUntilStmt::ClauseNode::OR:
     281            collectWhens( currNode->left,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
     282            collectWhens( currNode->right,  ambigIdxs, andIdxs, index, currNode->ambiguousWhen, false );
     283            return;
     284        case WaitUntilStmt::ClauseNode::LEAF:
     285            if ( parentAmbig ) {
     286                ambigIdxs.push_back(make_pair(index, currNode));
     287            }
     288            if ( parentAnd && currNode->leaf->when_cond ) {
     289                currNode->childOfAnd = true;
     290                andIdxs.push_back(index);
     291            }
     292            index++;
     293            return;
     294        default:
     295            assertf(false, "Unreachable waituntil clause node type. How did you get here???");
     296    }
    297297}
    298298
    299299// overloaded wrapper for collectWhens that sets initial values
    300300void GenerateWaitUntilCore::collectWhens( WaitUntilStmt::ClauseNode * currNode, vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigIdxs, vector<int> & andIdxs ) {
    301         int idx = 0;
    302         collectWhens( currNode, ambigIdxs, andIdxs, idx, false, false );
    303 }
    304 
    305 // recursively updates ClauseNode whenState on internal nodes so that next pass can see which
     301    int idx = 0;
     302    collectWhens( currNode, ambigIdxs, andIdxs, idx, false, false );
     303}
     304
     305// recursively updates ClauseNode whenState on internal nodes so that next pass can see which 
    306306//    subtrees are "turned off"
    307307// sets whenState = false iff both children have whenState == false.
     
    309309// since the ambiguous clauses were filtered in paintWhenTree we don't need to worry about that here
    310310void GenerateWaitUntilCore::updateWhenState( WaitUntilStmt::ClauseNode * currNode ) {
    311         if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) return;
    312         updateWhenState( currNode->left );
    313         updateWhenState( currNode->right );
    314         if ( !currNode->left->whenState && !currNode->right->whenState )
    315                 currNode->whenState = false;
    316         else
    317                 currNode->whenState = true;
     311    if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) return;
     312    updateWhenState( currNode->left );
     313    updateWhenState( currNode->right );
     314    if ( !currNode->left->whenState && !currNode->right->whenState )
     315        currNode->whenState = false;
     316    else
     317        currNode->whenState = true;
    318318}
    319319
     
    321321// assumes that this will only be called on subtrees that are entirely whenState == false
    322322void GenerateWaitUntilCore::genSubtreeAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, bool status, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData ) {
    323         if ( ( currNode->op == WaitUntilStmt::ClauseNode::AND && status )
    324                 || ( currNode->op == WaitUntilStmt::ClauseNode::OR && !status ) ) {
    325                 // need to recurse on both subtrees if && subtree needs to be true or || subtree needs to be false
    326                 genSubtreeAssign( stmt, currNode->left, status, idx, retStmt, clauseData );
    327                 genSubtreeAssign( stmt, currNode->right, status, idx, retStmt, clauseData );
    328         } else if ( ( currNode->op == WaitUntilStmt::ClauseNode::OR && status )
    329                 || ( currNode->op == WaitUntilStmt::ClauseNode::AND && !status ) ) {
    330                 // only one subtree needs to evaluate to status if && subtree needs to be true or || subtree needs to be false
    331                 CompoundStmt * leftStmt = new CompoundStmt( stmt->location );
    332                 CompoundStmt * rightStmt = new CompoundStmt( stmt->location );
    333 
    334                 // only one side needs to evaluate to status so we recurse on both subtrees
    335                 //    but only keep the statements from the subtree with minimal statements
    336                 genSubtreeAssign( stmt, currNode->left, status, idx, leftStmt, clauseData );
    337                 genSubtreeAssign( stmt, currNode->right, status, idx, rightStmt, clauseData );
    338 
    339                 // append minimal statements to retStmt
    340                 if ( leftStmt->kids.size() < rightStmt->kids.size() ) {
    341                         retStmt->kids.splice( retStmt->kids.end(), leftStmt->kids );
    342                 } else {
    343                         retStmt->kids.splice( retStmt->kids.end(), rightStmt->kids );
    344                 }
    345 
    346                 delete leftStmt;
    347                 delete rightStmt;
    348         } else if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) {
    349                 const CodeLocation & loc = stmt->location;
    350                 if ( status && !currNode->childOfAnd ) {
    351                         retStmt->push_back(
    352                                 new ExprStmt( loc,
    353                                     UntypedExpr::createAssign( loc,
    354                                         genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
    355                                         new NameExpr( loc, "__SELECT_RUN" )
    356                                     )
    357                                 )
    358                         );
    359                 } else if ( !status && currNode->childOfAnd ) {
    360                         retStmt->push_back(
    361                                 new ExprStmt( loc,
    362                                     UntypedExpr::createAssign( loc,
    363                                         genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
    364                                         new NameExpr( loc, "__SELECT_UNSAT" )
    365                                     )
    366                                 )
    367                         );
    368                 }
    369 
    370                 // No need to generate statements for the following cases since childOfAnd are always set to true
    371                 //    and !childOfAnd are always false
    372                 // - status && currNode->childOfAnd
    373                 // - !status && !currNode->childOfAnd
    374                 idx++;
    375         }
     323    if ( ( currNode->op == WaitUntilStmt::ClauseNode::AND && status )
     324        || ( currNode->op == WaitUntilStmt::ClauseNode::OR && !status ) ) {
     325        // need to recurse on both subtrees if && subtree needs to be true or || subtree needs to be false
     326        genSubtreeAssign( stmt, currNode->left, status, idx, retStmt, clauseData );
     327        genSubtreeAssign( stmt, currNode->right, status, idx, retStmt, clauseData );
     328    } else if ( ( currNode->op == WaitUntilStmt::ClauseNode::OR && status )
     329        || ( currNode->op == WaitUntilStmt::ClauseNode::AND && !status ) ) {
     330        // only one subtree needs to evaluate to status if && subtree needs to be true or || subtree needs to be false
     331        CompoundStmt * leftStmt = new CompoundStmt( stmt->location );
     332        CompoundStmt * rightStmt = new CompoundStmt( stmt->location );
     333
     334        // only one side needs to evaluate to status so we recurse on both subtrees
     335        //    but only keep the statements from the subtree with minimal statements
     336        genSubtreeAssign( stmt, currNode->left, status, idx, leftStmt, clauseData );
     337        genSubtreeAssign( stmt, currNode->right, status, idx, rightStmt, clauseData );
     338       
     339        // append minimal statements to retStmt
     340        if ( leftStmt->kids.size() < rightStmt->kids.size() ) {
     341            retStmt->kids.splice( retStmt->kids.end(), leftStmt->kids );
     342        } else {
     343            retStmt->kids.splice( retStmt->kids.end(), rightStmt->kids );
     344        }
     345       
     346        delete leftStmt;
     347        delete rightStmt;
     348    } else if ( currNode->op == WaitUntilStmt::ClauseNode::LEAF ) {
     349        const CodeLocation & loc = stmt->location;
     350        if ( status && !currNode->childOfAnd ) {
     351            retStmt->push_back(
     352                new ExprStmt( loc,
     353                    UntypedExpr::createAssign( loc,
     354                        genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
     355                        new NameExpr( loc, "__SELECT_RUN" )
     356                    )
     357                )
     358            );
     359        } else if ( !status && currNode->childOfAnd ) {
     360            retStmt->push_back(
     361                new ExprStmt( loc,
     362                    UntypedExpr::createAssign( loc,
     363                        genArrAccessExpr( loc, idx, clauseData.at(idx)->statusName ),
     364                        new NameExpr( loc, "__SELECT_UNSAT" )
     365                    )
     366                )
     367            );
     368        }
     369
     370        // No need to generate statements for the following cases since childOfAnd are always set to true
     371        //    and !childOfAnd are always false
     372        // - status && currNode->childOfAnd
     373        // - !status && !currNode->childOfAnd
     374        idx++;
     375    }
    376376}
    377377
    378378void GenerateWaitUntilCore::genStatusAssign( const WaitUntilStmt * stmt, WaitUntilStmt::ClauseNode * currNode, int & idx, CompoundStmt * retStmt, vector<ClauseData *> & clauseData ) {
    379         switch (currNode->op) {
    380                 case WaitUntilStmt::ClauseNode::AND:
    381                         // check which subtrees have all whenState == false (disabled)
    382                         if (!currNode->left->whenState && !currNode->right->whenState) {
    383                                 // this case can only occur when whole tree is disabled since otherwise
    384                                 //    genStatusAssign( ... ) isn't called on nodes with whenState == false
    385                                 assert( !currNode->whenState ); // paranoidWWW
    386                                 // whole tree disabled so pass true so that select is SAT vacuously
    387                                 genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
    388                         } else if ( !currNode->left->whenState ) {
    389                                 // pass true since x && true === x
    390                                 genSubtreeAssign( stmt, currNode->left, true, idx, retStmt, clauseData );
    391                                 genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
    392                         } else if ( !currNode->right->whenState ) {
    393                                 genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
    394                                 genSubtreeAssign( stmt, currNode->right, true, idx, retStmt, clauseData );
    395                         } else {
    396                                 // if no children with whenState == false recurse normally via break
    397                                 break;
    398                         }
    399                         return;
    400                 case WaitUntilStmt::ClauseNode::OR:
    401                         if (!currNode->left->whenState && !currNode->right->whenState) {
    402                                 assert( !currNode->whenState ); // paranoid
    403                                 genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
    404                         } else if ( !currNode->left->whenState ) {
    405                                 // pass false since x || false === x
    406                                 genSubtreeAssign( stmt, currNode->left, false, idx, retStmt, clauseData );
    407                                 genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
    408                         } else if ( !currNode->right->whenState ) {
    409                                 genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
    410                                 genSubtreeAssign( stmt, currNode->right, false, idx, retStmt, clauseData );
    411                         } else {
    412                                 break;
    413                         }
    414                         return;
    415                 case WaitUntilStmt::ClauseNode::LEAF:
    416                         idx++;
    417                         return;
    418                 default:
    419                         assertf(false, "Unreachable waituntil clause node type. How did you get here???");
    420         }
    421         genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
    422         genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
     379    switch (currNode->op) {
     380        case WaitUntilStmt::ClauseNode::AND:
     381            // check which subtrees have all whenState == false (disabled)
     382            if (!currNode->left->whenState && !currNode->right->whenState) {
     383                // this case can only occur when whole tree is disabled since otherwise
     384                //    genStatusAssign( ... ) isn't called on nodes with whenState == false
     385                assert( !currNode->whenState ); // paranoidWWW
     386                // whole tree disabled so pass true so that select is SAT vacuously
     387                genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
     388            } else if ( !currNode->left->whenState ) {
     389                // pass true since x && true === x
     390                genSubtreeAssign( stmt, currNode->left, true, idx, retStmt, clauseData );
     391                genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
     392            } else if ( !currNode->right->whenState ) {
     393                genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
     394                genSubtreeAssign( stmt, currNode->right, true, idx, retStmt, clauseData );
     395            } else {
     396                // if no children with whenState == false recurse normally via break
     397                break;
     398            }
     399            return;
     400        case WaitUntilStmt::ClauseNode::OR:
     401            if (!currNode->left->whenState && !currNode->right->whenState) {
     402                assert( !currNode->whenState ); // paranoid
     403                genSubtreeAssign( stmt, currNode, true, idx, retStmt, clauseData );
     404            } else if ( !currNode->left->whenState ) {
     405                // pass false since x || false === x
     406                genSubtreeAssign( stmt, currNode->left, false, idx, retStmt, clauseData );
     407                genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
     408            } else if ( !currNode->right->whenState ) {
     409                genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
     410                genSubtreeAssign( stmt, currNode->right, false, idx, retStmt, clauseData );
     411            } else {
     412                break;
     413            }
     414            return;
     415        case WaitUntilStmt::ClauseNode::LEAF:
     416            idx++;
     417            return;
     418        default:
     419            assertf(false, "Unreachable waituntil clause node type. How did you get here???");
     420    }
     421    genStatusAssign( stmt, currNode->left, idx, retStmt, clauseData );
     422    genStatusAssign( stmt, currNode->right, idx, retStmt, clauseData );
    423423}
    424424
    425425// generates a minimal set of assignments for status arr based on which whens are toggled on/off
    426426CompoundStmt * GenerateWaitUntilCore::getStatusAssignment( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData ) {
    427         updateWhenState( stmt->predicateTree );
    428         CompoundStmt * retval = new CompoundStmt( stmt->location );
    429         int idx = 0;
    430         genStatusAssign( stmt, stmt->predicateTree, idx, retval, clauseData );
    431         return retval;
     427    updateWhenState( stmt->predicateTree );
     428    CompoundStmt * retval = new CompoundStmt( stmt->location );
     429    int idx = 0;
     430    genStatusAssign( stmt, stmt->predicateTree, idx, retval, clauseData );
     431    return retval;
    432432}
    433433
    434434// generates nested if/elses for all possible assignments of ambiguous when_conds
    435435// exponential size of code gen but linear runtime O(n), where n is number of ambiguous whens()
    436 Stmt * GenerateWaitUntilCore::genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData,
    437         vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx ) {
    438         // I hate C++ sometimes, using vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type for size() comparison seems silly.
    439         //    Why is size_type parameterized on the type stored in the vector?????
    440 
    441         const CodeLocation & loc = stmt->location;
    442         int clauseIdx = ambigClauses.at(ambigIdx).first;
    443         WaitUntilStmt::ClauseNode * currNode = ambigClauses.at(ambigIdx).second;
    444         Stmt * thenStmt;
    445         Stmt * elseStmt;
    446 
    447         if ( ambigIdx == ambigClauses.size() - 1 ) { // base case
    448                 currNode->whenState = true;
    449                 thenStmt = getStatusAssignment( stmt, clauseData );
    450                 currNode->whenState = false;
    451                 elseStmt = getStatusAssignment( stmt, clauseData );
    452         } else {
    453                 // recurse both with when enabled and disabled to generate all possible cases
    454                 currNode->whenState = true;
    455                 thenStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
    456                 currNode->whenState = false;
    457                 elseStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
    458         }
    459 
    460         // insert first recursion result in if ( __when_cond_ ) { ... }
    461         // insert second recursion result in else { ... }
    462         return new CompoundStmt ( loc,
    463                 {
    464                         new IfStmt( loc,
    465                                 new NameExpr( loc, clauseData.at(clauseIdx)->whenName ),
    466                                 thenStmt,
    467                                 elseStmt
    468                         )
    469                 }
    470         );
     436Stmt * GenerateWaitUntilCore::genWhenStateConditions( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, 
     437    vector<pair<int, WaitUntilStmt::ClauseNode *>> & ambigClauses, vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type ambigIdx ) {
     438    // I hate C++ sometimes, using vector<pair<int, WaitUntilStmt::ClauseNode *>>::size_type for size() comparison seems silly.
     439    //    Why is size_type parameterized on the type stored in the vector?????
     440
     441    const CodeLocation & loc = stmt->location;
     442    int clauseIdx = ambigClauses.at(ambigIdx).first;
     443    WaitUntilStmt::ClauseNode * currNode = ambigClauses.at(ambigIdx).second;
     444    Stmt * thenStmt;
     445    Stmt * elseStmt;
     446   
     447    if ( ambigIdx == ambigClauses.size() - 1 ) { // base case
     448        currNode->whenState = true;
     449        thenStmt = getStatusAssignment( stmt, clauseData );
     450        currNode->whenState = false;
     451        elseStmt = getStatusAssignment( stmt, clauseData );
     452    } else {
     453        // recurse both with when enabled and disabled to generate all possible cases
     454        currNode->whenState = true;
     455        thenStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
     456        currNode->whenState = false;
     457        elseStmt = genWhenStateConditions( stmt, clauseData, ambigClauses, ambigIdx + 1 );
     458    }
     459
     460    // insert first recursion result in if ( __when_cond_ ) { ... }
     461    // insert second recursion result in else { ... }
     462    return new CompoundStmt ( loc,
     463        {
     464            new IfStmt( loc,
     465                new NameExpr( loc, clauseData.at(clauseIdx)->whenName ),
     466                thenStmt,
     467                elseStmt
     468            )
     469        }
     470    );
    471471}
    472472
     
    478478// mutates index to be index + 1
    479479Expr * genSatExpr( const CodeLocation & loc, int & index ) {
    480         return genArrAccessExpr( loc, index++, "clause_statuses" );
     480    return genArrAccessExpr( loc, index++, "clause_statuses" );
    481481}
    482482
    483483// return Expr that represents has_run(clause_statuses[index])
    484484Expr * genRunExpr( const CodeLocation & loc, int & index ) {
    485         return new UntypedExpr ( loc,
    486                 new NameExpr( loc, "__CFA_has_clause_run" ),
    487                 { genSatExpr( loc, index ) }
    488         );
     485    return new UntypedExpr ( loc,
     486        new NameExpr( loc, "__CFA_has_clause_run" ),
     487        { genSatExpr( loc, index ) }
     488    );
    489489}
    490490
     
    492492// the predicate expr used inside the predicate functions
    493493Expr * genPredExpr( const CodeLocation & loc, WaitUntilStmt::ClauseNode * currNode, int & idx, GenLeafExpr genLeaf ) {
    494         Expr * leftExpr, * rightExpr;
    495         switch (currNode->op) {
    496                 case WaitUntilStmt::ClauseNode::AND:
    497                         leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
    498                         rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
    499                         return new LogicalExpr( loc,
    500                                 new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
    501                                 new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
    502                                 LogicalFlag::AndExpr
    503                         );
    504                         break;
    505                 case WaitUntilStmt::ClauseNode::OR:
    506                         leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
    507                         rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
    508                         return new LogicalExpr( loc,
    509                                 new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
    510                                 new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
    511                                 LogicalFlag::OrExpr );
    512                         break;
    513                 case WaitUntilStmt::ClauseNode::LEAF:
    514                         return genLeaf( loc, idx );
    515                         break;
    516                 default:
    517                         assertf(false, "Unreachable waituntil clause node type. How did you get here???");\
    518                         return nullptr;
    519                         break;
    520         }
    521         return nullptr;
     494    Expr * leftExpr, * rightExpr;
     495    switch (currNode->op) {
     496        case WaitUntilStmt::ClauseNode::AND:
     497            leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
     498            rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
     499            return new LogicalExpr( loc,
     500                new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
     501                new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
     502                LogicalFlag::AndExpr
     503            );
     504            break;
     505        case WaitUntilStmt::ClauseNode::OR:
     506            leftExpr = genPredExpr( loc, currNode->left, idx, genLeaf );
     507            rightExpr = genPredExpr( loc, currNode->right, idx, genLeaf );
     508            return new LogicalExpr( loc,
     509                new CastExpr( loc, leftExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
     510                new CastExpr( loc, rightExpr, new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast ),
     511                LogicalFlag::OrExpr );
     512            break;
     513        case WaitUntilStmt::ClauseNode::LEAF:
     514            return genLeaf( loc, idx );
     515            break;
     516        default:
     517            assertf(false, "Unreachable waituntil clause node type. How did you get here???");\
     518            return nullptr;
     519            break;
     520    }
     521    return nullptr;
    522522}
    523523
     
    526526/* Ex:
    527527{
    528         waituntil( A ){ doA(); }
    529         or waituntil( B ){ doB(); }
    530         and waituntil( C ) { doC(); }
     528    waituntil( A ){ doA(); }
     529    or waituntil( B ){ doB(); }
     530    and waituntil( C ) { doC(); }
    531531}
    532532generates =>
    533533static inline bool is_full_sat_1( int * clause_statuses ) {
    534         return clause_statuses[0]
    535                 || clause_statuses[1]
    536                 && clause_statuses[2];
     534    return clause_statuses[0]
     535        || clause_statuses[1]
     536        && clause_statuses[2];
    537537}
    538538
    539539static inline bool is_done_sat_1( int * clause_statuses ) {
    540         return has_run(clause_statuses[0])
    541                 || has_run(clause_statuses[1])
    542                 && has_run(clause_statuses[2]);
     540    return has_run(clause_statuses[0])
     541        || has_run(clause_statuses[1])
     542        && has_run(clause_statuses[2]);
    543543}
    544544*/
     
    546546// predName and genLeaf determine if this generates an is_done or an is_full predicate
    547547FunctionDecl * buildPredicate( const WaitUntilStmt * stmt, GenLeafExpr genLeaf, string & predName ) {
    548         int arrIdx = 0;
    549         const CodeLocation & loc = stmt->location;
    550         CompoundStmt * body = new CompoundStmt( loc );
    551         body->push_back( new ReturnStmt( loc, genPredExpr( loc,  stmt->predicateTree, arrIdx, genLeaf ) ) );
    552 
    553         return new FunctionDecl( loc,
    554                 predName,
    555                 {
    556                         new ObjectDecl( loc,
    557                                 "clause_statuses",
    558                                 new PointerType( new BasicType( BasicKind::LongUnsignedInt ) )
    559                         )
    560                 },
    561                 {
    562                         new ObjectDecl( loc,
    563                                 "sat_ret",
    564                                 new BasicType( BasicKind::Bool )
    565                         )
    566                 },
    567                 body,               // body
    568                 { Storage::Static },    // storage
    569                 Linkage::Cforall,       // linkage
    570                 {},                     // attributes
    571                 { Function::Inline }
    572         );
     548    int arrIdx = 0;
     549    const CodeLocation & loc = stmt->location;
     550    CompoundStmt * body = new CompoundStmt( loc );
     551    body->push_back( new ReturnStmt( loc, genPredExpr( loc,  stmt->predicateTree, arrIdx, genLeaf ) ) );
     552
     553    return new FunctionDecl( loc,
     554        predName,
     555        {
     556            new ObjectDecl( loc,
     557                "clause_statuses",
     558                new PointerType( new BasicType( BasicKind::LongUnsignedInt ) )
     559            )
     560        },
     561        {
     562            new ObjectDecl( loc,
     563                "sat_ret",
     564                new BasicType( BasicKind::Bool )
     565            )
     566        },
     567        body,               // body
     568        { Storage::Static },    // storage
     569        Linkage::Cforall,       // linkage
     570        {},                     // attributes
     571        { Function::Inline }
     572    );
    573573}
    574574
    575575// Creates is_done and is_full predicates
    576576void GenerateWaitUntilCore::addPredicates( const WaitUntilStmt * stmt, string & satName, string & runName ) {
    577         if ( !stmt->else_stmt || stmt->else_cond ) // don't need SAT predicate when else variation with no else_cond
    578                 satFns.push_back( Concurrency::buildPredicate( stmt, genSatExpr, satName ) );
    579         satFns.push_back( Concurrency::buildPredicate( stmt, genRunExpr, runName ) );
     577    if ( !stmt->else_stmt || stmt->else_cond ) // don't need SAT predicate when else variation with no else_cond
     578        satFns.push_back( Concurrency::buildPredicate( stmt, genSatExpr, satName ) );
     579    satFns.push_back( Concurrency::buildPredicate( stmt, genRunExpr, runName ) );
    580580}
    581581
     
    585585//      register_select(A, clause1);
    586586// }
    587 void GenerateWaitUntilCore::setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body ) {
    588         CompoundStmt * currBody = body;
    589         const CodeLocation & loc = clause->location;
    590 
    591         // If we have a when_cond make the initialization conditional
    592         if ( clause->when_cond )
    593                 currBody = new CompoundStmt( loc );
    594 
    595         // Generates: setup_clause( clause1, &clause_statuses[0], &park_counter );
    596         currBody->push_back( new ExprStmt( loc,
    597                 new UntypedExpr ( loc,
    598                         new NameExpr( loc, "setup_clause" ),
    599                         {
    600                                 new NameExpr( loc, data->nodeName ),
    601                                 new AddressExpr( loc, genArrAccessExpr( loc, data->index, data->statusName ) ),
    602                                 new AddressExpr( loc, new NameExpr( loc, pCountName ) )
    603                         }
    604                 )
    605         ));
    606 
    607         // Generates: register_select(A, clause1);
    608         currBody->push_back( new ExprStmt( loc, genSelectTraitCall( clause, data, "register_select" ) ) );
    609 
    610         // generates: if ( when_cond ) { ... currBody ... }
    611         if ( clause->when_cond )
    612                 body->push_back(
    613                         new IfStmt( loc,
    614                                 new NameExpr( loc, data->whenName ),
    615                                 currBody
    616                         )
    617                 );
     587void GenerateWaitUntilCore::setUpClause( const WhenClause * clause, ClauseData * data, string & pCountName, CompoundStmt * body ) {   
     588    CompoundStmt * currBody = body;
     589    const CodeLocation & loc = clause->location;
     590
     591    // If we have a when_cond make the initialization conditional
     592    if ( clause->when_cond )
     593        currBody = new CompoundStmt( loc );
     594
     595    // Generates: setup_clause( clause1, &clause_statuses[0], &park_counter );
     596    currBody->push_back( new ExprStmt( loc,
     597        new UntypedExpr ( loc,
     598            new NameExpr( loc, "setup_clause" ),
     599            {
     600                new NameExpr( loc, data->nodeName ),
     601                new AddressExpr( loc, genArrAccessExpr( loc, data->index, data->statusName ) ),
     602                new AddressExpr( loc, new NameExpr( loc, pCountName ) )
     603            }
     604        )
     605    ));
     606
     607    // Generates: register_select(A, clause1);
     608    currBody->push_back( new ExprStmt( loc, genSelectTraitCall( clause, data, "register_select" ) ) );
     609
     610    // generates: if ( when_cond ) { ... currBody ... }
     611    if ( clause->when_cond )
     612        body->push_back(
     613            new IfStmt( loc,
     614                new NameExpr( loc, data->whenName ),
     615                currBody
     616            )
     617        );
    618618}
    619619
    620620// Used to generate a call to one of the select trait routines
    621621Expr * GenerateWaitUntilCore::genSelectTraitCall( const WhenClause * clause, const ClauseData * data, string fnName ) {
    622         const CodeLocation & loc = clause->location;
    623         return new UntypedExpr ( loc,
    624                 new NameExpr( loc, fnName ),
    625                 {
    626                         new NameExpr( loc, data->targetName ),
    627                         new NameExpr( loc, data->nodeName )
    628                 }
    629         );
     622    const CodeLocation & loc = clause->location;
     623    return new UntypedExpr ( loc,
     624        new NameExpr( loc, fnName ),
     625        {
     626            new NameExpr( loc, data->targetName ),
     627            new NameExpr( loc, data->nodeName )
     628        }
     629    );
    630630}
    631631
    632632// Generates:
    633 /* on_selected( target_1, node_1 ); ... corresponding body of target_1 ...
     633/* on_selected( target_1, node_1 ); ... corresponding body of target_1 ... 
    634634*/
    635635CompoundStmt * GenerateWaitUntilCore::genStmtBlock( const WhenClause * clause, const ClauseData * data ) {
    636         const CodeLocation & cLoc = clause->location;
    637         return new CompoundStmt( cLoc,
    638                 {
    639                         new IfStmt( cLoc,
    640                                 genSelectTraitCall( clause, data, "on_selected" ),
    641                                 ast::deepCopy( clause->stmt )
    642                         )
    643                 }
    644         );
     636    const CodeLocation & cLoc = clause->location;
     637    return new CompoundStmt( cLoc,
     638        {
     639            new IfStmt( cLoc,
     640                genSelectTraitCall( clause, data, "on_selected" ),
     641                ast::deepCopy( clause->stmt )
     642            )
     643        }
     644    );
    645645}
    646646
    647647// this routine generates and returns the following
    648648/*for ( int i = 0; i < numClauses; i++ ) {
    649         if ( predName(clause_statuses) ) break;
    650         if (clause_statuses[i] == __SELECT_SAT) {
    651                 switch (i) {
    652                         case 0:
    653                                 try {
    654                                     on_selected( target1, clause1 );
    655                                     dotarget1stmt();
    656                                 }
    657                                 finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
    658                                 break;
    659                         ...
    660                         case N:
    661                                 ...
    662                                 break;
    663                 }
    664         }
     649    if ( predName(clause_statuses) ) break;
     650    if (clause_statuses[i] == __SELECT_SAT) {
     651        switch (i) {
     652            case 0:
     653                try {
     654                    on_selected( target1, clause1 );
     655                    dotarget1stmt();
     656                }
     657                finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
     658                break;
     659            ...
     660            case N:
     661                ...
     662                break;
     663        }
     664    }
    665665}*/
    666666CompoundStmt * GenerateWaitUntilCore::genStatusCheckFor( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, string & predName ) {
    667         CompoundStmt * ifBody = new CompoundStmt( stmt->location );
    668         const CodeLocation & loc = stmt->location;
    669 
    670         string switchLabel = namer_label.newName();
    671 
    672         /* generates:
    673         switch (i) {
    674                 case 0:
    675                         try {
    676                                 on_selected( target1, clause1 );
    677                                 dotarget1stmt();
    678                         }
    679                         finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
    680                         break;
    681                         ...
    682                 case N:
    683                         ...
    684                         break;
    685         }*/
    686         std::vector<ptr<CaseClause>> switchCases;
    687         int idx = 0;
    688         for ( const auto & clause: stmt->clauses ) {
    689                 const CodeLocation & cLoc = clause->location;
    690                 switchCases.push_back(
    691                         new CaseClause( cLoc,
    692                                 ConstantExpr::from_int( cLoc, idx ),
    693                                 {
    694                                     new CompoundStmt( cLoc,
    695                                         {
    696                                             new ast::TryStmt( cLoc,
    697                                                 genStmtBlock( clause, clauseData.at(idx) ),
    698                                                 {},
    699                                                 new ast::FinallyClause( cLoc,
    700                                                     new CompoundStmt( cLoc,
    701                                                         {
    702                                                             new ExprStmt( loc,
    703                                                                 new UntypedExpr ( loc,
    704                                                                     new NameExpr( loc, "?=?" ),
    705                                                                     {
    706                                                                         new UntypedExpr ( loc,
    707                                                                             new NameExpr( loc, "?[?]" ),
    708                                                                             {
    709                                                                                 new NameExpr( loc, clauseData.at(0)->statusName ),
    710                                                                                 new NameExpr( loc, idxName )
    711                                                                             }
    712                                                                         ),
    713                                                                         new NameExpr( loc, "__SELECT_RUN" )
    714                                                                     }
    715                                                                 )
    716                                                             ),
    717                                                             new ExprStmt( loc, genSelectTraitCall( clause, clauseData.at(idx), "unregister_select" ) )
    718                                                         }
    719                                                     )
    720                                                 )
    721                                             ),
    722                                             new BranchStmt( cLoc, BranchStmt::Kind::Break, Label( cLoc, switchLabel ) )
    723                                         }
    724                                     )
    725                                 }
    726                         )
    727                 );
    728                 idx++;
    729         }
    730 
    731         ifBody->push_back(
    732                 new SwitchStmt( loc,
    733                         new NameExpr( loc, idxName ),
    734                         std::move( switchCases ),
    735                         { Label( loc, switchLabel ) }
    736                 )
    737         );
    738 
    739         // gens:
    740         // if (clause_statuses[i] == __SELECT_SAT) {
    741         //      ... ifBody  ...
    742         // }
    743         IfStmt * ifSwitch = new IfStmt( loc,
    744                 new UntypedExpr ( loc,
    745                         new NameExpr( loc, "?==?" ),
    746                         {
    747                                 new UntypedExpr ( loc,
    748                                     new NameExpr( loc, "?[?]" ),
    749                                     {
    750                                         new NameExpr( loc, clauseData.at(0)->statusName ),
    751                                         new NameExpr( loc, idxName )
    752                                     }
    753                                 ),
    754                                 new NameExpr( loc, "__SELECT_SAT" )
    755                         }
    756                 ),      // condition
    757                 ifBody  // body
    758         );
    759 
    760         string forLabel = namer_label.newName();
    761 
    762         // we hoist init here so that this pass can happen after hoistdecls pass
    763         return new CompoundStmt( loc,
    764                 {
    765                         new DeclStmt( loc,
    766                                 new ObjectDecl( loc,
    767                                     idxName,
    768                                     new BasicType( BasicKind::SignedInt ),
    769                                     new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
    770                                 )
    771                         ),
    772                         new ForStmt( loc,
    773                                 {},  // inits
    774                                 new UntypedExpr ( loc,
    775                                     new NameExpr( loc, "?<?" ),
    776                                     {
    777                                         new NameExpr( loc, idxName ),
    778                                         ConstantExpr::from_int( loc, stmt->clauses.size() )
    779                                     }
    780                                 ),  // cond
    781                                 new UntypedExpr ( loc,
    782                                     new NameExpr( loc, "?++" ),
    783                                     { new NameExpr( loc, idxName ) }
    784                                 ),  // inc
    785                                 new CompoundStmt( loc,
    786                                     {
    787                                         new IfStmt( loc,
    788                                             new UntypedExpr ( loc,
    789                                                 new NameExpr( loc, predName ),
    790                                                 { new NameExpr( loc, clauseData.at(0)->statusName ) }
    791                                             ),
    792                                             new BranchStmt( loc, BranchStmt::Kind::Break, Label( loc, forLabel ) )
    793                                         ),
    794                                         ifSwitch
    795                                     }
    796                                 ),   // body
    797                                 { Label( loc, forLabel ) }
    798                         )
    799                 }
    800         );
     667    CompoundStmt * ifBody = new CompoundStmt( stmt->location );
     668    const CodeLocation & loc = stmt->location;
     669
     670    string switchLabel = namer_label.newName();
     671
     672    /* generates:
     673    switch (i) {
     674        case 0:
     675            try {
     676                on_selected( target1, clause1 );
     677                dotarget1stmt();
     678            }
     679            finally { clause_statuses[i] = __SELECT_RUN; unregister_select(target1, clause1); }
     680            break;
     681            ...
     682        case N:
     683            ...
     684            break;
     685    }*/
     686    std::vector<ptr<CaseClause>> switchCases;
     687    int idx = 0;
     688    for ( const auto & clause: stmt->clauses ) {
     689        const CodeLocation & cLoc = clause->location;
     690        switchCases.push_back(
     691            new CaseClause( cLoc,
     692                ConstantExpr::from_int( cLoc, idx ),
     693                {
     694                    new CompoundStmt( cLoc,
     695                        {
     696                            new ast::TryStmt( cLoc,
     697                                genStmtBlock( clause, clauseData.at(idx) ),
     698                                {},
     699                                new ast::FinallyClause( cLoc,
     700                                    new CompoundStmt( cLoc,
     701                                        {
     702                                            new ExprStmt( loc,
     703                                                new UntypedExpr ( loc,
     704                                                    new NameExpr( loc, "?=?" ),
     705                                                    {
     706                                                        new UntypedExpr ( loc,
     707                                                            new NameExpr( loc, "?[?]" ),
     708                                                            {
     709                                                                new NameExpr( loc, clauseData.at(0)->statusName ),
     710                                                                new NameExpr( loc, idxName )
     711                                                            }
     712                                                        ),
     713                                                        new NameExpr( loc, "__SELECT_RUN" )
     714                                                    }
     715                                                )
     716                                            ),
     717                                            new ExprStmt( loc, genSelectTraitCall( clause, clauseData.at(idx), "unregister_select" ) )
     718                                        }
     719                                    )
     720                                )
     721                            ),
     722                            new BranchStmt( cLoc, BranchStmt::Kind::Break, Label( cLoc, switchLabel ) )
     723                        }
     724                    )
     725                }
     726            )
     727        );
     728        idx++;
     729    }
     730
     731    ifBody->push_back(
     732        new SwitchStmt( loc,
     733            new NameExpr( loc, idxName ),
     734            std::move( switchCases ),
     735            { Label( loc, switchLabel ) }
     736        )
     737    );
     738
     739    // gens:
     740    // if (clause_statuses[i] == __SELECT_SAT) {
     741    //      ... ifBody  ...
     742    // }
     743    IfStmt * ifSwitch = new IfStmt( loc,
     744        new UntypedExpr ( loc,
     745            new NameExpr( loc, "?==?" ),
     746            {
     747                new UntypedExpr ( loc,
     748                    new NameExpr( loc, "?[?]" ),
     749                    {
     750                        new NameExpr( loc, clauseData.at(0)->statusName ),
     751                        new NameExpr( loc, idxName )
     752                    }
     753                ),
     754                new NameExpr( loc, "__SELECT_SAT" )
     755            }
     756        ),      // condition
     757        ifBody  // body
     758    );
     759
     760    string forLabel = namer_label.newName();
     761
     762    // we hoist init here so that this pass can happen after hoistdecls pass
     763    return new CompoundStmt( loc,
     764        {
     765            new DeclStmt( loc,
     766                new ObjectDecl( loc,
     767                    idxName,
     768                    new BasicType( BasicKind::SignedInt ),
     769                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     770                )
     771            ),
     772            new ForStmt( loc,
     773                {},  // inits
     774                new UntypedExpr ( loc,
     775                    new NameExpr( loc, "?<?" ),
     776                    {
     777                        new NameExpr( loc, idxName ),
     778                        ConstantExpr::from_int( loc, stmt->clauses.size() )
     779                    }
     780                ),  // cond
     781                new UntypedExpr ( loc,
     782                    new NameExpr( loc, "?++" ),
     783                    { new NameExpr( loc, idxName ) }
     784                ),  // inc
     785                new CompoundStmt( loc,
     786                    {
     787                        new IfStmt( loc,
     788                            new UntypedExpr ( loc,
     789                                new NameExpr( loc, predName ),
     790                                { new NameExpr( loc, clauseData.at(0)->statusName ) }
     791                            ),
     792                            new BranchStmt( loc, BranchStmt::Kind::Break, Label( loc, forLabel ) )
     793                        ),
     794                        ifSwitch
     795                    }
     796                ),   // body
     797                { Label( loc, forLabel ) }
     798            )
     799        }
     800    );
    801801}
    802802
    803803// Generates: !is_full_sat_n() / !is_run_sat_n()
    804804Expr * genNotSatExpr( const WaitUntilStmt * stmt, string & satName, string & arrName ) {
    805         const CodeLocation & loc = stmt->location;
    806         return new UntypedExpr ( loc,
    807                 new NameExpr( loc, "!?" ),
    808                 {
    809                         new UntypedExpr ( loc,
    810                                 new NameExpr( loc, satName ),
    811                                 { new NameExpr( loc, arrName ) }
    812                         )
    813                 }
    814         );
     805    const CodeLocation & loc = stmt->location;
     806    return new UntypedExpr ( loc,
     807        new NameExpr( loc, "!?" ),
     808        {
     809            new UntypedExpr ( loc,
     810                new NameExpr( loc, satName ),
     811                { new NameExpr( loc, arrName ) }
     812            )
     813        }
     814    );
    815815}
    816816
     
    819819// If not enough have run to satisfy predicate after one pass then the else is run
    820820Stmt * GenerateWaitUntilCore::genElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, vector<ClauseData *> & clauseData ) {
    821         return new CompoundStmt( stmt->else_stmt->location,
    822                 {
    823                         genStatusCheckFor( stmt, clauseData, runName ),
    824                         new IfStmt( stmt->else_stmt->location,
    825                                 genNotSatExpr( stmt, runName, arrName ),
    826                                 ast::deepCopy( stmt->else_stmt )
    827                         )
    828                 }
    829         );
     821    return new CompoundStmt( stmt->else_stmt->location,
     822        {
     823            genStatusCheckFor( stmt, clauseData, runName ),
     824            new IfStmt( stmt->else_stmt->location,
     825                genNotSatExpr( stmt, runName, arrName ),
     826                ast::deepCopy( stmt->else_stmt )
     827            )
     828        }
     829    );
    830830}
    831831
    832832Stmt * GenerateWaitUntilCore::genNoElseClauseBranch( const WaitUntilStmt * stmt, string & runName, string & arrName, string & pCountName, vector<ClauseData *> & clauseData ) {
    833         CompoundStmt * whileBody = new CompoundStmt( stmt->location );
    834         const CodeLocation & loc = stmt->location;
    835 
    836         // generates: __CFA_maybe_park( &park_counter );
    837         whileBody->push_back(
    838                 new ExprStmt( loc,
    839                         new UntypedExpr ( loc,
    840                                 new NameExpr( loc, "__CFA_maybe_park" ),
    841                                 { new AddressExpr( loc, new NameExpr( loc, pCountName ) ) }
    842                         )
    843                 )
    844         );
    845 
    846         whileBody->push_back( genStatusCheckFor( stmt, clauseData, runName ) );
    847 
    848         return new CompoundStmt( loc,
    849                 {
    850                         new WhileDoStmt( loc,
    851                                 genNotSatExpr( stmt, runName, arrName ),
    852                                 whileBody,  // body
    853                                 {}          // no inits
    854                         )
    855                 }
    856         );
     833    CompoundStmt * whileBody = new CompoundStmt( stmt->location );
     834    const CodeLocation & loc = stmt->location;
     835
     836    // generates: __CFA_maybe_park( &park_counter );
     837    whileBody->push_back(
     838        new ExprStmt( loc,
     839            new UntypedExpr ( loc,
     840                new NameExpr( loc, "__CFA_maybe_park" ),
     841                { new AddressExpr( loc, new NameExpr( loc, pCountName ) ) }
     842            )
     843        )
     844    );
     845
     846    whileBody->push_back( genStatusCheckFor( stmt, clauseData, runName ) );
     847
     848    return new CompoundStmt( loc,
     849        {
     850            new WhileDoStmt( loc,
     851                genNotSatExpr( stmt, runName, arrName ),
     852                whileBody,  // body
     853                {}          // no inits
     854            )
     855        }
     856    );
    857857}
    858858
     
    862862// select_node clause1;
    863863void GenerateWaitUntilCore::genClauseInits( const WaitUntilStmt * stmt, vector<ClauseData *> & clauseData, CompoundStmt * body, string & statusName, string & elseWhenName ) {
    864         ClauseData * currClause;
    865         for ( vector<ClauseData*>::size_type i = 0; i < stmt->clauses.size(); i++ ) {
    866                 currClause = new ClauseData( i, statusName );
    867                 currClause->nodeName = namer_node.newName();
    868                 currClause->targetName = namer_target.newName();
    869                 currClause->whenName = namer_when.newName();
    870                 clauseData.push_back(currClause);
    871                 const CodeLocation & cLoc = stmt->clauses.at(i)->location;
    872 
    873                 // typeof(target) & __clause_target_0 = target;
    874                 body->push_back(
    875                         new DeclStmt( cLoc,
    876                                 new ObjectDecl( cLoc,
    877                                     currClause->targetName,
    878                                     new ReferenceType(
    879                                         new TypeofType( new UntypedExpr( cLoc,
    880                                             new NameExpr( cLoc, "__CFA_select_get_type" ),
    881                                             { ast::deepCopy( stmt->clauses.at(i)->target ) }
    882                                         ))
    883                                     ),
    884                                     new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->target ) )
    885                                 )
    886                         )
    887                 );
    888 
    889                 // bool __when_cond_0 = when_cond; // only generated if when_cond defined
    890                 if ( stmt->clauses.at(i)->when_cond )
    891                         body->push_back(
    892                                 new DeclStmt( cLoc,
    893                                     new ObjectDecl( cLoc,
    894                                         currClause->whenName,
    895                                         new BasicType( BasicKind::Bool ),
    896                                         new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->when_cond ) )
    897                                     )
    898                                 )
    899                         );
    900 
    901                 // select_node clause1;
    902                 body->push_back(
    903                         new DeclStmt( cLoc,
    904                                 new ObjectDecl( cLoc,
    905                                     currClause->nodeName,
    906                                     new StructInstType( selectNodeDecl )
    907                                 )
    908                         )
    909                 );
    910         }
    911 
    912         if ( stmt->else_stmt && stmt->else_cond ) {
    913                 body->push_back(
    914                         new DeclStmt( stmt->else_cond->location,
    915                                 new ObjectDecl( stmt->else_cond->location,
    916                                     elseWhenName,
    917                                     new BasicType( BasicKind::Bool ),
    918                                     new SingleInit( stmt->else_cond->location, ast::deepCopy( stmt->else_cond ) )
    919                                 )
    920                         )
    921                 );
    922         }
     864    ClauseData * currClause;
     865    for ( vector<ClauseData*>::size_type i = 0; i < stmt->clauses.size(); i++ ) {
     866        currClause = new ClauseData( i, statusName );
     867        currClause->nodeName = namer_node.newName();
     868        currClause->targetName = namer_target.newName();
     869        currClause->whenName = namer_when.newName();
     870        clauseData.push_back(currClause);
     871        const CodeLocation & cLoc = stmt->clauses.at(i)->location;
     872
     873        // typeof(target) & __clause_target_0 = target;
     874        body->push_back(
     875            new DeclStmt( cLoc,
     876                new ObjectDecl( cLoc,
     877                    currClause->targetName,
     878                    new ReferenceType(
     879                        new TypeofType( new UntypedExpr( cLoc,
     880                            new NameExpr( cLoc, "__CFA_select_get_type" ),
     881                            { ast::deepCopy( stmt->clauses.at(i)->target ) }
     882                        ))
     883                    ),
     884                    new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->target ) )
     885                )
     886            )
     887        );
     888
     889        // bool __when_cond_0 = when_cond; // only generated if when_cond defined
     890        if ( stmt->clauses.at(i)->when_cond )
     891            body->push_back(
     892                new DeclStmt( cLoc,
     893                    new ObjectDecl( cLoc,
     894                        currClause->whenName,
     895                        new BasicType( BasicKind::Bool ),
     896                        new SingleInit( cLoc, ast::deepCopy( stmt->clauses.at(i)->when_cond ) )
     897                    )
     898                )
     899            );
     900       
     901        // select_node clause1;
     902        body->push_back(
     903            new DeclStmt( cLoc,
     904                new ObjectDecl( cLoc,
     905                    currClause->nodeName,
     906                    new StructInstType( selectNodeDecl )
     907                )
     908            )
     909        );
     910    }
     911
     912    if ( stmt->else_stmt && stmt->else_cond ) {
     913        body->push_back(
     914            new DeclStmt( stmt->else_cond->location,
     915                new ObjectDecl( stmt->else_cond->location,
     916                    elseWhenName,
     917                    new BasicType( BasicKind::Bool ),
     918                    new SingleInit( stmt->else_cond->location, ast::deepCopy( stmt->else_cond ) )
     919                )
     920            )
     921        );
     922    }
    923923}
    924924
     
    929929*/
    930930Stmt * GenerateWaitUntilCore::buildOrCaseSwitch( const WaitUntilStmt * stmt, string & statusName, vector<ClauseData *> & data ) {
    931         const CodeLocation & loc = stmt->location;
    932 
    933         IfStmt * outerIf = nullptr;
     931    const CodeLocation & loc = stmt->location;
     932
     933    IfStmt * outerIf = nullptr;
    934934        IfStmt * lastIf = nullptr;
    935935
    936936        //adds an if/elif clause for each select clause address to run the corresponding clause stmt
    937937        for ( long unsigned int i = 0; i < data.size(); i++ ) {
    938                 const CodeLocation & cLoc = stmt->clauses.at(i)->location;
     938        const CodeLocation & cLoc = stmt->clauses.at(i)->location;
    939939
    940940                IfStmt * currIf = new IfStmt( cLoc,
    941                         new UntypedExpr( cLoc,
    942                                 new NameExpr( cLoc, "?==?" ),
    943                                 {
    944                                     new NameExpr( cLoc, statusName ),
    945                                     new CastExpr( cLoc,
    946                                         new AddressExpr( cLoc, new NameExpr( cLoc, data.at(i)->nodeName ) ),
    947                                         new BasicType( BasicKind::LongUnsignedInt ), GeneratedFlag::ExplicitCast
    948                                     )
    949                                 }
    950                         ),
    951                         genStmtBlock( stmt->clauses.at(i), data.at(i) )
     941                        new UntypedExpr( cLoc, 
     942                new NameExpr( cLoc, "?==?" ),
     943                {
     944                    new NameExpr( cLoc, statusName ),
     945                    new CastExpr( cLoc,
     946                        new AddressExpr( cLoc, new NameExpr( cLoc, data.at(i)->nodeName ) ),
     947                        new BasicType( BasicKind::LongUnsignedInt ), GeneratedFlag::ExplicitCast
     948                    )
     949                }
     950            ),
     951            genStmtBlock( stmt->clauses.at(i), data.at(i) )
    952952                );
    953 
     953               
    954954                if ( i == 0 ) {
    955955                        outerIf = currIf;
     
    962962        }
    963963
    964         return new CompoundStmt( loc,
    965                 {
    966                         new ExprStmt( loc, new UntypedExpr( loc, new NameExpr( loc, "park" ) ) ),
    967                         outerIf
    968                 }
    969         );
     964    return new CompoundStmt( loc,
     965        {
     966            new ExprStmt( loc, new UntypedExpr( loc, new NameExpr( loc, "park" ) ) ),
     967            outerIf
     968        }
     969    );
    970970}
    971971
    972972Stmt * GenerateWaitUntilCore::recursiveOrIfGen( const WaitUntilStmt * stmt, vector<ClauseData *> & data, vector<ClauseData*>::size_type idx, string & elseWhenName ) {
    973         if ( idx == data.size() ) {   // base case, gen last else
    974                 const CodeLocation & cLoc = stmt->else_stmt->location;
    975                 if ( !stmt->else_stmt ) // normal non-else gen
    976                         return buildOrCaseSwitch( stmt, data.at(0)->statusName, data );
    977 
    978                 Expr * raceFnCall = new UntypedExpr( stmt->location,
    979                         new NameExpr( stmt->location, "__select_node_else_race" ),
    980                         { new NameExpr( stmt->location, data.at(0)->nodeName ) }
    981                 );
    982 
    983                 if ( stmt->else_stmt && stmt->else_cond ) { // return else conditional on both when and race
    984                         return new IfStmt( cLoc,
    985                                 new LogicalExpr( cLoc,
    986                                     new CastExpr( cLoc,
    987                                         new NameExpr( cLoc, elseWhenName ),
    988                                         new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    989                                     ),
    990                                     new CastExpr( cLoc,
    991                                         raceFnCall,
    992                                         new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    993                                     ),
    994                                     LogicalFlag::AndExpr
    995                                 ),
    996                                 ast::deepCopy( stmt->else_stmt ),
    997                                 buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
    998                         );
    999                 }
    1000 
    1001                 // return else conditional on race
    1002                 return new IfStmt( stmt->else_stmt->location,
    1003                         raceFnCall,
    1004                         ast::deepCopy( stmt->else_stmt ),
    1005                         buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
    1006                 );
    1007         }
    1008         const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
    1009 
    1010         Expr * baseCond = genSelectTraitCall( stmt->clauses.at(idx), data.at(idx), "register_select" );
    1011         Expr * ifCond;
    1012 
    1013         // If we have a when_cond make the register call conditional on it
    1014         if ( stmt->clauses.at(idx)->when_cond ) {
    1015                 ifCond = new LogicalExpr( cLoc,
    1016                         new CastExpr( cLoc,
    1017                                 new NameExpr( cLoc, data.at(idx)->whenName ),
    1018                                 new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1019                         ),
    1020                         new CastExpr( cLoc,
    1021                                 baseCond,
    1022                                 new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1023                         ),
    1024                         LogicalFlag::AndExpr
    1025                 );
    1026         } else ifCond = baseCond;
    1027 
    1028         return new CompoundStmt( cLoc,
    1029                 {   // gens: setup_clause( clause1, &status, 0p );
    1030                         new ExprStmt( cLoc,
    1031                                 new UntypedExpr ( cLoc,
    1032                                     new NameExpr( cLoc, "setup_clause" ),
    1033                                     {
    1034                                         new NameExpr( cLoc, data.at(idx)->nodeName ),
    1035                                         new AddressExpr( cLoc, new NameExpr( cLoc, data.at(idx)->statusName ) ),
    1036                                         ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::SignedInt ) ) )
    1037                                     }
    1038                                 )
    1039                         ),
    1040                         // gens: if (__when_cond && register_select()) { clause body } else { ... recursiveOrIfGen ... }
    1041                         new IfStmt( cLoc,
    1042                                 ifCond,
    1043                                 genStmtBlock( stmt->clauses.at(idx), data.at(idx) ),
    1044                                 recursiveOrIfGen( stmt, data, idx + 1, elseWhenName )
    1045                         )
    1046                 }
    1047         );
     973    if ( idx == data.size() ) {   // base case, gen last else
     974        const CodeLocation & cLoc = stmt->else_stmt->location;
     975        if ( !stmt->else_stmt ) // normal non-else gen
     976            return buildOrCaseSwitch( stmt, data.at(0)->statusName, data );
     977
     978        Expr * raceFnCall = new UntypedExpr( stmt->location,
     979            new NameExpr( stmt->location, "__select_node_else_race" ),
     980            { new NameExpr( stmt->location, data.at(0)->nodeName ) }
     981        );
     982
     983        if ( stmt->else_stmt && stmt->else_cond ) { // return else conditional on both when and race
     984            return new IfStmt( cLoc,
     985                new LogicalExpr( cLoc,
     986                    new CastExpr( cLoc,
     987                        new NameExpr( cLoc, elseWhenName ),
     988                        new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     989                    ),
     990                    new CastExpr( cLoc,
     991                        raceFnCall,
     992                        new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     993                    ),
     994                    LogicalFlag::AndExpr
     995                ),
     996                ast::deepCopy( stmt->else_stmt ),
     997                buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
     998            );
     999        }
     1000
     1001        // return else conditional on race
     1002        return new IfStmt( stmt->else_stmt->location,
     1003            raceFnCall,
     1004            ast::deepCopy( stmt->else_stmt ),
     1005            buildOrCaseSwitch( stmt, data.at(0)->statusName, data )
     1006        );
     1007    }
     1008    const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
     1009
     1010    Expr * baseCond = genSelectTraitCall( stmt->clauses.at(idx), data.at(idx), "register_select" );
     1011    Expr * ifCond;
     1012
     1013    // If we have a when_cond make the register call conditional on it
     1014    if ( stmt->clauses.at(idx)->when_cond ) {
     1015        ifCond = new LogicalExpr( cLoc,
     1016            new CastExpr( cLoc,
     1017                new NameExpr( cLoc, data.at(idx)->whenName ),
     1018                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1019            ),
     1020            new CastExpr( cLoc,
     1021                baseCond,
     1022                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1023            ),
     1024            LogicalFlag::AndExpr
     1025        );
     1026    } else ifCond = baseCond;
     1027
     1028    return new CompoundStmt( cLoc,
     1029        {   // gens: setup_clause( clause1, &status, 0p );
     1030            new ExprStmt( cLoc,
     1031                new UntypedExpr ( cLoc,
     1032                    new NameExpr( cLoc, "setup_clause" ),
     1033                    {
     1034                        new NameExpr( cLoc, data.at(idx)->nodeName ),
     1035                        new AddressExpr( cLoc, new NameExpr( cLoc, data.at(idx)->statusName ) ),
     1036                        ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::SignedInt ) ) )
     1037                    }
     1038                )
     1039            ),
     1040            // gens: if (__when_cond && register_select()) { clause body } else { ... recursiveOrIfGen ... }
     1041            new IfStmt( cLoc,
     1042                ifCond,
     1043                genStmtBlock( stmt->clauses.at(idx), data.at(idx) ),
     1044                recursiveOrIfGen( stmt, data, idx + 1, elseWhenName )
     1045            )
     1046        }
     1047    );
    10481048}
    10491049
    10501050// This gens the special case of an all OR waituntil:
    1051 /*
     1051/* 
    10521052int status = 0;
    10531053
     
    10581058
    10591059try {
    1060         setup_clause( clause1, &status, 0p );
    1061         if ( __when_cond_0 && register_select( 1 ) ) {
    1062                 ... clause 1 body ...
    1063         } else {
    1064                 ... recursively gen for each of n clauses ...
    1065                 setup_clause( clausen, &status, 0p );
    1066                 if ( __when_cond_n-1 && register_select( n ) ) {
    1067                         ... clause n body ...
    1068                 } else {
    1069                         if ( else_when ) ... else clause body ...
    1070                         else {
    1071                                 park();
    1072 
    1073                                 // after winning the race and before unpark() clause_status is set to be the winning clause index + 1
    1074                                 if ( clause_status == &clause1) ... clause 1 body ...
    1075                                 ...
    1076                                 elif ( clause_status == &clausen ) ... clause n body ...
    1077                         }
    1078                 }
    1079         }
    1080 }
    1081 finally {
    1082         if ( __when_cond_1 && clause1.status != 0p) unregister_select( 1 ); // if registered unregister
    1083         ...
    1084         if ( __when_cond_n && clausen.status != 0p) unregister_select( n );
     1060    setup_clause( clause1, &status, 0p );
     1061    if ( __when_cond_0 && register_select( 1 ) ) {
     1062        ... clause 1 body ...
     1063    } else {
     1064        ... recursively gen for each of n clauses ...
     1065        setup_clause( clausen, &status, 0p );
     1066        if ( __when_cond_n-1 && register_select( n ) ) {
     1067            ... clause n body ...
     1068        } else {
     1069            if ( else_when ) ... else clause body ...
     1070            else {
     1071                park();
     1072
     1073                // after winning the race and before unpark() clause_status is set to be the winning clause index + 1
     1074                if ( clause_status == &clause1) ... clause 1 body ...
     1075                ...
     1076                elif ( clause_status == &clausen ) ... clause n body ...
     1077            }
     1078        }
     1079    }
     1080}
     1081finally { 
     1082    if ( __when_cond_1 && clause1.status != 0p) unregister_select( 1 ); // if registered unregister
     1083    ...
     1084    if ( __when_cond_n && clausen.status != 0p) unregister_select( n );
    10851085}
    10861086*/
    10871087Stmt * GenerateWaitUntilCore::genAllOr( const WaitUntilStmt * stmt ) {
    1088         const CodeLocation & loc = stmt->location;
    1089         string statusName = namer_status.newName();
    1090         string elseWhenName = namer_when.newName();
    1091         int numClauses = stmt->clauses.size();
    1092         CompoundStmt * body = new CompoundStmt( stmt->location );
    1093 
    1094         // Generates: unsigned long int status = 0;
    1095         body->push_back( new DeclStmt( loc,
    1096                 new ObjectDecl( loc,
    1097                         statusName,
    1098                         new BasicType( BasicKind::LongUnsignedInt ),
    1099                         new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
    1100                 )
    1101         ));
    1102 
    1103         vector<ClauseData *> clauseData;
    1104         genClauseInits( stmt, clauseData, body, statusName, elseWhenName );
    1105 
    1106         vector<int> whenIndices; // track which clauses have whens
    1107 
    1108         CompoundStmt * unregisters = new CompoundStmt( loc );
    1109         Expr * ifCond;
    1110         for ( int i = 0; i < numClauses; i++ ) {
    1111                 const CodeLocation & cLoc = stmt->clauses.at(i)->location;
    1112                 // Gens: node.status != 0p
    1113                 UntypedExpr * statusPtrCheck = new UntypedExpr( cLoc,
    1114                         new NameExpr( cLoc, "?!=?" ),
    1115                         {
    1116                                 ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::LongUnsignedInt ) ) ),
    1117                                 new UntypedExpr( cLoc,
    1118                                     new NameExpr( cLoc, "__get_clause_status" ),
    1119                                     { new NameExpr( cLoc, clauseData.at(i)->nodeName ) }
    1120                                 )
    1121                         }
    1122                 );
    1123 
    1124                 // If we have a when_cond make the unregister call conditional on it
    1125                 if ( stmt->clauses.at(i)->when_cond ) {
    1126                         whenIndices.push_back(i);
    1127                         ifCond = new LogicalExpr( cLoc,
    1128                                 new CastExpr( cLoc,
    1129                                     new NameExpr( cLoc, clauseData.at(i)->whenName ),
    1130                                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1131                                 ),
    1132                                 new CastExpr( cLoc,
    1133                                     statusPtrCheck,
    1134                                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1135                                 ),
    1136                                 LogicalFlag::AndExpr
    1137                         );
    1138                 } else ifCond = statusPtrCheck;
    1139 
    1140                 unregisters->push_back(
    1141                         new IfStmt( cLoc,
    1142                                 ifCond,
    1143                                 new ExprStmt( cLoc, genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ) )
    1144                         )
    1145                 );
    1146         }
    1147 
    1148         if ( whenIndices.empty() || whenIndices.size() != stmt->clauses.size() ) {
    1149                 body->push_back(
    1150                                 new ast::TryStmt( loc,
    1151                                 new CompoundStmt( loc, { recursiveOrIfGen( stmt, clauseData, 0, elseWhenName ) } ),
    1152                                 {},
    1153                                 new ast::FinallyClause( loc, unregisters )
    1154                         )
    1155                 );
    1156         } else { // If all clauses have whens, we need to skip the waituntil if they are all false
    1157                 Expr * outerIfCond = new NameExpr( loc, clauseData.at( whenIndices.at(0) )->whenName );
    1158                 Expr * lastExpr = outerIfCond;
    1159 
    1160                 for ( vector<int>::size_type i = 1; i < whenIndices.size(); i++ ) {
    1161                         outerIfCond = new LogicalExpr( loc,
    1162                                 new CastExpr( loc,
    1163                                     new NameExpr( loc, clauseData.at( whenIndices.at(i) )->whenName ),
    1164                                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1165                                 ),
    1166                                 new CastExpr( loc,
    1167                                     lastExpr,
    1168                                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1169                                 ),
    1170                                 LogicalFlag::OrExpr
    1171                         );
    1172                         lastExpr = outerIfCond;
    1173                 }
    1174 
    1175                 body->push_back(
    1176                                 new ast::TryStmt( loc,
    1177                                 new CompoundStmt( loc,
    1178                                     {
    1179                                         new IfStmt( loc,
    1180                                             outerIfCond,
    1181                                             recursiveOrIfGen( stmt, clauseData, 0, elseWhenName )
    1182                                         )
    1183                                     }
    1184                                 ),
    1185                                 {},
    1186                                 new ast::FinallyClause( loc, unregisters )
    1187                         )
    1188                 );
    1189         }
    1190 
    1191         for ( ClauseData * datum : clauseData )
    1192                 delete datum;
    1193 
    1194         return body;
     1088    const CodeLocation & loc = stmt->location;
     1089    string statusName = namer_status.newName();
     1090    string elseWhenName = namer_when.newName();
     1091    int numClauses = stmt->clauses.size();
     1092    CompoundStmt * body = new CompoundStmt( stmt->location );
     1093
     1094    // Generates: unsigned long int status = 0;
     1095    body->push_back( new DeclStmt( loc,
     1096        new ObjectDecl( loc,
     1097            statusName,
     1098            new BasicType( BasicKind::LongUnsignedInt ),
     1099            new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     1100        )
     1101    ));
     1102
     1103    vector<ClauseData *> clauseData;
     1104    genClauseInits( stmt, clauseData, body, statusName, elseWhenName );
     1105
     1106    vector<int> whenIndices; // track which clauses have whens
     1107
     1108    CompoundStmt * unregisters = new CompoundStmt( loc );
     1109    Expr * ifCond;
     1110    for ( int i = 0; i < numClauses; i++ ) {
     1111        const CodeLocation & cLoc = stmt->clauses.at(i)->location;
     1112        // Gens: node.status != 0p
     1113        UntypedExpr * statusPtrCheck = new UntypedExpr( cLoc,
     1114            new NameExpr( cLoc, "?!=?" ),
     1115            {
     1116                ConstantExpr::null( cLoc, new PointerType( new BasicType( BasicKind::LongUnsignedInt ) ) ),
     1117                new UntypedExpr( cLoc,
     1118                    new NameExpr( cLoc, "__get_clause_status" ),
     1119                    { new NameExpr( cLoc, clauseData.at(i)->nodeName ) }
     1120                )
     1121            }
     1122        );
     1123
     1124        // If we have a when_cond make the unregister call conditional on it
     1125        if ( stmt->clauses.at(i)->when_cond ) {
     1126            whenIndices.push_back(i);
     1127            ifCond = new LogicalExpr( cLoc,
     1128                new CastExpr( cLoc,
     1129                    new NameExpr( cLoc, clauseData.at(i)->whenName ),
     1130                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1131                ),
     1132                new CastExpr( cLoc,
     1133                    statusPtrCheck,
     1134                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1135                ),
     1136                LogicalFlag::AndExpr
     1137            );
     1138        } else ifCond = statusPtrCheck;
     1139       
     1140        unregisters->push_back(
     1141            new IfStmt( cLoc,
     1142                ifCond,
     1143                new ExprStmt( cLoc, genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ) )
     1144            )
     1145        );
     1146    }
     1147
     1148    if ( whenIndices.empty() || whenIndices.size() != stmt->clauses.size() ) {
     1149        body->push_back(
     1150                new ast::TryStmt( loc,
     1151                new CompoundStmt( loc, { recursiveOrIfGen( stmt, clauseData, 0, elseWhenName ) } ),
     1152                {},
     1153                new ast::FinallyClause( loc, unregisters )
     1154            )
     1155        );
     1156    } else { // If all clauses have whens, we need to skip the waituntil if they are all false
     1157        Expr * outerIfCond = new NameExpr( loc, clauseData.at( whenIndices.at(0) )->whenName );
     1158        Expr * lastExpr = outerIfCond;
     1159
     1160        for ( vector<int>::size_type i = 1; i < whenIndices.size(); i++ ) {
     1161            outerIfCond = new LogicalExpr( loc,
     1162                new CastExpr( loc,
     1163                    new NameExpr( loc, clauseData.at( whenIndices.at(i) )->whenName ),
     1164                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1165                ),
     1166                new CastExpr( loc,
     1167                    lastExpr,
     1168                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1169                ),
     1170                LogicalFlag::OrExpr
     1171            );
     1172            lastExpr = outerIfCond;
     1173        }
     1174
     1175        body->push_back(
     1176                new ast::TryStmt( loc,
     1177                new CompoundStmt( loc,
     1178                    {
     1179                        new IfStmt( loc,
     1180                            outerIfCond,
     1181                            recursiveOrIfGen( stmt, clauseData, 0, elseWhenName )
     1182                        )
     1183                    }
     1184                ),
     1185                {},
     1186                new ast::FinallyClause( loc, unregisters )
     1187            )
     1188        );
     1189    }
     1190
     1191    for ( ClauseData * datum : clauseData )
     1192        delete datum;
     1193
     1194    return body;
    11951195}
    11961196
    11971197Stmt * GenerateWaitUntilCore::postvisit( const WaitUntilStmt * stmt ) {
    1198         if ( !selectNodeDecl )
    1199                 SemanticError( stmt, "waituntil statement requires #include <waituntil.hfa>" );
    1200 
    1201         // Prep clause tree to figure out how to set initial statuses
    1202         // setTreeSizes( stmt->predicateTree );
    1203         if ( paintWhenTree( stmt->predicateTree ) ) // if this returns true we can special case since tree is all OR's
    1204                 return genAllOr( stmt );
    1205 
    1206         CompoundStmt * tryBody = new CompoundStmt( stmt->location );
    1207         CompoundStmt * body = new CompoundStmt( stmt->location );
    1208         string statusArrName = namer_status.newName();
    1209         string pCountName = namer_park.newName();
    1210         string satName = namer_sat.newName();
    1211         string runName = namer_run.newName();
    1212         string elseWhenName = namer_when.newName();
    1213         int numClauses = stmt->clauses.size();
    1214         addPredicates( stmt, satName, runName );
    1215 
    1216         const CodeLocation & loc = stmt->location;
    1217 
    1218         // Generates: int park_counter = 0;
    1219         body->push_back( new DeclStmt( loc,
    1220                 new ObjectDecl( loc,
    1221                         pCountName,
    1222                         new BasicType( BasicKind::SignedInt ),
    1223                         new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
    1224                 )
    1225         ));
    1226 
    1227         // Generates: int clause_statuses[3] = { 0 };
    1228         body->push_back( new DeclStmt( loc,
    1229                 new ObjectDecl( loc,
    1230                         statusArrName,
    1231                         new ArrayType( new BasicType( BasicKind::LongUnsignedInt ), ConstantExpr::from_int( loc, numClauses ), LengthFlag::FixedLen, DimensionFlag::DynamicDim ),
    1232                         new ListInit( loc,
    1233                                 {
    1234                                     new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
    1235                                 }
    1236                         )
    1237                 )
    1238         ));
    1239 
    1240         vector<ClauseData *> clauseData;
    1241         genClauseInits( stmt, clauseData, body, statusArrName, elseWhenName );
    1242 
    1243         vector<pair<int, WaitUntilStmt::ClauseNode *>> ambiguousClauses;       // list of ambiguous clauses
    1244         vector<int> andWhenClauses;    // list of clauses that have an AND op as a direct parent and when_cond defined
    1245 
    1246         collectWhens( stmt->predicateTree, ambiguousClauses, andWhenClauses );
    1247 
    1248         // This is only needed for clauses that have AND as a parent and a when_cond defined
    1249         // generates: if ( ! when_cond_0 ) clause_statuses_0 = __SELECT_RUN;
    1250         for ( int idx : andWhenClauses ) {
    1251                 const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
    1252                 body->push_back(
    1253                         new IfStmt( cLoc,
    1254                                 new UntypedExpr ( cLoc,
    1255                                     new NameExpr( cLoc, "!?" ),
    1256                                     { new NameExpr( cLoc, clauseData.at(idx)->whenName ) }
    1257                                 ),  // IfStmt cond
    1258                                 new ExprStmt( cLoc,
    1259                                     new UntypedExpr ( cLoc,
    1260                                         new NameExpr( cLoc, "?=?" ),
    1261                                         {
    1262                                             new UntypedExpr ( cLoc,
    1263                                                 new NameExpr( cLoc, "?[?]" ),
    1264                                                 {
    1265                                                     new NameExpr( cLoc, statusArrName ),
    1266                                                     ConstantExpr::from_int( cLoc, idx )
    1267                                                 }
    1268                                             ),
    1269                                             new NameExpr( cLoc, "__SELECT_RUN" )
    1270                                         }
    1271                                     )
    1272                                 )  // IfStmt then
    1273                         )
    1274                 );
    1275         }
    1276 
    1277         // Only need to generate conditional initial state setting for ambiguous when clauses
    1278         if ( !ambiguousClauses.empty() ) {
    1279                 body->push_back( genWhenStateConditions( stmt, clauseData, ambiguousClauses, 0 ) );
    1280         }
    1281 
    1282         // generates the following for each clause:
    1283         // setup_clause( clause1, &clause_statuses[0], &park_counter );
    1284         // register_select(A, clause1);
    1285         for ( int i = 0; i < numClauses; i++ ) {
    1286                 setUpClause( stmt->clauses.at(i), clauseData.at(i), pCountName, tryBody );
    1287         }
    1288 
    1289         // generate satisfy logic based on if there is an else clause and if it is conditional
    1290         if ( stmt->else_stmt && stmt->else_cond ) { // gen both else/non else branches
    1291                 tryBody->push_back(
    1292                         new IfStmt( stmt->else_cond->location,
    1293                                 new NameExpr( stmt->else_cond->location, elseWhenName ),
    1294                                 genElseClauseBranch( stmt, runName, statusArrName, clauseData ),
    1295                                 genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData )
    1296                         )
    1297                 );
    1298         } else if ( !stmt->else_stmt ) { // normal gen
    1299                 tryBody->push_back( genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData ) );
    1300         } else { // generate just else
    1301                 tryBody->push_back( genElseClauseBranch( stmt, runName, statusArrName, clauseData ) );
    1302         }
    1303 
    1304         // Collection of unregister calls on resources to be put in finally clause
    1305         // for each clause:
    1306         // if ( !__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
    1307         // OR if when( ... ) defined on resource
    1308         // if ( when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
    1309         CompoundStmt * unregisters = new CompoundStmt( loc );
    1310 
    1311         Expr * statusExpr; // !__CFA_has_clause_run( clause_statuses[i] )
    1312         for ( int i = 0; i < numClauses; i++ ) {
    1313                 const CodeLocation & cLoc = stmt->clauses.at(i)->location;
    1314 
    1315                 // Generates: !__CFA_has_clause_run( clause_statuses[i] )
    1316                 statusExpr = new UntypedExpr ( cLoc,
    1317                         new NameExpr( cLoc, "!?" ),
    1318                         {
    1319                                 new UntypedExpr ( cLoc,
    1320                                     new NameExpr( cLoc, "__CFA_has_clause_run" ),
    1321                                     {
    1322                                         genArrAccessExpr( cLoc, i, statusArrName )
    1323                                     }
    1324                                 )
    1325                         }
    1326                 );
    1327 
    1328                 // Generates:
    1329                 // (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
    1330                 statusExpr = new LogicalExpr( cLoc,
    1331                         new CastExpr( cLoc,
    1332                                 statusExpr,
    1333                                 new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1334                         ),
    1335                         new CastExpr( cLoc,
    1336                                 genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ),
    1337                                 new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1338                         ),
    1339                         LogicalFlag::AndExpr
    1340                 );
    1341 
    1342                 // if when cond defined generates:
    1343                 // when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
    1344                 if ( stmt->clauses.at(i)->when_cond )
    1345                         statusExpr = new LogicalExpr( cLoc,
    1346                                 new CastExpr( cLoc,
    1347                                     new NameExpr( cLoc, clauseData.at(i)->whenName ),
    1348                                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1349                                 ),
    1350                                 new CastExpr( cLoc,
    1351                                     statusExpr,
    1352                                     new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
    1353                                 ),
    1354                                 LogicalFlag::AndExpr
    1355                         );
    1356 
    1357                 // generates:
    1358                 // if ( statusExpr ) { ... clausei stmt ... }
    1359                 unregisters->push_back(
    1360                         new IfStmt( cLoc,
    1361                                 statusExpr,
    1362                                 new CompoundStmt( cLoc,
    1363                                     {
    1364                                         new IfStmt( cLoc,
    1365                                             genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "on_selected" ),
    1366                                             ast::deepCopy( stmt->clauses.at(i)->stmt )
    1367                                         )
    1368                                     }
    1369                                 )
    1370                         )
    1371                 );
    1372 
    1373                 // // generates:
    1374                 // // if ( statusExpr ) { ... clausei stmt ... }
    1375                 // unregisters->push_back(
    1376                 //     new IfStmt( cLoc,
    1377                 //         statusExpr,
    1378                 //         genStmtBlock( stmt->clauses.at(i), clauseData.at(i) )
    1379                 //     )
    1380                 // );
    1381         }
    1382 
    1383         body->push_back(
    1384                 new ast::TryStmt(
    1385                         loc,
    1386                         tryBody,
    1387                         {},
    1388                         new ast::FinallyClause( loc, unregisters )
    1389                 )
    1390         );
    1391 
    1392         for ( ClauseData * datum : clauseData )
    1393                 delete datum;
    1394 
    1395         return body;
     1198    if ( !selectNodeDecl )
     1199        SemanticError( stmt, "waituntil statement requires #include <waituntil.hfa>" );
     1200
     1201    // Prep clause tree to figure out how to set initial statuses
     1202    // setTreeSizes( stmt->predicateTree );
     1203    if ( paintWhenTree( stmt->predicateTree ) ) // if this returns true we can special case since tree is all OR's
     1204        return genAllOr( stmt );
     1205
     1206    CompoundStmt * tryBody = new CompoundStmt( stmt->location );
     1207    CompoundStmt * body = new CompoundStmt( stmt->location );
     1208    string statusArrName = namer_status.newName();
     1209    string pCountName = namer_park.newName();
     1210    string satName = namer_sat.newName();
     1211    string runName = namer_run.newName();
     1212    string elseWhenName = namer_when.newName();
     1213    int numClauses = stmt->clauses.size();
     1214    addPredicates( stmt, satName, runName );
     1215
     1216    const CodeLocation & loc = stmt->location;
     1217
     1218    // Generates: int park_counter = 0;
     1219    body->push_back( new DeclStmt( loc,
     1220        new ObjectDecl( loc,
     1221            pCountName,
     1222            new BasicType( BasicKind::SignedInt ),
     1223            new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     1224        )
     1225    ));
     1226
     1227    // Generates: int clause_statuses[3] = { 0 };
     1228    body->push_back( new DeclStmt( loc,
     1229        new ObjectDecl( loc,
     1230            statusArrName,
     1231            new ArrayType( new BasicType( BasicKind::LongUnsignedInt ), ConstantExpr::from_int( loc, numClauses ), LengthFlag::FixedLen, DimensionFlag::DynamicDim ),
     1232            new ListInit( loc,
     1233                {
     1234                    new SingleInit( loc, ConstantExpr::from_int( loc, 0 ) )
     1235                }
     1236            )
     1237        )
     1238    ));
     1239
     1240    vector<ClauseData *> clauseData;
     1241    genClauseInits( stmt, clauseData, body, statusArrName, elseWhenName );
     1242
     1243    vector<pair<int, WaitUntilStmt::ClauseNode *>> ambiguousClauses;       // list of ambiguous clauses
     1244    vector<int> andWhenClauses;    // list of clauses that have an AND op as a direct parent and when_cond defined
     1245
     1246    collectWhens( stmt->predicateTree, ambiguousClauses, andWhenClauses );
     1247
     1248    // This is only needed for clauses that have AND as a parent and a when_cond defined
     1249    // generates: if ( ! when_cond_0 ) clause_statuses_0 = __SELECT_RUN;
     1250    for ( int idx : andWhenClauses ) {
     1251        const CodeLocation & cLoc = stmt->clauses.at(idx)->location;
     1252        body->push_back(
     1253            new IfStmt( cLoc,
     1254                new UntypedExpr ( cLoc,
     1255                    new NameExpr( cLoc, "!?" ),
     1256                    { new NameExpr( cLoc, clauseData.at(idx)->whenName ) }
     1257                ),  // IfStmt cond
     1258                new ExprStmt( cLoc,
     1259                    new UntypedExpr ( cLoc,
     1260                        new NameExpr( cLoc, "?=?" ),
     1261                        {
     1262                            new UntypedExpr ( cLoc,
     1263                                new NameExpr( cLoc, "?[?]" ),
     1264                                {
     1265                                    new NameExpr( cLoc, statusArrName ),
     1266                                    ConstantExpr::from_int( cLoc, idx )
     1267                                }
     1268                            ),
     1269                            new NameExpr( cLoc, "__SELECT_RUN" )
     1270                        }
     1271                    )
     1272                )  // IfStmt then
     1273            )
     1274        );
     1275    }
     1276
     1277    // Only need to generate conditional initial state setting for ambiguous when clauses
     1278    if ( !ambiguousClauses.empty() ) {
     1279        body->push_back( genWhenStateConditions( stmt, clauseData, ambiguousClauses, 0 ) );
     1280    }
     1281
     1282    // generates the following for each clause:
     1283    // setup_clause( clause1, &clause_statuses[0], &park_counter );
     1284    // register_select(A, clause1);
     1285    for ( int i = 0; i < numClauses; i++ ) {
     1286        setUpClause( stmt->clauses.at(i), clauseData.at(i), pCountName, tryBody );
     1287    }
     1288
     1289    // generate satisfy logic based on if there is an else clause and if it is conditional
     1290    if ( stmt->else_stmt && stmt->else_cond ) { // gen both else/non else branches
     1291        tryBody->push_back(
     1292            new IfStmt( stmt->else_cond->location,
     1293                new NameExpr( stmt->else_cond->location, elseWhenName ),
     1294                genElseClauseBranch( stmt, runName, statusArrName, clauseData ),
     1295                genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData )
     1296            )
     1297        );
     1298    } else if ( !stmt->else_stmt ) { // normal gen
     1299        tryBody->push_back( genNoElseClauseBranch( stmt, runName, statusArrName, pCountName, clauseData ) );
     1300    } else { // generate just else
     1301        tryBody->push_back( genElseClauseBranch( stmt, runName, statusArrName, clauseData ) );
     1302    }
     1303
     1304    // Collection of unregister calls on resources to be put in finally clause
     1305    // for each clause:
     1306    // if ( !__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
     1307    // OR if when( ... ) defined on resource
     1308    // if ( when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei ) ) { ... clausei stmt ... }
     1309    CompoundStmt * unregisters = new CompoundStmt( loc );
     1310
     1311    Expr * statusExpr; // !__CFA_has_clause_run( clause_statuses[i] )
     1312    for ( int i = 0; i < numClauses; i++ ) {
     1313        const CodeLocation & cLoc = stmt->clauses.at(i)->location;
     1314
     1315        // Generates: !__CFA_has_clause_run( clause_statuses[i] )
     1316        statusExpr = new UntypedExpr ( cLoc,
     1317            new NameExpr( cLoc, "!?" ),
     1318            {
     1319                new UntypedExpr ( cLoc,
     1320                    new NameExpr( cLoc, "__CFA_has_clause_run" ),
     1321                    {
     1322                        genArrAccessExpr( cLoc, i, statusArrName )
     1323                    }
     1324                )
     1325            }
     1326        );
     1327       
     1328        // Generates:
     1329        // (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
     1330        statusExpr = new LogicalExpr( cLoc,
     1331            new CastExpr( cLoc,
     1332                statusExpr,
     1333                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1334            ),
     1335            new CastExpr( cLoc,
     1336                genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "unregister_select" ),
     1337                new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1338            ),
     1339            LogicalFlag::AndExpr
     1340        );
     1341       
     1342        // if when cond defined generates:
     1343        // when_cond_i && (!__CFA_has_clause_run( clause_statuses[i] )) && unregister_select( ... , clausei );
     1344        if ( stmt->clauses.at(i)->when_cond )
     1345            statusExpr = new LogicalExpr( cLoc,
     1346                new CastExpr( cLoc,
     1347                    new NameExpr( cLoc, clauseData.at(i)->whenName ),
     1348                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1349                ),
     1350                new CastExpr( cLoc,
     1351                    statusExpr,
     1352                    new BasicType( BasicKind::Bool ), GeneratedFlag::ExplicitCast
     1353                ),
     1354                LogicalFlag::AndExpr
     1355            );
     1356
     1357        // generates:
     1358        // if ( statusExpr ) { ... clausei stmt ... }
     1359        unregisters->push_back(
     1360            new IfStmt( cLoc,
     1361                statusExpr,
     1362                new CompoundStmt( cLoc,
     1363                    {
     1364                        new IfStmt( cLoc,
     1365                            genSelectTraitCall( stmt->clauses.at(i), clauseData.at(i), "on_selected" ),
     1366                            ast::deepCopy( stmt->clauses.at(i)->stmt )
     1367                        )
     1368                    }
     1369                )
     1370            )
     1371        );
     1372
     1373        // // generates:
     1374        // // if ( statusExpr ) { ... clausei stmt ... }
     1375        // unregisters->push_back(
     1376        //     new IfStmt( cLoc,
     1377        //         statusExpr,
     1378        //         genStmtBlock( stmt->clauses.at(i), clauseData.at(i) )
     1379        //     )
     1380        // );
     1381    }
     1382
     1383    body->push_back(
     1384        new ast::TryStmt(
     1385            loc,
     1386            tryBody,
     1387            {},
     1388            new ast::FinallyClause( loc, unregisters )
     1389        )
     1390    );
     1391
     1392    for ( ClauseData * datum : clauseData )
     1393        delete datum;
     1394
     1395    return body;
    13961396}
    13971397
     
    13991399// Predicates are added after "struct select_node { ... };"
    14001400class AddPredicateDecls final : public WithDeclsToAdd<> {
    1401         vector<FunctionDecl *> & satFns;
    1402         const StructDecl * selectNodeDecl = nullptr;
     1401    vector<FunctionDecl *> & satFns;
     1402    const StructDecl * selectNodeDecl = nullptr;
    14031403
    14041404  public:
    1405         void previsit( const StructDecl * decl ) {
    1406                 if ( !decl->body ) {
    1407                         return;
    1408                 } else if ( "select_node" == decl->name ) {
    1409                         assert( !selectNodeDecl );
    1410                         selectNodeDecl = decl;
    1411                         for ( FunctionDecl * fn : satFns )
    1412                                 declsToAddAfter.push_back(fn);
    1413                 }
    1414         }
    1415         AddPredicateDecls( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
     1405    void previsit( const StructDecl * decl ) {
     1406        if ( !decl->body ) {
     1407            return;
     1408        } else if ( "select_node" == decl->name ) {
     1409            assert( !selectNodeDecl );
     1410            selectNodeDecl = decl;
     1411            for ( FunctionDecl * fn : satFns )
     1412                declsToAddAfter.push_back(fn);           
     1413        }
     1414    }
     1415    AddPredicateDecls( vector<FunctionDecl *> & satFns ): satFns(satFns) {}
    14161416};
    14171417
    14181418void generateWaitUntil( TranslationUnit & translationUnit ) {
    1419         vector<FunctionDecl *> satFns;
     1419    vector<FunctionDecl *> satFns;
    14201420        Pass<GenerateWaitUntilCore>::run( translationUnit, satFns );
    1421         Pass<AddPredicateDecls>::run( translationUnit, satFns );
     1421    Pass<AddPredicateDecls>::run( translationUnit, satFns );
    14221422}
    14231423
  • src/Parser/parser.yy

    r7042c60 rcf191ac  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 23 15:39:29 2024
    13 // Update Count     : 6620
     12// Last Modified On : Sat Mar 16 18:19:23 2024
     13// Update Count     : 6617
    1414//
    1515
     
    493493%type<decl> exception_declaration
    494494
    495 %type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declaring_list field_declarator field_abstract_list_opt field_abstract
     495%type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declarator field_abstract_list_opt field_abstract
    496496%type<expr> field field_name_list field_name fraction_constants_opt
    497497
     
    26822682        // empty
    26832683                { $$ = nullptr; }
    2684         | field_declaring_list
    2685         ;
    2686 
    2687 field_declaring_list:
    2688         field_declarator
    2689         | field_declaring_list ',' attribute_list_opt field_declarator
     2684        | field_declarator
     2685        | field_declaring_list_opt ',' attribute_list_opt field_declarator
    26902686                { $$ = $1->set_last( $4->addQualifiers( $3 ) ); }
    26912687        ;
  • src/ResolvExpr/CandidateFinder.cpp

    r7042c60 rcf191ac  
    14121412        }
    14131413
    1414         void Finder::postvisit(const ast::VariableExpr *variableExpr) {
    1415                 // not sufficient to just pass `variableExpr` here, type might have changed
    1416 
    1417                 auto cand = new Candidate(variableExpr, tenv);
    1418                 candidates.emplace_back(cand);
    1419         }
     1414    void Finder::postvisit(const ast::VariableExpr *variableExpr) {
     1415        // not sufficient to just pass `variableExpr` here, type might have changed
     1416
     1417        auto cand = new Candidate(variableExpr, tenv);
     1418        candidates.emplace_back(cand);
     1419    }
    14201420
    14211421        void Finder::postvisit( const ast::ConstantExpr * constantExpr ) {
     
    21332133
    21342134// get the valueE(...) ApplicationExpr that returns the enum value
    2135 const ast::Expr * getValueEnumCall(
    2136         const ast::Expr * expr,
     2135const ast::Expr * getValueEnumCall( 
     2136        const ast::Expr * expr, 
    21372137        const ResolvExpr::ResolveContext & context, const ast::TypeEnvironment & env ) {
    21382138                auto callExpr = new ast::UntypedExpr(
  • src/ResolvExpr/CommonType.cc

    r7042c60 rcf191ac  
    3636namespace ResolvExpr {
    3737
    38 namespace {
    39 
    4038        // GENERATED START, DO NOT EDIT
    4139        // GENERATED BY BasicTypes-gen.cc
     
    399397                        }
    400398                } else if ( auto type2AsAttr = dynamic_cast< const ast::EnumAttrType * >( type2 ) ) {
    401                         if ( type2AsAttr->attr == ast::EnumAttribute::Posn ) {
    402                                 ast::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::SignedInt ];
    403                                 if (
    404                                         ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
    405                                                 || widen.first )
    406                                         && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
    407                                                 || widen.second )
    408                                 ) {
    409                                         result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
    410                                 }
    411                         }
     399            if ( type2AsAttr->attr == ast::EnumAttribute::Posn ) {
     400                            ast::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::SignedInt ];
     401                            if (
     402                                    ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
     403                                            || widen.first )
     404                                    && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
     405                                            || widen.second )
     406                            ) {
     407                                    result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
     408                            }
     409            }
    412410                }
    413411        }
     
    521519                                                                // xxx - assume LHS is always the target type
    522520
    523                                                                 if ( ! ((widen.second && ref2->qualifiers.is_mutex)
     521                                                                if ( ! ((widen.second && ref2->qualifiers.is_mutex) 
    524522                                                                || (ref1->qualifiers.is_mutex == ref2->qualifiers.is_mutex ))) return;
    525523
     
    712710// size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType");
    713711
    714 ast::ptr< ast::Type > handleReference(
    715         const ast::ptr< ast::Type > & t1, const ast::ptr< ast::Type > & t2, WidenMode widen,
    716         ast::TypeEnvironment & env,
    717         const ast::OpenVarSet & open
    718 ) {
    719         ast::ptr<ast::Type> common;
    720         ast::AssertionSet have, need;
    721         ast::OpenVarSet newOpen( open );
    722 
    723         // need unify to bind type variables
    724         if ( unify( t1, t2, env, have, need, newOpen, common ) ) {
    725                 ast::CV::Qualifiers q1 = t1->qualifiers, q2 = t2->qualifiers;
     712namespace {
     713        ast::ptr< ast::Type > handleReference(
     714                const ast::ptr< ast::Type > & t1, const ast::ptr< ast::Type > & t2, WidenMode widen,
     715                ast::TypeEnvironment & env,
     716                const ast::OpenVarSet & open
     717        ) {
     718                ast::ptr<ast::Type> common;
     719                ast::AssertionSet have, need;
     720                ast::OpenVarSet newOpen{ open };
     721
     722                // need unify to bind type variables
     723                if ( unify( t1, t2, env, have, need, newOpen, common ) ) {
     724                        ast::CV::Qualifiers q1 = t1->qualifiers, q2 = t2->qualifiers;
     725                        PRINT(
     726                                std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
     727                        )
     728                        if ( ( widen.first || q2 <= q1 ) && ( widen.second || q1 <= q2 ) ) {
     729                                PRINT(
     730                                        std::cerr << "widen okay" << std::endl;
     731                                )
     732                                add_qualifiers( common, q1 | q2 );
     733                                return common;
     734                        }
     735                }
     736
    726737                PRINT(
    727                         std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
     738                        std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
    728739                )
    729                 if ( ( widen.first || q2 <= q1 ) && ( widen.second || q1 <= q2 ) ) {
    730                         PRINT(
    731                                 std::cerr << "widen okay" << std::endl;
    732                         )
    733                         add_qualifiers( common, q1 | q2 );
    734                         return common;
    735                 }
    736         }
    737 
    738         PRINT(
    739                 std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
    740         )
    741         return { nullptr };
     740                return { nullptr };
     741        }
    742742}
    743 
    744 } // namespace
    745743
    746744ast::ptr< ast::Type > commonType(
     
    783781        }
    784782        // otherwise both are reference types of the same depth and this is handled by the visitor
    785         return ast::Pass<CommonType>::read( type1.get(),
    786                 type2, widen, env, open, need, have );
     783        ast::Pass<CommonType> visitor{ type2, widen, env, open, need, have };
     784        type1->accept( visitor );
     785        // ast::ptr< ast::Type > result = visitor.core.result;
     786
     787        return visitor.core.result;
    787788}
    788789
  • src/ResolvExpr/ConversionCost.cc

    r7042c60 rcf191ac  
    3131#define PRINT(x)
    3232#endif
    33 
    34 namespace {
    3533
    3634        // GENERATED START, DO NOT EDIT
     
    154152        );
    155153
     154namespace {
    156155        int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
    157156                        const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
     
    380379
    381380void ConversionCost::postvisit( const ast::EnumAttrType * src ) {
    382         auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
     381    auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
    383382        assert( src->attr != ast::EnumAttribute::Label );
    384         if ( src->attr == ast::EnumAttribute::Value ) {
    385                 if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Value) {
    386                         cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
    387                 } else {
    388                         auto baseType = src->instance->base->base;
    389                         cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );
     383    if ( src->attr == ast::EnumAttribute::Value ) {
     384        if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Value) {
     385            cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
     386        } else {
     387            auto baseType = src->instance->base->base;
     388            cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );
    390389                        if ( cost < Cost::infinity ) {
    391390                                cost.incUnsafe();
    392391                        }
    393                 }
    394         } else { // ast::EnumAttribute::Posn
    395                 if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
    396                         cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
    397                         if ( cost < Cost::unsafe ) cost.incSafe();
    398                 } else {
    399                         static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::SignedInt ) };
    400                         cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
    401                         if ( cost < Cost::unsafe ) {
    402                                 cost.incSafe();
    403                         }
    404                 }
    405         }
     392        }
     393    } else { // ast::EnumAttribute::Posn
     394        if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
     395                    cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
     396                    if ( cost < Cost::unsafe ) cost.incSafe();
     397            } else {
     398                    static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::SignedInt ) };
     399                    cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
     400                    if ( cost < Cost::unsafe ) {
     401                            cost.incSafe();
     402                    }
     403            }
     404    }
    406405}
    407406
  • src/ResolvExpr/PolyCost.cc

    r7042c60 rcf191ac  
    2929        const ast::TypeEnvironment &env_;
    3030
    31         PolyCost( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
     31        PolyCost( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) 
    3232        : symtab( symtab ), result( 0 ), env_( env ) {}
    3333
    3434        void previsit( const ast::TypeInstType * type ) {
    35                 if ( const ast::EqvClass * eqv = env_.lookup( *type ) ; eqv && eqv->bound ) {
     35                if ( const ast::EqvClass * eqv = env_.lookup( *type ) ) /* && */ if ( eqv->bound ) {
    3636                        if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) {
    3737                                if ( symtab.lookupType( otherType->name ) ) {
    3838                                        // Bound to opaque type.
    39                                         result = 1;
     39                                        result += 1;
    4040                                }
    4141                        } else {
    4242                                // Bound to concrete type.
    43                                 result = 1;
     43                                result += 1;
    4444                        }
    4545                }
     
    5252        const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    5353) {
    54         return ast::Pass<PolyCost>::read( type, symtab, env );
     54        ast::Pass<PolyCost> costing( symtab, env );
     55        type->accept( costing );
     56        return (costing.core.result > 0) ? 1 : 0;
    5557}
    5658
  • src/ResolvExpr/RenameVars.cc

    r7042c60 rcf191ac  
    3030
    3131namespace {
     32        class RenamingData {
     33                int level = 0;
     34                int resetCount = 0;
    3235
    33 class RenamingData {
    34         int level = 0;
    35         int resetCount = 0;
    36 
    37         int next_expr_id = 1;
    38         int next_usage_id = 1;
    39         ScopedMap< std::string, std::string > nameMap;
    40         ScopedMap< std::string, ast::TypeEnvKey > idMap;
    41 public:
    42         void reset() {
    43                 level = 0;
    44                 ++resetCount;
    45         }
    46 
    47         void nextUsage() {
    48                 ++next_usage_id;
    49         }
    50 
    51         const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
    52                 auto it = idMap.find( type->name );
    53                 if ( it == idMap.end() ) return type;
    54 
    55                 // Unconditionally mutate because map will *always* have different name.
    56                 ast::TypeInstType * mut = ast::shallowCopy( type );
    57                 // Reconcile base node since some copies might have been made.
    58                 mut->base = it->second.base;
    59                 mut->formal_usage = it->second.formal_usage;
    60                 mut->expr_id = it->second.expr_id;
    61                 return mut;
    62         }
    63 
    64         const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
    65                 if ( type->forall.empty() ) return type;
    66                 idMap.beginScope();
    67 
    68                 // Load new names from this forall clause and perform renaming.
    69                 auto mutType = ast::shallowCopy( type );
    70                 // assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
    71                 for ( auto & td : mutType->forall ) {
    72                         auto mut = ast::shallowCopy( td.get() );
    73                         // assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
    74 
    75                         if ( mode == GEN_EXPR_ID ) {
    76                                 mut->expr_id = next_expr_id;
    77                                 mut->formal_usage = -1;
    78                                 ++next_expr_id;
    79                         } else if ( mode == GEN_USAGE ) {
    80                                 assertf( mut->expr_id, "unfilled expression id in generating candidate type" );
    81                                 mut->formal_usage = next_usage_id;
    82                         } else {
    83                                 assert(false);
    84                         }
    85                         idMap[ td->name ] = ast::TypeEnvKey( *mut );
    86 
    87                         td = mut;
     36                int next_expr_id = 1;
     37                int next_usage_id = 1;
     38                ScopedMap< std::string, std::string > nameMap;
     39                ScopedMap< std::string, ast::TypeEnvKey > idMap;
     40        public:
     41                void reset() {
     42                        level = 0;
     43                        ++resetCount;
    8844                }
    8945
    90                 return mutType;
    91         }
     46                void nextUsage() {
     47                        ++next_usage_id;
     48                }
    9249
    93         void closeLevel( const ast::FunctionType * type ) {
    94                 if ( type->forall.empty() ) return;
    95                 idMap.endScope();
    96         }
    97 };
     50                const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
     51                        auto it = idMap.find( type->name );
     52                        if ( it == idMap.end() ) return type;
    9853
    99 // Global State:
    100 RenamingData renaming;
     54                        // Unconditionally mutate because map will *always* have different name.
     55                        ast::TypeInstType * mut = ast::shallowCopy( type );
     56                        // Reconcile base node since some copies might have been made.
     57                        mut->base = it->second.base;
     58                        mut->formal_usage = it->second.formal_usage;
     59                        mut->expr_id = it->second.expr_id;
     60                        return mut;
     61                }
    10162
    102 struct RenameVars final : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
    103         RenameMode mode;
     63                const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
     64                        if ( type->forall.empty() ) return type;
     65                        idMap.beginScope();
    10466
    105         const ast::FunctionType * previsit( const ast::FunctionType * type ) {
    106                 return renaming.openLevel( type, mode );
    107         }
     67                        // Load new names from this forall clause and perform renaming.
     68                        auto mutType = ast::shallowCopy( type );
     69                        // assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
     70                        for ( auto & td : mutType->forall ) {
     71                                auto mut = ast::shallowCopy( td.get() );
     72                                // assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
    10873
    109         /*
    110         const ast::StructInstType * previsit( const ast::StructInstType * type ) {
    111                 return renaming.openLevel( type );
    112         }
    113         const ast::UnionInstType * previsit( const ast::UnionInstType * type ) {
    114                 return renaming.openLevel( type );
    115         }
    116         const ast::TraitInstType * previsit( const ast::TraitInstType * type ) {
    117                 return renaming.openLevel( type );
    118         }
    119         */
     74                                if (mode == GEN_EXPR_ID) {
     75                                        mut->expr_id = next_expr_id;
     76                                        mut->formal_usage = -1;
     77                                        ++next_expr_id;
     78                                }
     79                                else if (mode == GEN_USAGE) {
     80                                        assertf(mut->expr_id, "unfilled expression id in generating candidate type");
     81                                        mut->formal_usage = next_usage_id;
     82                                }
     83                                else {
     84                                        assert(false);
     85                                }
     86                                idMap[ td->name ] = ast::TypeEnvKey( *mut );
    12087
    121         const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
    122                 // Do not rename an actual type.
    123                 if ( mode == GEN_USAGE && !type->formal_usage ) return type;
    124                 return renaming.rename( type );
    125         }
    126         void postvisit( const ast::FunctionType * type ) {
    127                 renaming.closeLevel( type );
    128         }
    129 };
     88                                td = mut;
     89                        }
     90
     91                        return mutType;
     92                }
     93
     94                void closeLevel( const ast::FunctionType * type ) {
     95                        if ( type->forall.empty() ) return;
     96                        idMap.endScope();
     97                }
     98        };
     99
     100        // Global State:
     101        RenamingData renaming;
     102
     103        struct RenameVars final : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
     104                RenameMode mode;
     105
     106                const ast::FunctionType * previsit( const ast::FunctionType * type ) {
     107                        return renaming.openLevel( type, mode );
     108                }
     109
     110                /*
     111                const ast::StructInstType * previsit( const ast::StructInstType * type ) {
     112                        return renaming.openLevel( type );
     113                }
     114                const ast::UnionInstType * previsit( const ast::UnionInstType * type ) {
     115                        return renaming.openLevel( type );
     116                }
     117                const ast::TraitInstType * previsit( const ast::TraitInstType * type ) {
     118                        return renaming.openLevel( type );
     119                }
     120                */
     121
     122                const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
     123                        if (mode == GEN_USAGE && !type->formal_usage) return type; // do not rename an actual type
     124                        return renaming.rename( type );
     125                }
     126                void postvisit( const ast::FunctionType * type ) {
     127                        renaming.closeLevel( type );
     128                }
     129        };
    130130
    131131} // namespace
  • src/ResolvExpr/Unify.cc

    r7042c60 rcf191ac  
    4747namespace ResolvExpr {
    4848
    49 bool typesCompatible(
    50                 const ast::Type * first, const ast::Type * second,
    51                 const ast::TypeEnvironment & env ) {
    52         ast::TypeEnvironment newEnv;
    53         ast::OpenVarSet open, closed;
    54         ast::AssertionSet need, have;
    55 
    56         ast::ptr<ast::Type> newFirst( first ), newSecond( second );
    57         env.apply( newFirst );
    58         env.apply( newSecond );
    59 
    60         // findOpenVars( newFirst, open, closed, need, have, FirstClosed );
    61         findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen );
    62 
    63         return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
    64 }
    65 
    66 bool typesCompatibleIgnoreQualifiers(
    67                 const ast::Type * first, const ast::Type * second,
    68                 const ast::TypeEnvironment & env ) {
    69         ast::TypeEnvironment newEnv;
    70         ast::OpenVarSet open;
    71         ast::AssertionSet need, have;
    72 
    73         ast::Type * newFirst  = shallowCopy( first  );
    74         ast::Type * newSecond = shallowCopy( second );
    75 
    76         newFirst ->qualifiers = {};
    77         newSecond->qualifiers = {};
    78         ast::ptr< ast::Type > t1_(newFirst );
    79         ast::ptr< ast::Type > t2_(newSecond);
    80 
    81         ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
    82         ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
    83 
    84         return unifyExact(
    85                 subFirst,
    86                 subSecond,
    87                 newEnv, need, have, open, noWiden() );
    88 }
    89 
    90 namespace {
    91         /// Replaces ttype variables with their bound types.
    92         /// If this isn't done when satifying ttype assertions, then argument lists can have
    93         /// different size and structure when they should be compatible.
    94         struct TtypeExpander : public ast::WithShortCircuiting, public ast::PureVisitor {
     49        bool typesCompatible(
     50                        const ast::Type * first, const ast::Type * second,
     51                        const ast::TypeEnvironment & env ) {
     52                ast::TypeEnvironment newEnv;
     53                ast::OpenVarSet open, closed;
     54                ast::AssertionSet need, have;
     55
     56                ast::ptr<ast::Type> newFirst{ first }, newSecond{ second };
     57                env.apply( newFirst );
     58                env.apply( newSecond );
     59
     60                // findOpenVars( newFirst, open, closed, need, have, FirstClosed );
     61                findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen );
     62
     63                return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
     64        }
     65
     66        bool typesCompatibleIgnoreQualifiers(
     67                        const ast::Type * first, const ast::Type * second,
     68                        const ast::TypeEnvironment & env ) {
     69                ast::TypeEnvironment newEnv;
     70                ast::OpenVarSet open;
     71                ast::AssertionSet need, have;
     72
     73                ast::Type * newFirst  = shallowCopy( first  );
     74                ast::Type * newSecond = shallowCopy( second );
     75
     76                newFirst ->qualifiers = {};
     77                newSecond->qualifiers = {};
     78                ast::ptr< ast::Type > t1_(newFirst );
     79                ast::ptr< ast::Type > t2_(newSecond);
     80
     81                ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
     82                ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
     83
     84                return unifyExact(
     85                        subFirst,
     86                        subSecond,
     87                        newEnv, need, have, open, noWiden() );
     88        }
     89
     90        namespace {
     91                                /// Replaces ttype variables with their bound types.
     92                /// If this isn't done when satifying ttype assertions, then argument lists can have
     93                /// different size and structure when they should be compatible.
     94                struct TtypeExpander : public ast::WithShortCircuiting, public ast::PureVisitor {
     95                        ast::TypeEnvironment & tenv;
     96
     97                        TtypeExpander( ast::TypeEnvironment & env ) : tenv( env ) {}
     98
     99                        const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
     100                                if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
     101                                        // expand ttype parameter into its actual type
     102                                        if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
     103                                                return clz->bound;
     104                                        }
     105                                }
     106                                return typeInst;
     107                        }
     108                };
     109        }
     110
     111        std::vector< ast::ptr< ast::Type > > flattenList(
     112                const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
     113        ) {
     114                std::vector< ast::ptr< ast::Type > > dst;
     115                dst.reserve( src.size() );
     116                for ( const auto & d : src ) {
     117                        ast::Pass<TtypeExpander> expander{ env };
     118                        // TtypeExpander pass is impure (may mutate nodes in place)
     119                        // need to make nodes shared to prevent accidental mutation
     120                        ast::ptr<ast::Type> dc = d->accept(expander);
     121                        auto types = flatten( dc );
     122                        for ( ast::ptr< ast::Type > & t : types ) {
     123                                // outermost const, volatile, _Atomic qualifiers in parameters should not play
     124                                // a role in the unification of function types, since they do not determine
     125                                // whether a function is callable.
     126                                // NOTE: **must** consider at least mutex qualifier, since functions can be
     127                                // overloaded on outermost mutex and a mutex function has different
     128                                // requirements than a non-mutex function
     129                                remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
     130                                dst.emplace_back( t );
     131                        }
     132                }
     133                return dst;
     134        }
     135
     136        // Unification of Expressions
     137        //
     138        // Boolean outcome (obvious):  Are they basically spelled the same?
     139        // Side effect of binding variables (subtle):  if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T`
     140        //
     141        // Context:  if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2`
     142        // where the VAREXPR are meant as notational metavariables representing the fact that unification always
     143        // sees distinct ast::VariableExpr objects at these positions
     144
     145        static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
     146                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     147                WidenMode widen );
     148
     149        class UnifyExpr final : public ast::WithShortCircuiting {
     150                const ast::Expr * e2;
    95151                ast::TypeEnvironment & tenv;
    96 
    97                 TtypeExpander( ast::TypeEnvironment & env ) : tenv( env ) {}
    98 
    99                 const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
    100                         if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
    101                                 // expand ttype parameter into its actual type
    102                                 if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
    103                                         return clz->bound;
     152                ast::AssertionSet & need;
     153                ast::AssertionSet & have;
     154                const ast::OpenVarSet & open;
     155                WidenMode widen;
     156        public:
     157                bool result;
     158
     159        private:
     160
     161                void tryMatchOnStaticValue( const ast::Expr * e1 ) {
     162                        Evaluation r1 = eval(e1);
     163                        Evaluation r2 = eval(e2);
     164
     165                        if ( ! r1.hasKnownValue ) return;
     166                        if ( ! r2.hasKnownValue ) return;
     167
     168                        if (r1.knownValue != r2.knownValue) return;
     169
     170                        visit_children = false;
     171                        result = true;
     172                }
     173
     174        public:
     175
     176                void previsit( const ast::Node * ) { assert(false); }
     177
     178                void previsit( const ast::Expr * e1 ) {
     179                        tryMatchOnStaticValue( e1 );
     180                        visit_children = false;
     181                }
     182
     183                void previsit( const ast::CastExpr * e1 ) {
     184                        tryMatchOnStaticValue( e1 );
     185
     186                        if (result) {
     187                                assert (visit_children == false);
     188                        } else {
     189                                assert (visit_children == true);
     190                                visit_children = false;
     191
     192                                auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
     193                                if ( ! e2c ) return;
     194
     195                                // inspect casts' target types
     196                                if ( ! unifyExact(
     197                                        e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
     198
     199                                // inspect casts' inner expressions
     200                                result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
     201                        }
     202                }
     203
     204                void previsit( const ast::VariableExpr * e1 ) {
     205                        tryMatchOnStaticValue( e1 );
     206
     207                        if (result) {
     208                                assert (visit_children == false);
     209                        } else {
     210                                assert (visit_children == true);
     211                                visit_children = false;
     212
     213                                auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
     214                                if ( ! e2v ) return;
     215
     216                                assert(e1->var);
     217                                assert(e2v->var);
     218
     219                                // conservative: variable exprs match if their declarations are represented by the same C++ AST object
     220                                result = (e1->var == e2v->var);
     221                        }
     222                }
     223
     224                void previsit( const ast::SizeofExpr * e1 ) {
     225                        tryMatchOnStaticValue( e1 );
     226
     227                        if (result) {
     228                                assert (visit_children == false);
     229                        } else {
     230                                assert (visit_children == true);
     231                                visit_children = false;
     232
     233                                auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
     234                                if ( ! e2so ) return;
     235
     236                                assert((e1->type != nullptr) ^ (e1->expr != nullptr));
     237                                assert((e2so->type != nullptr) ^ (e2so->expr != nullptr));
     238                                if ( ! (e1->type && e2so->type) )  return;
     239
     240                                // expression unification calls type unification (mutual recursion)
     241                                result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
     242                        }
     243                }
     244
     245                UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need,
     246                        ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
     247                : e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {}
     248        };
     249
     250        static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
     251                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     252                WidenMode widen ) {
     253                assert( e1 && e2 );
     254                return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen );
     255        }
     256
     257        class Unify final : public ast::WithShortCircuiting {
     258                const ast::Type * type2;
     259                ast::TypeEnvironment & tenv;
     260                ast::AssertionSet & need;
     261                ast::AssertionSet & have;
     262                const ast::OpenVarSet & open;
     263                WidenMode widen;
     264        public:
     265                static size_t traceId;
     266                bool result;
     267
     268                Unify(
     269                        const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need,
     270                        ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
     271                : type2(type2), tenv(env), need(need), have(have), open(open), widen(widen),
     272                result(false) {}
     273
     274                void previsit( const ast::Node * ) { visit_children = false; }
     275
     276                void postvisit( const ast::VoidType * vt) {
     277                        result = dynamic_cast< const ast::VoidType * >( type2 )
     278                                || tryToUnifyWithEnumValue(vt, type2, tenv, need, have, open, noWiden());
     279                        ;
     280                }
     281
     282                void postvisit( const ast::BasicType * basic ) {
     283                        if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
     284                                result = basic->kind == basic2->kind;
     285                        }
     286                        result = result || tryToUnifyWithEnumValue(basic, type2, tenv, need, have, open, noWiden());
     287                }
     288
     289                void postvisit( const ast::PointerType * pointer ) {
     290                        if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
     291                                result = unifyExact(
     292                                        pointer->base, pointer2->base, tenv, need, have, open,
     293                                        noWiden());
     294                        }
     295                        result = result || tryToUnifyWithEnumValue(pointer, type2, tenv, need, have, open, noWiden());
     296                }
     297
     298                void postvisit( const ast::ArrayType * array ) {
     299                        auto array2 = dynamic_cast< const ast::ArrayType * >( type2 );
     300                        if ( ! array2 ) return;
     301
     302                        if ( array->isVarLen != array2->isVarLen ) return;
     303                        if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
     304
     305                        if ( array->dimension ) {
     306                                assert( array2->dimension );
     307                                // type unification calls expression unification (mutual recursion)
     308                                if ( ! unify(array->dimension, array2->dimension,
     309                                    tenv, need, have, open, widen) ) return;
     310                        }
     311
     312                        result = unifyExact(
     313                                array->base, array2->base, tenv, need, have, open, noWiden())
     314                                || tryToUnifyWithEnumValue(array, type2, tenv, need, have, open, noWiden());
     315                }
     316
     317                void postvisit( const ast::ReferenceType * ref ) {
     318                        if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
     319                                result = unifyExact(
     320                                        ref->base, ref2->base, tenv, need, have, open, noWiden());
     321                        }
     322                }
     323
     324        private:
     325
     326                template< typename Iter >
     327                static bool unifyTypeList(
     328                        Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
     329                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
     330                ) {
     331                        while ( crnt1 != end1 && crnt2 != end2 ) {
     332                                const ast::Type * t1 = *crnt1;
     333                                const ast::Type * t2 = *crnt2;
     334                                bool isTuple1 = Tuples::isTtype( t1 );
     335                                bool isTuple2 = Tuples::isTtype( t2 );
     336
     337                                // assumes here that ttype *must* be last parameter
     338                                if ( isTuple1 && ! isTuple2 ) {
     339                                        // combine remainder of list2, then unify
     340                                        return unifyExact(
     341                                                t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
     342                                                noWiden() );
     343                                } else if ( ! isTuple1 && isTuple2 ) {
     344                                        // combine remainder of list1, then unify
     345                                        return unifyExact(
     346                                                tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
     347                                                noWiden() );
    104348                                }
    105                         }
    106                         return typeInst;
    107                 }
    108         };
    109 }
    110 
    111 std::vector< ast::ptr< ast::Type > > flattenList(
    112         const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
    113 ) {
    114         std::vector< ast::ptr< ast::Type > > dst;
    115         dst.reserve( src.size() );
    116         for ( const auto & d : src ) {
    117                 ast::Pass<TtypeExpander> expander( env );
    118                 // TtypeExpander pass is impure (may mutate nodes in place)
    119                 // need to make nodes shared to prevent accidental mutation
    120                 ast::ptr<ast::Type> dc = d->accept(expander);
    121                 auto types = flatten( dc );
    122                 for ( ast::ptr< ast::Type > & t : types ) {
    123                         // outermost const, volatile, _Atomic qualifiers in parameters should not play
    124                         // a role in the unification of function types, since they do not determine
    125                         // whether a function is callable.
    126                         // NOTE: **must** consider at least mutex qualifier, since functions can be
    127                         // overloaded on outermost mutex and a mutex function has different
    128                         // requirements than a non-mutex function
    129                         remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
    130                         dst.emplace_back( t );
    131                 }
    132         }
    133         return dst;
    134 }
    135 
    136 // Unification of Expressions
    137 //
    138 // Boolean outcome (obvious):  Are they basically spelled the same?
    139 // Side effect of binding variables (subtle):  if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T`
    140 //
    141 // Context:  if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2`
    142 // where the VAREXPR are meant as notational metavariables representing the fact that unification always
    143 // sees distinct ast::VariableExpr objects at these positions
    144 
    145 static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
    146         ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    147         WidenMode widen );
    148 
    149 class UnifyExpr final : public ast::WithShortCircuiting {
    150         const ast::Expr * e2;
    151         ast::TypeEnvironment & tenv;
    152         ast::AssertionSet & need;
    153         ast::AssertionSet & have;
    154         const ast::OpenVarSet & open;
    155         WidenMode widen;
    156 public:
    157         bool result;
    158 
    159 private:
    160 
    161         void tryMatchOnStaticValue( const ast::Expr * e1 ) {
    162                 Evaluation r1 = eval(e1);
    163                 Evaluation r2 = eval(e2);
    164 
    165                 if ( !r1.hasKnownValue ) return;
    166                 if ( !r2.hasKnownValue ) return;
    167 
    168                 if ( r1.knownValue != r2.knownValue ) return;
    169 
    170                 visit_children = false;
    171                 result = true;
    172         }
    173 
    174 public:
    175 
    176         void previsit( const ast::Node * ) { assert(false); }
    177 
    178         void previsit( const ast::Expr * e1 ) {
    179                 tryMatchOnStaticValue( e1 );
    180                 visit_children = false;
    181         }
    182 
    183         void previsit( const ast::CastExpr * e1 ) {
    184                 tryMatchOnStaticValue( e1 );
    185 
    186                 if ( result ) {
    187                         assert( visit_children == false );
    188                 } else {
    189                         assert( visit_children == true );
    190                         visit_children = false;
    191 
    192                         auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
    193                         if ( !e2c ) return;
    194 
    195                         // inspect casts' target types
    196                         if ( !unifyExact(
    197                                 e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
    198 
    199                         // inspect casts' inner expressions
    200                         result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
    201                 }
    202         }
    203 
    204         void previsit( const ast::VariableExpr * e1 ) {
    205                 tryMatchOnStaticValue( e1 );
    206 
    207                 if ( result ) {
    208                         assert( visit_children == false );
    209                 } else {
    210                         assert( visit_children == true );
    211                         visit_children = false;
    212 
    213                         auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
    214                         if ( !e2v ) return;
    215 
    216                         assert(e1->var);
    217                         assert(e2v->var);
    218 
    219                         // conservative: variable exprs match if their declarations are represented by the same C++ AST object
    220                         result = (e1->var == e2v->var);
    221                 }
    222         }
    223 
    224         void previsit( const ast::SizeofExpr * e1 ) {
    225                 tryMatchOnStaticValue( e1 );
    226 
    227                 if ( result ) {
    228                         assert( visit_children == false );
    229                 } else {
    230                         assert( visit_children == true );
    231                         visit_children = false;
    232 
    233                         auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
    234                         if ( !e2so ) return;
    235 
    236                         assert((e1->type != nullptr) ^ (e1->expr != nullptr));
    237                         assert((e2so->type != nullptr) ^ (e2so->expr != nullptr));
    238                         if ( !(e1->type && e2so->type) ) return;
    239 
    240                         // expression unification calls type unification (mutual recursion)
    241                         result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
    242                 }
    243         }
    244 
    245         UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need,
    246                 ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
    247         : e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {}
    248 };
    249 
    250 static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
    251         ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    252         WidenMode widen ) {
    253         assert( e1 && e2 );
    254         return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen );
    255 }
    256 
    257 class Unify final : public ast::WithShortCircuiting {
    258         const ast::Type * type2;
    259         ast::TypeEnvironment & tenv;
    260         ast::AssertionSet & need;
    261         ast::AssertionSet & have;
    262         const ast::OpenVarSet & open;
    263         WidenMode widen;
    264 public:
    265         static size_t traceId;
    266         bool result;
    267 
    268         Unify(
    269                 const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need,
    270                 ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
    271         : type2(type2), tenv(env), need(need), have(have), open(open), widen(widen),
    272         result(false) {}
    273 
    274         void previsit( const ast::Node * ) { visit_children = false; }
    275 
    276         void postvisit( const ast::VoidType * vt) {
    277                 result = dynamic_cast< const ast::VoidType * >( type2 )
    278                         || tryToUnifyWithEnumValue(vt, type2, tenv, need, have, open, noWiden());
    279                 ;
    280         }
    281 
    282         void postvisit( const ast::BasicType * basic ) {
    283                 if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
    284                         result = basic->kind == basic2->kind;
    285                 }
    286                 result = result || tryToUnifyWithEnumValue(basic, type2, tenv, need, have, open, noWiden());
    287         }
    288 
    289         void postvisit( const ast::PointerType * pointer ) {
    290                 if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
    291                         result = unifyExact(
    292                                 pointer->base, pointer2->base, tenv, need, have, open,
    293                                 noWiden());
    294                 }
    295                 result = result || tryToUnifyWithEnumValue(pointer, type2, tenv, need, have, open, noWiden());
    296         }
    297 
    298         void postvisit( const ast::ArrayType * array ) {
    299                 auto array2 = dynamic_cast< const ast::ArrayType * >( type2 );
    300                 if ( !array2 ) return;
    301 
    302                 if ( array->isVarLen != array2->isVarLen ) return;
    303                 if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
    304 
    305                 if ( array->dimension ) {
    306                         assert( array2->dimension );
    307                         // type unification calls expression unification (mutual recursion)
    308                         if ( !unify(array->dimension, array2->dimension,
    309                                 tenv, need, have, open, widen) ) return;
    310                 }
    311 
    312                 result = unifyExact(
    313                         array->base, array2->base, tenv, need, have, open, noWiden())
    314                         || tryToUnifyWithEnumValue(array, type2, tenv, need, have, open, noWiden());
    315         }
    316 
    317         void postvisit( const ast::ReferenceType * ref ) {
    318                 if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
    319                         result = unifyExact(
    320                                 ref->base, ref2->base, tenv, need, have, open, noWiden());
    321                 }
    322         }
    323 
    324 private:
    325 
    326         template< typename Iter >
    327         static bool unifyTypeList(
    328                 Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
    329                 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
    330         ) {
    331                 while ( crnt1 != end1 && crnt2 != end2 ) {
    332                         const ast::Type * t1 = *crnt1;
    333                         const ast::Type * t2 = *crnt2;
    334                         bool isTuple1 = Tuples::isTtype( t1 );
    335                         bool isTuple2 = Tuples::isTtype( t2 );
    336 
    337                         // assumes here that ttype *must* be last parameter
    338                         if ( isTuple1 && !isTuple2 ) {
    339                                 // combine remainder of list2, then unify
     349
     350                                if ( ! unifyExact(
     351                                        t1, t2, env, need, have, open, noWiden() )
     352                                ) return false;
     353
     354                                ++crnt1; ++crnt2;
     355                        }
     356
     357                        // May get to the end of one argument list before the other. This is only okay if the
     358                        // other is a ttype
     359                        if ( crnt1 != end1 ) {
     360                                // try unifying empty tuple with ttype
     361                                const ast::Type * t1 = *crnt1;
     362                                if ( ! Tuples::isTtype( t1 ) ) return false;
    340363                                return unifyExact(
    341364                                        t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
    342365                                        noWiden() );
    343                         } else if ( !isTuple1 && isTuple2 ) {
    344                                 // combine remainder of list1, then unify
     366                        } else if ( crnt2 != end2 ) {
     367                                // try unifying empty tuple with ttype
     368                                const ast::Type * t2 = *crnt2;
     369                                if ( ! Tuples::isTtype( t2 ) ) return false;
    345370                                return unifyExact(
    346371                                        tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
     
    348373                        }
    349374
    350                         if ( !unifyExact(
    351                                 t1, t2, env, need, have, open, noWiden() )
    352                         ) return false;
    353 
    354                         ++crnt1; ++crnt2;
    355                 }
    356 
    357                 // May get to the end of one argument list before the other. This is only okay if the
    358                 // other is a ttype
    359                 if ( crnt1 != end1 ) {
    360                         // try unifying empty tuple with ttype
    361                         const ast::Type * t1 = *crnt1;
    362                         if ( !Tuples::isTtype( t1 ) ) return false;
    363                         return unifyExact(
    364                                 t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
    365                                 noWiden() );
    366                 } else if ( crnt2 != end2 ) {
    367                         // try unifying empty tuple with ttype
    368                         const ast::Type * t2 = *crnt2;
    369                         if ( !Tuples::isTtype( t2 ) ) return false;
    370                         return unifyExact(
    371                                 tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
    372                                 noWiden() );
    373                 }
    374 
    375                 return true;
    376         }
    377 
    378         static bool unifyTypeList(
    379                 const std::vector< ast::ptr< ast::Type > > & list1,
    380                 const std::vector< ast::ptr< ast::Type > > & list2,
    381                 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    382                 const ast::OpenVarSet & open
     375                        return true;
     376                }
     377
     378                static bool unifyTypeList(
     379                        const std::vector< ast::ptr< ast::Type > > & list1,
     380                        const std::vector< ast::ptr< ast::Type > > & list2,
     381                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     382                        const ast::OpenVarSet & open
     383                ) {
     384                        return unifyTypeList(
     385                                list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open);
     386                }
     387
     388                static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
     389                        auto i = assns.find( assn );
     390                        if ( i != assns.end() ) {
     391                                i->second.isUsed = true;
     392                        }
     393                }
     394
     395                /// mark all assertions in `type` used in both `assn1` and `assn2`
     396                static void markAssertions(
     397                        ast::AssertionSet & assn1, ast::AssertionSet & assn2,
     398                        const ast::FunctionType * type
     399                ) {
     400                        for ( auto & assert : type->assertions ) {
     401                                markAssertionSet( assn1, assert );
     402                                markAssertionSet( assn2, assert );
     403                        }
     404                }
     405
     406                bool tryToUnifyWithEnumValue( const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
     407                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     408                        WidenMode widen) {
     409                        if ( auto attrType2 = dynamic_cast<const ast::EnumAttrType *>(type2)) {
     410                                if (attrType2->attr == ast::EnumAttribute::Value) {
     411                                        return unifyExact( type1, attrType2->instance->base->base, env, need, have, open,
     412                                                widen);
     413                                } else if (attrType2->attr == ast::EnumAttribute::Posn) {
     414                                        return unifyExact( type1, attrType2->instance, env, need, have, open, widen );
     415                                }
     416                        }
     417                        return false;
     418                }
     419
     420        public:
     421                void postvisit( const ast::FunctionType * func ) {
     422                        auto func2 = dynamic_cast< const ast::FunctionType * >( type2 );
     423                        if ( ! func2 ) return;
     424
     425                        if ( func->isVarArgs != func2->isVarArgs ) return;
     426
     427                        // Flatten the parameter lists for both functions so that tuple structure does not
     428                        // affect unification. Does not actually mutate function parameters.
     429                        auto params = flattenList( func->params, tenv );
     430                        auto params2 = flattenList( func2->params, tenv );
     431
     432                        // sizes don't have to match if ttypes are involved; need to be more precise w.r.t.
     433                        // where the ttype is to prevent errors
     434                        if (
     435                                ( params.size() != params2.size() || func->returns.size() != func2->returns.size() )
     436                                && ! func->isTtype()
     437                                && ! func2->isTtype()
     438                        ) return;
     439
     440                        if ( ! unifyTypeList( params, params2, tenv, need, have, open ) ) return;
     441                        if ( ! unifyTypeList(
     442                                func->returns, func2->returns, tenv, need, have, open ) ) return;
     443
     444                        markAssertions( have, need, func );
     445                        markAssertions( have, need, func2 );
     446
     447                        result = true;
     448                }
     449
     450        private:
     451                // Returns: other, cast as XInstType
     452                // Assigns this->result: whether types are compatible (up to generic parameters)
     453                template< typename XInstType >
     454                const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
     455                        // check that the other type is compatible and named the same
     456                        auto otherInst = dynamic_cast< const XInstType * >( other );
     457                        if (otherInst && inst->name == otherInst->name)
     458                                this->result = otherInst;
     459                        return otherInst;
     460                }
     461
     462                /// Creates a tuple type based on a list of TypeExpr
     463                template< typename Iter >
     464                static const ast::Type * tupleFromExprs(
     465                        const ast::TypeExpr * param, Iter & crnt, Iter end, ast::CV::Qualifiers qs
     466                ) {
     467                        std::vector< ast::ptr< ast::Type > > types;
     468                        do {
     469                                types.emplace_back( param->type );
     470
     471                                ++crnt;
     472                                if ( crnt == end ) break;
     473                                param = strict_dynamic_cast< const ast::TypeExpr * >( crnt->get() );
     474                        } while(true);
     475
     476                        return new ast::TupleType{ std::move(types), qs };
     477                }
     478
     479                template< typename XInstType >
     480                void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
     481                        // check that other type is compatible and named the same
     482                        const XInstType * otherInst = handleRefType( inst, other );
     483                        if ( ! this->result ) return;
     484
     485                        // check that parameters of types unify, if any
     486                        const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
     487                        const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
     488
     489                        auto it = params.begin();
     490                        auto jt = params2.begin();
     491                        for ( ; it != params.end() && jt != params2.end(); ++it, ++jt ) {
     492                                auto param = strict_dynamic_cast< const ast::TypeExpr * >( it->get() );
     493                                auto param2 = strict_dynamic_cast< const ast::TypeExpr * >( jt->get() );
     494
     495                                ast::ptr< ast::Type > pty = param->type;
     496                                ast::ptr< ast::Type > pty2 = param2->type;
     497
     498                                bool isTuple = Tuples::isTtype( pty );
     499                                bool isTuple2 = Tuples::isTtype( pty2 );
     500
     501                                if ( isTuple && isTuple2 ) {
     502                                        ++it; ++jt;  // skip ttype parameters before break
     503                                } else if ( isTuple ) {
     504                                        // bundle remaining params into tuple
     505                                        pty2 = tupleFromExprs( param2, jt, params2.end(), pty->qualifiers );
     506                                        ++it;  // skip ttype parameter for break
     507                                } else if ( isTuple2 ) {
     508                                        // bundle remaining params into tuple
     509                                        pty = tupleFromExprs( param, it, params.end(), pty2->qualifiers );
     510                                        ++jt;  // skip ttype parameter for break
     511                                }
     512
     513                                if ( ! unifyExact(
     514                                                pty, pty2, tenv, need, have, open, noWiden() ) ) {
     515                                        result = false;
     516                                        return;
     517                                }
     518
     519                                // ttype parameter should be last
     520                                if ( isTuple || isTuple2 ) break;
     521                        }
     522                        result = it == params.end() && jt == params2.end();
     523                }
     524
     525        public:
     526                void postvisit( const ast::StructInstType * aggrType ) {
     527                        handleGenericRefType( aggrType, type2 );
     528                        result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
     529                }
     530
     531                void postvisit( const ast::UnionInstType * aggrType ) {
     532                        handleGenericRefType( aggrType, type2 );
     533                        result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
     534                }
     535
     536                void postvisit( const ast::EnumInstType * aggrType ) {
     537                        handleRefType( aggrType, type2 );
     538                        result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
     539                }
     540
     541                void postvisit( const ast::EnumAttrType * enumAttr ) {
     542                        // Lazy approach for now
     543                        if ( auto otherPos = dynamic_cast< const ast::EnumAttrType *>(type2) ) {
     544                            if ( enumAttr->match(otherPos) ) {
     545                                    result = otherPos;
     546                            }
     547            } 
     548                }
     549
     550                void postvisit( const ast::TraitInstType * aggrType ) {
     551                        handleRefType( aggrType, type2 );
     552                        result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
     553                }
     554
     555                void postvisit( const ast::TypeInstType * typeInst ) {
     556                        // assert( open.find( *typeInst ) == open.end() );
     557                        auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
     558                        if ( otherInst && typeInst->name == otherInst->name ) {
     559                                this->result = otherInst;
     560                        }
     561                        result = result || tryToUnifyWithEnumValue(typeInst, type2, tenv, need, have, open, noWiden());
     562                }
     563
     564        private:
     565                /// Creates a tuple type based on a list of Type
     566
     567                static bool unifyList(
     568                        const std::vector< ast::ptr< ast::Type > > & list1,
     569                        const std::vector< ast::ptr< ast::Type > > & list2, ast::TypeEnvironment & env,
     570                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
     571                ) {
     572                        auto crnt1 = list1.begin();
     573                        auto crnt2 = list2.begin();
     574                        while ( crnt1 != list1.end() && crnt2 != list2.end() ) {
     575                                const ast::Type * t1 = *crnt1;
     576                                const ast::Type * t2 = *crnt2;
     577                                bool isTuple1 = Tuples::isTtype( t1 );
     578                                bool isTuple2 = Tuples::isTtype( t2 );
     579
     580                                // assumes ttype must be last parameter
     581                                if ( isTuple1 && ! isTuple2 ) {
     582                                        // combine entirety of list2, then unify
     583                                        return unifyExact(
     584                                                t1, tupleFromTypes( list2 ), env, need, have, open,
     585                                                noWiden() );
     586                                } else if ( ! isTuple1 && isTuple2 ) {
     587                                        // combine entirety of list1, then unify
     588                                        return unifyExact(
     589                                                tupleFromTypes( list1 ), t2, env, need, have, open,
     590                                                noWiden() );
     591                                }
     592
     593                                if ( ! unifyExact(
     594                                        t1, t2, env, need, have, open, noWiden() )
     595                                ) return false;
     596
     597                                ++crnt1; ++crnt2;
     598                        }
     599
     600                        if ( crnt1 != list1.end() ) {
     601                                // try unifying empty tuple type with ttype
     602                                const ast::Type * t1 = *crnt1;
     603                                if ( ! Tuples::isTtype( t1 ) ) return false;
     604                                // xxx - this doesn't generate an empty tuple, contrary to comment; both ported
     605                                // from Rob's code
     606                                return unifyExact(
     607                                                t1, tupleFromTypes( list2 ), env, need, have, open,
     608                                                noWiden() );
     609                        } else if ( crnt2 != list2.end() ) {
     610                                // try unifying empty tuple with ttype
     611                                const ast::Type * t2 = *crnt2;
     612                                if ( ! Tuples::isTtype( t2 ) ) return false;
     613                                // xxx - this doesn't generate an empty tuple, contrary to comment; both ported
     614                                // from Rob's code
     615                                return unifyExact(
     616                                                tupleFromTypes( list1 ), t2, env, need, have, open,
     617                                                noWiden() );
     618                        }
     619
     620                        return true;
     621                }
     622
     623        public:
     624                void postvisit( const ast::TupleType * tuple ) {
     625                        auto tuple2 = dynamic_cast< const ast::TupleType * >( type2 );
     626                        if ( ! tuple2 ) return;
     627
     628                        ast::Pass<TtypeExpander> expander{ tenv };
     629
     630                        const ast::Type * flat = tuple->accept( expander );
     631                        const ast::Type * flat2 = tuple2->accept( expander );
     632
     633                        auto types = flatten( flat );
     634                        auto types2 = flatten( flat2 );
     635
     636                        result = unifyList( types, types2, tenv, need, have, open )
     637                                || tryToUnifyWithEnumValue(tuple, type2, tenv, need, have, open, noWiden());
     638                }
     639
     640                void postvisit( const ast::VarArgsType * vat) {
     641                        result = dynamic_cast< const ast::VarArgsType * >( type2 )
     642                                || tryToUnifyWithEnumValue(vat, type2, tenv, need, have, open, noWiden());
     643                }
     644
     645                void postvisit( const ast::ZeroType * zt) {
     646                        result = dynamic_cast< const ast::ZeroType * >( type2 )
     647                                || tryToUnifyWithEnumValue(zt, type2, tenv, need, have, open, noWiden());
     648                }
     649
     650                void postvisit( const ast::OneType * ot) {
     651                        result = dynamic_cast< const ast::OneType * >( type2 )
     652                                || tryToUnifyWithEnumValue(ot, type2, tenv, need, have, open, noWiden());
     653                }
     654        };
     655
     656        // size_t Unify::traceId = Stats::Heap::new_stacktrace_id("Unify");
     657
     658        bool unify(
     659                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     660                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     661                        ast::OpenVarSet & open
    383662        ) {
    384                 return unifyTypeList(
    385                         list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open);
    386         }
    387 
    388         static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
    389                 auto i = assns.find( assn );
    390                 if ( i != assns.end() ) {
    391                         i->second.isUsed = true;
    392                 }
    393         }
    394 
    395         /// mark all assertions in `type` used in both `assn1` and `assn2`
    396         static void markAssertions(
    397                 ast::AssertionSet & assn1, ast::AssertionSet & assn2,
    398                 const ast::FunctionType * type
     663                ast::ptr<ast::Type> common;
     664                return unify( type1, type2, env, need, have, open, common );
     665        }
     666
     667        bool unify(
     668                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     669                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     670                        ast::OpenVarSet & open, ast::ptr<ast::Type> & common
    399671        ) {
    400                 for ( auto & assert : type->assertions ) {
    401                         markAssertionSet( assn1, assert );
    402                         markAssertionSet( assn2, assert );
    403                 }
    404         }
    405 
    406         bool tryToUnifyWithEnumValue( const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
    407                 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    408                 WidenMode widen) {
    409                 if ( auto attrType2 = dynamic_cast<const ast::EnumAttrType *>(type2)) {
    410                         if (attrType2->attr == ast::EnumAttribute::Value) {
    411                                 return unifyExact( type1, attrType2->instance->base->base, env, need, have, open,
    412                                         widen);
    413                         } else if (attrType2->attr == ast::EnumAttribute::Posn) {
    414                                 return unifyExact( type1, attrType2->instance, env, need, have, open, widen );
    415                         }
    416                 }
    417                 return false;
    418         }
    419 
    420 public:
    421         void postvisit( const ast::FunctionType * func ) {
    422                 auto func2 = dynamic_cast< const ast::FunctionType * >( type2 );
    423                 if ( !func2 ) return;
    424 
    425                 if ( func->isVarArgs != func2->isVarArgs ) return;
    426 
    427                 // Flatten the parameter lists for both functions so that tuple structure does not
    428                 // affect unification. Does not actually mutate function parameters.
    429                 auto params = flattenList( func->params, tenv );
    430                 auto params2 = flattenList( func2->params, tenv );
    431 
    432                 // sizes don't have to match if ttypes are involved; need to be more precise w.r.t.
    433                 // where the ttype is to prevent errors
    434                 if (
    435                         ( params.size() != params2.size() || func->returns.size() != func2->returns.size() )
    436                         && !func->isTtype()
    437                         && !func2->isTtype()
    438                 ) return;
    439 
    440                 if ( !unifyTypeList( params, params2, tenv, need, have, open ) ) return;
    441                 if ( !unifyTypeList(
    442                         func->returns, func2->returns, tenv, need, have, open ) ) return;
    443 
    444                 markAssertions( have, need, func );
    445                 markAssertions( have, need, func2 );
    446 
    447                 result = true;
    448         }
    449 
    450 private:
    451         // Returns: other, cast as XInstType
    452         // Assigns this->result: whether types are compatible (up to generic parameters)
    453         template< typename XInstType >
    454         const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
    455                 // check that the other type is compatible and named the same
    456                 auto otherInst = dynamic_cast< const XInstType * >( other );
    457                 if ( otherInst && inst->name == otherInst->name ) {
    458                         this->result = otherInst;
    459                 }
    460                 return otherInst;
    461         }
    462 
    463         /// Creates a tuple type based on a list of TypeExpr
    464         template< typename Iter >
    465         static const ast::Type * tupleFromExprs(
    466                 const ast::TypeExpr * param, Iter & crnt, Iter end, ast::CV::Qualifiers qs
     672                ast::OpenVarSet closed;
     673                // findOpenVars( type1, open, closed, need, have, FirstClosed );
     674                findOpenVars( type2, open, closed, need, have, env, FirstOpen );
     675                return unifyInexact(
     676                        type1, type2, env, need, have, open, WidenMode{ true, true }, common );
     677        }
     678
     679        bool unifyExact(
     680                        const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
     681                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     682                        WidenMode widen
    467683        ) {
    468                 std::vector< ast::ptr< ast::Type > > types;
    469                 do {
    470                         types.emplace_back( param->type );
    471 
    472                         ++crnt;
    473                         if ( crnt == end ) break;
    474                         param = strict_dynamic_cast< const ast::TypeExpr * >( crnt->get() );
    475                 } while(true);
    476 
    477                 return new ast::TupleType( std::move(types), qs );
    478         }
    479 
    480         template< typename XInstType >
    481         void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
    482                 // check that other type is compatible and named the same
    483                 const XInstType * otherInst = handleRefType( inst, other );
    484                 if ( !this->result ) return;
    485 
    486                 // check that parameters of types unify, if any
    487                 const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
    488                 const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
    489 
    490                 auto it = params.begin();
    491                 auto jt = params2.begin();
    492                 for ( ; it != params.end() && jt != params2.end(); ++it, ++jt ) {
    493                         auto param = strict_dynamic_cast< const ast::TypeExpr * >( it->get() );
    494                         auto param2 = strict_dynamic_cast< const ast::TypeExpr * >( jt->get() );
    495 
    496                         ast::ptr< ast::Type > pty = param->type;
    497                         ast::ptr< ast::Type > pty2 = param2->type;
    498 
    499                         bool isTuple = Tuples::isTtype( pty );
    500                         bool isTuple2 = Tuples::isTtype( pty2 );
    501 
    502                         if ( isTuple && isTuple2 ) {
    503                                 ++it; ++jt;  // skip ttype parameters before break
    504                         } else if ( isTuple ) {
    505                                 // bundle remaining params into tuple
    506                                 pty2 = tupleFromExprs( param2, jt, params2.end(), pty->qualifiers );
    507                                 ++it;  // skip ttype parameter for break
    508                         } else if ( isTuple2 ) {
    509                                 // bundle remaining params into tuple
    510                                 pty = tupleFromExprs( param, it, params.end(), pty2->qualifiers );
    511                                 ++jt;  // skip ttype parameter for break
    512                         }
    513 
    514                         if ( !unifyExact(
    515                                         pty, pty2, tenv, need, have, open, noWiden() ) ) {
    516                                 result = false;
    517                                 return;
    518                         }
    519 
    520                         // ttype parameter should be last
    521                         if ( isTuple || isTuple2 ) break;
    522                 }
    523                 result = it == params.end() && jt == params2.end();
    524         }
    525 
    526 public:
    527         void postvisit( const ast::StructInstType * aggrType ) {
    528                 handleGenericRefType( aggrType, type2 );
    529                 result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
    530         }
    531 
    532         void postvisit( const ast::UnionInstType * aggrType ) {
    533                 handleGenericRefType( aggrType, type2 );
    534                 result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
    535         }
    536 
    537         void postvisit( const ast::EnumInstType * aggrType ) {
    538                 handleRefType( aggrType, type2 );
    539                 result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
    540         }
    541 
    542         void postvisit( const ast::EnumAttrType * enumAttr ) {
    543                 // Lazy approach for now
    544                 if ( auto otherPos = dynamic_cast< const ast::EnumAttrType *>( type2 ) ) {
    545                         if ( enumAttr->match(otherPos) ) {
    546                                 result = otherPos;
    547                         }
    548                 }
    549         }
    550 
    551         void postvisit( const ast::TraitInstType * aggrType ) {
    552                 handleRefType( aggrType, type2 );
    553                 result = result || tryToUnifyWithEnumValue(aggrType, type2, tenv, need, have, open, noWiden());
    554         }
    555 
    556         void postvisit( const ast::TypeInstType * typeInst ) {
    557                 // assert( open.find( *typeInst ) == open.end() );
    558                 auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
    559                 if ( otherInst && typeInst->name == otherInst->name ) {
    560                         this->result = otherInst;
    561                 }
    562                 result = result || tryToUnifyWithEnumValue(typeInst, type2, tenv, need, have, open, noWiden());
    563         }
    564 
    565 private:
    566         /// Creates a tuple type based on a list of Type
    567         static bool unifyList(
    568                 const std::vector< ast::ptr< ast::Type > > & list1,
    569                 const std::vector< ast::ptr< ast::Type > > & list2, ast::TypeEnvironment & env,
    570                 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
     684                if ( type1->qualifiers != type2->qualifiers ) return false;
     685
     686                auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
     687                auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
     688                bool isopen1 = var1 && env.lookup(*var1);
     689                bool isopen2 = var2 && env.lookup(*var2);
     690
     691                if ( isopen1 && isopen2 ) {
     692                        if ( var1->base->kind != var2->base->kind ) return false;
     693                        return env.bindVarToVar(
     694                                var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have,
     695                                open, widen );
     696                } else if ( isopen1 ) {
     697                        return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen );
     698                } else if ( isopen2 ) {
     699                        return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
     700                } else {
     701                        return ast::Pass<Unify>::read(
     702                                type1, type2, env, need, have, open, widen );
     703                }
     704        }
     705
     706        bool unifyInexact(
     707                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     708                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     709                        const ast::OpenVarSet & open, WidenMode widen,
     710                        ast::ptr<ast::Type> & common
    571711        ) {
    572                 auto crnt1 = list1.begin();
    573                 auto crnt2 = list2.begin();
    574                 while ( crnt1 != list1.end() && crnt2 != list2.end() ) {
    575                         const ast::Type * t1 = *crnt1;
    576                         const ast::Type * t2 = *crnt2;
    577                         bool isTuple1 = Tuples::isTtype( t1 );
    578                         bool isTuple2 = Tuples::isTtype( t2 );
    579 
    580                         // assumes ttype must be last parameter
    581                         if ( isTuple1 && !isTuple2 ) {
    582                                 // combine entirety of list2, then unify
    583                                 return unifyExact(
    584                                         t1, tupleFromTypes( list2 ), env, need, have, open,
    585                                         noWiden() );
    586                         } else if ( !isTuple1 && isTuple2 ) {
    587                                 // combine entirety of list1, then unify
    588                                 return unifyExact(
    589                                         tupleFromTypes( list1 ), t2, env, need, have, open,
    590                                         noWiden() );
    591                         }
    592 
    593                         if ( !unifyExact(
    594                                 t1, t2, env, need, have, open, noWiden() )
    595                         ) return false;
    596 
    597                         ++crnt1; ++crnt2;
    598                 }
    599 
    600                 if ( crnt1 != list1.end() ) {
    601                         // try unifying empty tuple type with ttype
    602                         const ast::Type * t1 = *crnt1;
    603                         if ( !Tuples::isTtype( t1 ) ) return false;
    604                         // xxx - this doesn't generate an empty tuple, contrary to comment; both ported
    605                         // from Rob's code
    606                         return unifyExact(
    607                                         t1, tupleFromTypes( list2 ), env, need, have, open,
    608                                         noWiden() );
    609                 } else if ( crnt2 != list2.end() ) {
    610                         // try unifying empty tuple with ttype
    611                         const ast::Type * t2 = *crnt2;
    612                         if ( !Tuples::isTtype( t2 ) ) return false;
    613                         // xxx - this doesn't generate an empty tuple, contrary to comment; both ported
    614                         // from Rob's code
    615                         return unifyExact(
    616                                         tupleFromTypes( list1 ), t2, env, need, have, open,
    617                                         noWiden() );
    618                 }
    619 
    620                 return true;
    621         }
    622 
    623 public:
    624         void postvisit( const ast::TupleType * tuple ) {
    625                 auto tuple2 = dynamic_cast< const ast::TupleType * >( type2 );
    626                 if ( ! tuple2 ) return;
    627 
    628                 ast::Pass<TtypeExpander> expander{ tenv };
    629 
    630                 const ast::Type * flat = tuple->accept( expander );
    631                 const ast::Type * flat2 = tuple2->accept( expander );
    632 
    633                 auto types = flatten( flat );
    634                 auto types2 = flatten( flat2 );
    635 
    636                 result = unifyList( types, types2, tenv, need, have, open )
    637                         || tryToUnifyWithEnumValue(tuple, type2, tenv, need, have, open, noWiden());
    638         }
    639 
    640         void postvisit( const ast::VarArgsType * vat) {
    641                 result = dynamic_cast< const ast::VarArgsType * >( type2 )
    642                         || tryToUnifyWithEnumValue(vat, type2, tenv, need, have, open, noWiden());
    643         }
    644 
    645         void postvisit( const ast::ZeroType * zt) {
    646                 result = dynamic_cast< const ast::ZeroType * >( type2 )
    647                         || tryToUnifyWithEnumValue(zt, type2, tenv, need, have, open, noWiden());
    648         }
    649 
    650         void postvisit( const ast::OneType * ot) {
    651                 result = dynamic_cast< const ast::OneType * >( type2 )
    652                         || tryToUnifyWithEnumValue(ot, type2, tenv, need, have, open, noWiden());
    653         }
    654 };
    655 
    656 // size_t Unify::traceId = Stats::Heap::new_stacktrace_id("Unify");
    657 
    658 bool unify(
    659                 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    660                 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    661                 ast::OpenVarSet & open
    662 ) {
    663         ast::ptr<ast::Type> common;
    664         return unify( type1, type2, env, need, have, open, common );
    665 }
    666 
    667 bool unify(
    668                 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    669                 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    670                 ast::OpenVarSet & open, ast::ptr<ast::Type> & common
    671 ) {
    672         ast::OpenVarSet closed;
    673         // findOpenVars( type1, open, closed, need, have, FirstClosed );
    674         findOpenVars( type2, open, closed, need, have, env, FirstOpen );
    675         return unifyInexact(
    676                 type1, type2, env, need, have, open, WidenMode{ true, true }, common );
    677 }
    678 
    679 bool unifyExact(
    680                 const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
    681                 ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
    682                 WidenMode widen
    683 ) {
    684         if ( type1->qualifiers != type2->qualifiers ) return false;
    685 
    686         auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
    687         auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
    688         bool isopen1 = var1 && env.lookup(*var1);
    689         bool isopen2 = var2 && env.lookup(*var2);
    690 
    691         if ( isopen1 && isopen2 ) {
    692                 if ( var1->base->kind != var2->base->kind ) return false;
    693                 return env.bindVarToVar(
    694                         var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have,
    695                         open, widen );
    696         } else if ( isopen1 ) {
    697                 return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen );
    698         } else if ( isopen2 ) {
    699                 return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
    700         } else {
    701                 return ast::Pass<Unify>::read(
    702                         type1, type2, env, need, have, open, widen );
    703         }
    704 }
    705 
    706 bool unifyInexact(
    707                 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
    708                 ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
    709                 const ast::OpenVarSet & open, WidenMode widen,
    710                 ast::ptr<ast::Type> & common
    711 ) {
    712         ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
    713 
    714         // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
    715         // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
    716         ast::Type * t1 = shallowCopy(type1.get());
    717         ast::Type * t2 = shallowCopy(type2.get());
    718         t1->qualifiers = {};
    719         t2->qualifiers = {};
    720         ast::ptr< ast::Type > t1_(t1);
    721         ast::ptr< ast::Type > t2_(t2);
    722 
    723         if ( unifyExact( t1, t2, env, need, have, open, widen ) ) {
    724                 // if exact unification on unqualified types, try to merge qualifiers
    725                 if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
    726                         t1->qualifiers = q1 | q2;
    727                         common = t1;
     712                ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
     713
     714                // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
     715                // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
     716                ast::Type * t1 = shallowCopy(type1.get());
     717                ast::Type * t2 = shallowCopy(type2.get());
     718                t1->qualifiers = {};
     719                t2->qualifiers = {};
     720                ast::ptr< ast::Type > t1_(t1);
     721                ast::ptr< ast::Type > t2_(t2);
     722
     723                if ( unifyExact( t1, t2, env, need, have, open, widen ) ) {
     724                        // if exact unification on unqualified types, try to merge qualifiers
     725                        if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
     726                                t1->qualifiers = q1 | q2;
     727                                common = t1;
     728                                return true;
     729                        } else {
     730                                return false;
     731                        }
     732
     733                } else if (( common = commonType( t1, t2, env, need, have, open, widen ))) {
     734                        // no exact unification, but common type
     735                        auto c = shallowCopy(common.get());
     736                        c->qualifiers = q1 | q2;
     737                        common = c;
    728738                        return true;
    729739                } else {
    730740                        return false;
    731741                }
    732         } else if (( common = commonType( t1, t2, env, need, have, open, widen ))) {
    733                 // no exact unification, but common type
    734                 auto c = shallowCopy(common.get());
    735                 c->qualifiers = q1 | q2;
    736                 common = c;
    737                 return true;
    738         } else {
    739                 return false;
    740         }
    741 }
    742 
    743 ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
    744         if ( func->returns.empty() ) return new ast::VoidType();
    745         if ( func->returns.size() == 1 ) return func->returns[0];
    746 
    747         std::vector<ast::ptr<ast::Type>> tys;
    748         for ( const auto & decl : func->returns ) {
    749                 tys.emplace_back( decl );
    750         }
    751         return new ast::TupleType( std::move(tys) );
    752 }
    753 
     742        }
     743
     744        ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
     745                if ( func->returns.empty() ) return new ast::VoidType{};
     746                if ( func->returns.size() == 1 ) return func->returns[0];
     747
     748                std::vector<ast::ptr<ast::Type>> tys;
     749                for ( const auto & decl : func->returns ) {
     750                        tys.emplace_back( decl );
     751                }
     752                return new ast::TupleType{ std::move(tys) };
     753        }
    754754} // namespace ResolvExpr
    755755
  • src/ResolvExpr/typeops.h

    r7042c60 rcf191ac  
    2121
    2222namespace ResolvExpr {
     23        class TypeEnvironment;
    2324
    24 class TypeEnvironment;
     25        // combos: takes a list of sets and returns a set of lists representing every possible way of forming a list by
     26        // picking one element out of each set
     27        template< typename InputIterator, typename OutputIterator >
     28        void combos( InputIterator begin, InputIterator end, OutputIterator out ) {
     29                typedef typename InputIterator::value_type SetType;
     30                typedef typename std::vector< typename SetType::value_type > ListType;
    2531
    26 // combos: takes a list of sets and returns a set of lists representing every possible way of forming a list by
    27 // picking one element out of each set
    28 template< typename InputIterator, typename OutputIterator >
    29 void combos( InputIterator begin, InputIterator end, OutputIterator out ) {
    30         typedef typename InputIterator::value_type SetType;
    31         typedef typename std::vector< typename SetType::value_type > ListType;
     32                if ( begin == end )     {
     33                        *out++ = ListType();
     34                        return;
     35                } // if
    3236
    33         if ( begin == end )     {
    34                 *out++ = ListType();
    35                 return;
    36         } // if
     37                InputIterator current = begin;
     38                begin++;
    3739
    38         InputIterator current = begin;
    39         begin++;
     40                std::vector< ListType > recursiveResult;
     41                combos( begin, end, back_inserter( recursiveResult ) );
    4042
    41         std::vector< ListType > recursiveResult;
    42         combos( begin, end, back_inserter( recursiveResult ) );
    43 
    44         for ( const auto& i : recursiveResult ) for ( const auto& j : *current ) {
    45                 ListType result;
    46                 std::back_insert_iterator< ListType > inserter = back_inserter( result );
    47                 *inserter++ = j;
    48                 std::copy( i.begin(), i.end(), inserter );
    49                 *out++ = result;
    50         }
    51 }
    52 
    53 /// Flatten tuple type into existing list of types.
    54 inline void flatten(
    55         const ast::Type * type, std::vector< ast::ptr< ast::Type > > & out
    56 ) {
    57         if ( auto tupleType = dynamic_cast< const ast::TupleType * >( type ) ) {
    58                 for ( const ast::Type * t : tupleType->types ) {
    59                         flatten( t, out );
     43                for ( const auto& i : recursiveResult ) for ( const auto& j : *current ) {
     44                        ListType result;
     45                        std::back_insert_iterator< ListType > inserter = back_inserter( result );
     46                        *inserter++ = j;
     47                        std::copy( i.begin(), i.end(), inserter );
     48                        *out++ = result;
    6049                }
    61         } else {
    62                 out.emplace_back( type );
    63         }
    64 }
    65 
    66 /// Flatten tuple type into list of types.
    67 inline std::vector< ast::ptr< ast::Type > > flatten( const ast::Type * type ) {
    68         std::vector< ast::ptr< ast::Type > > out;
    69         out.reserve( type->size() );
    70         flatten( type, out );
    71         return out;
    72 }
    73 
    74 template< typename Iter >
    75 const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
    76         std::vector< ast::ptr< ast::Type > > types;
    77         while ( crnt != end ) {
    78                 // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
    79                 // that this results in a flat tuple
    80                 flatten( *crnt, types );
    81 
    82                 ++crnt;
    8350        }
    8451
    85         return new ast::TupleType( std::move(types) );
    86 }
     52        /// flatten tuple type into existing list of types
     53        inline void flatten(
     54                const ast::Type * type, std::vector< ast::ptr< ast::Type > > & out
     55        ) {
     56                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( type ) ) {
     57                        for ( const ast::Type * t : tupleType->types ) {
     58                                flatten( t, out );
     59                        }
     60                } else {
     61                        out.emplace_back( type );
     62                }
     63        }
    8764
    88 inline const ast::Type * tupleFromTypes(
    89         const std::vector< ast::ptr< ast::Type > > & tys
    90 ) {
    91         return tupleFromTypes( tys.begin(), tys.end() );
    92 }
     65        /// flatten tuple type into list of types
     66        inline std::vector< ast::ptr< ast::Type > > flatten( const ast::Type * type ) {
     67                std::vector< ast::ptr< ast::Type > > out;
     68                out.reserve( type->size() );
     69                flatten( type, out );
     70                return out;
     71        }
    9372
     73        template< typename Iter >
     74        const ast::Type * tupleFromTypes( Iter crnt, Iter end ) {
     75                std::vector< ast::ptr< ast::Type > > types;
     76                while ( crnt != end ) {
     77                        // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
     78                        // that this results in a flat tuple
     79                        flatten( *crnt, types );
     80
     81                        ++crnt;
     82                }
     83
     84                return new ast::TupleType{ std::move(types) };
     85        }
     86
     87        inline const ast::Type * tupleFromTypes(
     88                const std::vector< ast::ptr< ast::Type > > & tys
     89        ) {
     90                return tupleFromTypes( tys.begin(), tys.end() );
     91        }
    9492} // namespace ResolvExpr
    9593
  • src/SymTab/Mangler.cc

    r7042c60 rcf191ac  
    283283        postvisit( enumAttr->instance );
    284284        // mangleName += "_pos";
    285         switch ( enumAttr->attr )
    286         {
    287                 case ast::EnumAttribute::Label:
    288                         mangleName += "_label_";
    289                         break;
    290                 case ast::EnumAttribute::Posn:
     285    switch ( enumAttr->attr )
     286    {
     287        case ast::EnumAttribute::Label:
     288            mangleName += "_label_";
     289            break;
     290        case ast::EnumAttribute::Posn:
    291291                        mangleName += "_posn_";
    292                         break;
    293                 case ast::EnumAttribute::Value:
    294                         mangleName += "_value_";
    295                         break;
    296         }
     292            break;
     293        case ast::EnumAttribute::Value:
     294            mangleName += "_value_";
     295            break;
     296    }
    297297
    298298}
  • src/Validate/ForallPointerDecay.hpp

    r7042c60 rcf191ac  
    3939/// Expand all traits in an assertion list.
    4040std::vector<ast::ptr<ast::DeclWithType>> expandAssertions(
    41                 std::vector<ast::ptr<ast::DeclWithType>> const & );
     41        std::vector<ast::ptr<ast::DeclWithType>> const & );
    4242
    4343}
  • src/Validate/HoistStruct.cpp

    r7042c60 rcf191ac  
    149149template<typename InstType>
    150150InstType const * HoistStructCore::preCollectionInstType( InstType const * type ) {
    151         if ( !type->base->parent ) return type;
    152         if ( type->base->params.empty() ) return type;
    153 
    154         InstType * mut = ast::mutate( type );
    155         ast::AggregateDecl const * parent =
    156                 commonParent( this->parent, mut->base->parent );
    157         assert( parent );
    158 
    159         std::vector<ast::ptr<ast::Expr>> args;
    160         for ( const ast::ptr<ast::TypeDecl> & param : parent->params ) {
    161                 args.emplace_back( new ast::TypeExpr( param->location,
    162                         new ast::TypeInstType( param )
    163                 ) );
    164         }
    165         spliceBegin( mut->params, args );
    166         return mut;
     151    if ( !type->base->parent ) return type;
     152    if ( type->base->params.empty() ) return type;
     153
     154    InstType * mut = ast::mutate( type );
     155    ast::AggregateDecl const * parent =
     156        commonParent( this->parent, mut->base->parent );
     157    assert( parent );
     158
     159    std::vector<ast::ptr<ast::Expr>> args;
     160    for ( const ast::ptr<ast::TypeDecl> & param : parent->params ) {
     161        args.emplace_back( new ast::TypeExpr( param->location,
     162            new ast::TypeInstType( param )
     163        ) );
     164    }
     165    spliceBegin( mut->params, args );
     166    return mut;
    167167}
    168168
  • src/Validate/ImplementEnumFunc.cpp

    r7042c60 rcf191ac  
    88namespace {
    99class EnumAttrFuncGenerator {
    10         const ast::EnumDecl* decl;
    11         const ast::EnumInstType* instType;
    12         unsigned int functionNesting;
    13         ast::Linkage::Spec proto_linkage;
    14 
    15 public:
    16         std::list<ast::ptr<ast::Decl>> forwards;
    17         std::list<ast::ptr<ast::Decl>> definitions;
    18 
    19         void generateAndAppendFunctions(std::list<ast::ptr<ast::Decl>>&);
    20 
    21         EnumAttrFuncGenerator(
    22                         const ast::EnumDecl* decl,
    23                         const ast::EnumInstType* instType,
    24                         unsigned int functionNesting )
    25                 : decl(decl),
    26                   instType{instType},
    27                   functionNesting{functionNesting},
    28                   proto_linkage{ast::Linkage::Cforall} {}
    29 
    30         void genAttrFunctions();
    31         void genSuccPredPosn();
    32         void genSuccPredDecl();
    33 
    34         void appendReturnThis(ast::FunctionDecl* decl) {
    35                 assert(1 <= decl->params.size());
    36                 assert(1 == decl->returns.size());
    37                 assert(decl->stmts);
    38 
    39                 const CodeLocation& location = (decl->stmts->kids.empty())
    40                                                    ? decl->stmts->location
    41                                                    : decl->stmts->kids.back()->location;
    42                 const ast::DeclWithType* thisParam = decl->params.front();
    43                 decl->stmts.get_and_mutate()->push_back(new ast::ReturnStmt(
    44                         location, new ast::VariableExpr(location, thisParam)));
    45         }
    46         void genAttrStandardFuncs() {
    47                 ast::FunctionDecl* (EnumAttrFuncGenerator::*standardProtos[4])()
    48                         const = {&EnumAttrFuncGenerator::genCtorProto,
    49                                          &EnumAttrFuncGenerator::genCopyProto,
    50                                          &EnumAttrFuncGenerator::genDtorProto,
    51                                          &EnumAttrFuncGenerator::genAssignProto};
    52                 for (auto& generator : standardProtos) {
    53                         ast::FunctionDecl* decl = (this->*generator)();
    54                         produceForwardDecl(decl);
    55                         genFuncBody(decl);
    56                         if (CodeGen::isAssignment(decl->name)) {
    57                                 appendReturnThis(decl);
    58                         }
    59                         produceDecl(decl);
    60                 }
    61         }
    62 
    63 private:
    64         const CodeLocation& getLocation() const { return decl->location; }
    65 
    66         ast::FunctionDecl* genProto(
    67                 std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
    68                 std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
    69 
    70         void produceDecl(const ast::FunctionDecl* decl);
    71         void produceForwardDecl(const ast::FunctionDecl* decl);
    72 
    73         const ast::Decl* getDecl() const { return decl; }
    74 
    75         ast::FunctionDecl* genPosnProto() const;
    76         ast::FunctionDecl* genLabelProto() const;
    77         ast::FunctionDecl* genValueProto() const;
    78         ast::FunctionDecl* genSuccProto() const;
    79         ast::FunctionDecl* genPredProto() const;
    80 
    81         ast::FunctionDecl* genSuccPosProto() const;
    82         ast::FunctionDecl* genPredPosProto() const;
    83 
    84         // ---------------------------------------------------
    85         // ast::FunctionDecl* genAttrCtorProto() const;
    86         /// Changes the node inside a pointer so that it has the unused attribute.
    87         void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
    88                 ast::DeclWithType* decl = declPtr.get_and_mutate();
    89                 decl->attributes.push_back(new ast::Attribute("unused"));
    90         }
    91 
    92         ast::ObjectDecl* dstParam() const {
    93                 return new ast::ObjectDecl(getLocation(), "_dst",
    94                                            new ast::ReferenceType(new ast::EnumAttrType(
    95                                                ast::deepCopy(instType))));
    96         }
    97 
    98         ast::ObjectDecl* srcParam() const {
    99                 return new ast::ObjectDecl(
    100                         getLocation(), "_src",
    101                         new ast::EnumAttrType(ast::deepCopy(instType)));
    102         }
    103 
    104         /// E = EnumAttrType<T>`
    105         /// `void ?{}(E & _dst)`.
    106         ast::FunctionDecl* genCtorProto() const {
    107                 return genProto("?{}", {dstParam()}, {});
    108         }
    109 
    110         /// void ?{}(E & _dst, E _src)`.
    111         ast::FunctionDecl* genCopyProto() const {
    112                 return genProto("?{}", {dstParam(), srcParam()}, {});
    113         }
    114 
    115         ///`void ^?{}(E & _dst)`.
    116         ast::FunctionDecl* genDtorProto() const {
    117                 // The destructor must be mutex on a concurrent type.
    118                 return genProto("^?{}", {dstParam()}, {});
    119         }
    120 
    121         /// `E ?{}(E & _dst, E _src)`.
    122         ast::FunctionDecl* genAssignProto() const {
    123                 // Only the name is different, so just reuse the generation function.
    124                 auto retval = srcParam();
    125                 retval->name = "_ret";
    126                 return genProto("?=?", {dstParam(), srcParam()}, {retval});
    127         }
    128 
    129         void genFuncBody(ast::FunctionDecl* func) {
    130                 const CodeLocation& location = func->location;
    131                 auto& params = func->params;
    132                 if (InitTweak::isCopyConstructor(func) ||
    133                         InitTweak::isAssignment(func)) {
    134                         assert(2 == params.size());
    135                         auto dstParam = params.front().strict_as<ast::ObjectDecl>();
    136                         auto srcParam = params.back().strict_as<ast::ObjectDecl>();
    137                         func->stmts = genCopyBody(location, dstParam, srcParam);
    138                 } else {
    139                         assert(1 == params.size());
    140                         // Default constructor and destructor is empty.
    141                         func->stmts = new ast::CompoundStmt(location);
    142                         // Add unused attribute to parameter to silence warnings.
    143                         addUnusedAttribute(params.front());
    144 
    145                         // Just an extra step to make the forward and declaration match.
    146                         if (forwards.empty()) return;
    147                         ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
    148                                 forwards.back().get_and_mutate());
    149                         addUnusedAttribute(fwd->params.front());
    150                 }
    151         }
    152 
    153         const ast::CompoundStmt* genCopyBody( const CodeLocation& location,
    154                         const ast::ObjectDecl* dstParam, const ast::ObjectDecl* srcParam) {
    155                 return new ast::CompoundStmt(
    156                         location,
    157                         {new ast::ExprStmt(
    158                                 location,
    159                                 new ast::UntypedExpr(
    160                                         location, new ast::NameExpr(location, "__builtin_memcpy"),
    161                                         {
    162                                                 new ast::AddressExpr( location,
    163                                                         new ast::VariableExpr( location, dstParam ) ),
    164                                                 new ast::AddressExpr( location,
    165                                                         new ast::VariableExpr( location, srcParam ) ),
    166                                                 new ast::SizeofExpr( location, srcParam->type ),
    167                                         }))});
    168         }
    169 
    170         void genDtorBody(ast::FunctionDecl* func) {
    171                 const CodeLocation& location = func->location;
    172                 auto& params = func->params;
    173                 assert(1 == params.size());
    174                 func->stmts = new ast::CompoundStmt(location);
    175                 addUnusedAttribute(params.front());
    176 
    177                 // Just an extra step to make the forward and declaration match.
    178                 if (forwards.empty()) return;
    179                 ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
    180                         forwards.back().get_and_mutate());
    181                 addUnusedAttribute(fwd->params.front());
    182         }
    183 
    184         // ast::FunctionDecl*
    185         // ----------------------------------------------------
    186 
    187         ast::FunctionDecl* genSuccPredFunc(bool succ);
    188 
    189         const ast::Init* getAutoInit(const ast::Init* prev) const;
    190 
    191         std::vector<ast::ptr<ast::Init>> genLabelInit() const;
    192 
    193         std::vector<ast::ptr<ast::Init>> genValueInit() const;
    194         ast::ObjectDecl* genAttrArrayProto(
    195                 const ast::EnumAttribute attr, const CodeLocation& location,
    196                 std::vector<ast::ptr<ast::Init>>& inits) const;
    197         void genValueOrLabelBody(
    198                 ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
    199         void genPosnBody(ast::FunctionDecl* func) const;
    200         void genAttributesDecls(const ast::EnumAttribute attr);
     10    const ast::EnumDecl* decl;
     11    const ast::EnumInstType* instType;
     12    // const ast::EnumAttrType* attrType;
     13    unsigned int functionNesting;
     14    ast::Linkage::Spec proto_linkage;
     15
     16   public:
     17    std::list<ast::ptr<ast::Decl>> forwards;
     18    std::list<ast::ptr<ast::Decl>> definitions;
     19
     20    void generateAndAppendFunctions(std::list<ast::ptr<ast::Decl>>&);
     21
     22    EnumAttrFuncGenerator(const ast::EnumDecl* decl,
     23                          const ast::EnumInstType* instType,
     24                          // const ast::EnumAttrType* enumAttrType,
     25                          unsigned int functionNesting)
     26        : decl(decl),
     27          instType{instType},
     28          // attrType{enumAttrType},
     29          functionNesting{functionNesting},
     30          proto_linkage{ast::Linkage::Cforall} {}
     31
     32    void genAttrFunctions();
     33    void genSuccPredPosn();
     34    void genSuccPredDecl();
     35
     36    void appendReturnThis(ast::FunctionDecl* decl) {
     37        assert(1 <= decl->params.size());
     38        assert(1 == decl->returns.size());
     39        assert(decl->stmts);
     40
     41        const CodeLocation& location = (decl->stmts->kids.empty())
     42                                           ? decl->stmts->location
     43                                           : decl->stmts->kids.back()->location;
     44        const ast::DeclWithType* thisParam = decl->params.front();
     45        decl->stmts.get_and_mutate()->push_back(new ast::ReturnStmt(
     46            location, new ast::VariableExpr(location, thisParam)));
     47    }
     48    void genAttrStandardFuncs() {
     49        ast::FunctionDecl* (EnumAttrFuncGenerator::*standardProtos[4])()
     50            const = {&EnumAttrFuncGenerator::genCtorProto,
     51                     &EnumAttrFuncGenerator::genCopyProto,
     52                     &EnumAttrFuncGenerator::genDtorProto,
     53                     &EnumAttrFuncGenerator::genAssignProto};
     54        for (auto& generator : standardProtos) {
     55            ast::FunctionDecl* decl = (this->*generator)();
     56            produceForwardDecl(decl);
     57            genFuncBody(decl);
     58            if (CodeGen::isAssignment(decl->name)) {
     59                appendReturnThis(decl);
     60            }
     61            produceDecl(decl);
     62        }
     63    }
     64
     65   private:
     66    const CodeLocation& getLocation() const { return decl->location; }
     67
     68    ast::FunctionDecl* genProto(
     69        std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
     70        std::vector<ast::ptr<ast::DeclWithType>>&& returns) const;
     71
     72    void produceDecl(const ast::FunctionDecl* decl);
     73    void produceForwardDecl(const ast::FunctionDecl* decl);
     74
     75    const ast::Decl* getDecl() const { return decl; }
     76
     77    ast::FunctionDecl* genPosnProto() const;
     78    ast::FunctionDecl* genLabelProto() const;
     79    ast::FunctionDecl* genValueProto() const;
     80    ast::FunctionDecl* genSuccProto() const;
     81    ast::FunctionDecl* genPredProto() const;
     82
     83    ast::FunctionDecl* genSuccPosProto() const;
     84    ast::FunctionDecl* genPredPosProto() const;
     85
     86    // ---------------------------------------------------
     87    // ast::FunctionDecl* genAttrCtorProto() const;
     88    /// Changes the node inside a pointer so that it has the unused attribute.
     89    void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
     90        ast::DeclWithType* decl = declPtr.get_and_mutate();
     91        decl->attributes.push_back(new ast::Attribute("unused"));
     92    }
     93
     94    ast::ObjectDecl* dstParam() const {
     95        return new ast::ObjectDecl(getLocation(), "_dst",
     96                                   new ast::ReferenceType(new ast::EnumAttrType(
     97                                       ast::deepCopy(instType))));
     98    }
     99
     100    ast::ObjectDecl* srcParam() const {
     101        return new ast::ObjectDecl(
     102            getLocation(), "_src",
     103            new ast::EnumAttrType(ast::deepCopy(instType)));
     104    }
     105
     106    /// E = EnumAttrType<T>`
     107    /// `void ?{}(E & _dst)`.
     108    ast::FunctionDecl* genCtorProto() const {
     109        return genProto("?{}", {dstParam()}, {});
     110    }
     111
     112    /// void ?{}(E & _dst, E _src)`.
     113    ast::FunctionDecl* genCopyProto() const {
     114        return genProto("?{}", {dstParam(), srcParam()}, {});
     115    }
     116
     117    ///`void ^?{}(E & _dst)`.
     118    ast::FunctionDecl* genDtorProto() const {
     119        // The destructor must be mutex on a concurrent type.
     120        return genProto("^?{}", {dstParam()}, {});
     121    }
     122
     123    /// `E ?{}(E & _dst, E _src)`.
     124    ast::FunctionDecl* genAssignProto() const {
     125        // Only the name is different, so just reuse the generation function.
     126        auto retval = srcParam();
     127        retval->name = "_ret";
     128        return genProto("?=?", {dstParam(), srcParam()}, {retval});
     129    }
     130
     131    void genFuncBody(ast::FunctionDecl* func) {
     132        const CodeLocation& location = func->location;
     133        auto& params = func->params;
     134        if (InitTweak::isCopyConstructor(func) ||
     135            InitTweak::isAssignment(func)) {
     136            assert(2 == params.size());
     137            auto dstParam = params.front().strict_as<ast::ObjectDecl>();
     138            auto srcParam = params.back().strict_as<ast::ObjectDecl>();
     139            func->stmts = genCopyBody(location, dstParam, srcParam);
     140        } else {
     141            assert(1 == params.size());
     142            // Default constructor and destructor is empty.
     143            func->stmts = new ast::CompoundStmt(location);
     144            // Add unused attribute to parameter to silence warnings.
     145            addUnusedAttribute(params.front());
     146
     147            // Just an extra step to make the forward and declaration match.
     148            if (forwards.empty()) return;
     149            ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
     150                forwards.back().get_and_mutate());
     151            addUnusedAttribute(fwd->params.front());
     152        }
     153    }
     154
     155    const ast::CompoundStmt* genCopyBody(const CodeLocation& location,
     156                                         const ast::ObjectDecl* dstParam,
     157                                         const ast::ObjectDecl* srcParam) {
     158        return new ast::CompoundStmt(
     159            location,
     160            {new ast::ExprStmt(
     161                location,
     162                new ast::UntypedExpr(
     163                    location, new ast::NameExpr(location, "__builtin_memcpy"),
     164                    {
     165                        new ast::AddressExpr(location, new ast::VariableExpr(
     166                                                           location, dstParam)),
     167                        new ast::AddressExpr(location, new ast::VariableExpr(
     168                                                           location, srcParam)),
     169                        new ast::SizeofExpr(location, srcParam->type),
     170                    }))});
     171    }
     172
     173    void genDtorBody(ast::FunctionDecl* func) {
     174        const CodeLocation& location = func->location;
     175        auto& params = func->params;
     176        assert(1 == params.size());
     177        func->stmts = new ast::CompoundStmt(location);
     178        addUnusedAttribute(params.front());
     179
     180        // Just an extra step to make the forward and declaration match.
     181        if (forwards.empty()) return;
     182        ast::FunctionDecl* fwd = strict_dynamic_cast<ast::FunctionDecl*>(
     183            forwards.back().get_and_mutate());
     184        addUnusedAttribute(fwd->params.front());
     185    }
     186
     187    // ast::FunctionDecl*
     188    // ----------------------------------------------------
     189
     190    ast::FunctionDecl* genSuccPredFunc(bool succ);
     191
     192    const ast::Init* getAutoInit(const ast::Init* prev) const;
     193
     194    std::vector<ast::ptr<ast::Init>> genLabelInit() const;
     195
     196    std::vector<ast::ptr<ast::Init>> genValueInit() const;
     197    ast::ObjectDecl* genAttrArrayProto(
     198        const ast::EnumAttribute attr, const CodeLocation& location,
     199        std::vector<ast::ptr<ast::Init>>& inits) const;
     200    void genValueOrLabelBody(ast::FunctionDecl* func,
     201                             ast::ObjectDecl* arrDecl) const;
     202    void genPosnBody(ast::FunctionDecl* func) const;
     203    void genAttributesDecls(const ast::EnumAttribute attr);
    201204};
    202205
    203206std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
    204         std::vector<ast::ptr<ast::Init>> inits;
    205         for (size_t i = 0; i < decl->members.size(); i++) {
    206                 ast::ptr<ast::Decl> mem = decl->members.at(i);
    207                 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
    208                 assert(memAsObjectDecl);
    209                 inits.emplace_back(new ast::SingleInit(
    210                         mem->location,
    211                         ast::ConstantExpr::from_string(mem->location, mem->name)));
    212         }
    213         return inits;
     207    std::vector<ast::ptr<ast::Init>> inits;
     208    for (size_t i = 0; i < decl->members.size(); i++) {
     209        ast::ptr<ast::Decl> mem = decl->members.at(i);
     210        auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
     211        assert(memAsObjectDecl);
     212        inits.emplace_back(new ast::SingleInit(
     213            mem->location,
     214            ast::ConstantExpr::from_string(mem->location, mem->name)));
     215    }
     216    return inits;
    214217}
    215218
    216219std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
    217         std::vector<ast::ptr<ast::Init>> inits;
    218         for (size_t i = 0; i < decl->members.size(); i++) {
    219                 ast::ptr<ast::Decl> mem = decl->members.at(i);
    220                 auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
    221                 assert(memAsObjectDecl);
    222                 if (memAsObjectDecl->init) {
    223                         inits.emplace_back(memAsObjectDecl->init);
    224                 } else {
    225                         const CodeLocation& location = mem->location;
    226                         if (i == 0) {
    227                                 inits.emplace_back(new ast::SingleInit(
    228                                         location, ast::ConstantExpr::from_int(mem->location, 0)));
    229                         } else {
    230                                 inits.emplace_back(getAutoInit(inits.at(i - 1)));
    231                         }
    232                 }
    233         }
    234         return inits;
     220    std::vector<ast::ptr<ast::Init>> inits;
     221    for (size_t i = 0; i < decl->members.size(); i++) {
     222        ast::ptr<ast::Decl> mem = decl->members.at(i);
     223        auto memAsObjectDecl = mem.as<ast::ObjectDecl>();
     224        assert(memAsObjectDecl);
     225        if (memAsObjectDecl->init) {
     226            inits.emplace_back(memAsObjectDecl->init);
     227        } else {
     228            const CodeLocation& location = mem->location;
     229            if (i == 0) {
     230                inits.emplace_back(new ast::SingleInit(
     231                    location, ast::ConstantExpr::from_int(mem->location, 0)));
     232            } else {
     233                inits.emplace_back(getAutoInit(inits.at(i - 1)));
     234            }
     235        }
     236    }
     237    return inits;
    235238}
    236239const ast::Init* EnumAttrFuncGenerator::getAutoInit(
    237         const ast::Init* prev) const {
    238         if (prev == nullptr) {
    239                 return new ast::SingleInit(
    240                         getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
    241         }
    242         auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
    243         assert(prevInit);
    244         auto prevInitExpr = prevInit->value;
    245         if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
    246                 // Assume no string literal for now
    247                 return new ast::SingleInit(
    248                         getLocation(), ast::ConstantExpr::from_int(
    249                                 getLocation(), constInit->intValue() + 1));
    250         } else {
    251                 auto untypedThisInit = new ast::UntypedExpr(
    252                         getLocation(), new ast::NameExpr(getLocation(), "?++"),
    253                         {prevInitExpr});
    254                 return new ast::SingleInit(getLocation(), untypedThisInit);
    255         }
     240    const ast::Init* prev) const {
     241    if (prev == nullptr) {
     242        return new ast::SingleInit(
     243            getLocation(), ast::ConstantExpr::from_int(getLocation(), 0));
     244    }
     245    auto prevInit = dynamic_cast<const ast::SingleInit*>(prev);
     246    assert(prevInit);
     247    auto prevInitExpr = prevInit->value;
     248    if (auto constInit = prevInitExpr.as<ast::ConstantExpr>()) {
     249        // Assume no string literal for now
     250        return new ast::SingleInit(
     251            getLocation(), ast::ConstantExpr::from_int(
     252                               getLocation(), constInit->intValue() + 1));
     253    } else {
     254        auto untypedThisInit = new ast::UntypedExpr(
     255            getLocation(), new ast::NameExpr(getLocation(), "?++"),
     256            {prevInitExpr});
     257        return new ast::SingleInit(getLocation(), untypedThisInit);
     258    }
    256259}
    257260
    258261ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
    259         std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
    260         std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
    261         ast::FunctionDecl* decl = new ast::FunctionDecl(
    262                 // Auto-generated routines use the type declaration's location.
    263                 getLocation(), std::move(name), {}, {}, std::move(params),
    264                 std::move(returns),
    265                 // Only a prototype, no body.
    266                 nullptr,
    267                 // Use static storage if we are at the top level.
    268                 (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
    269                 proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
    270                 // Auto-generated routines are inline to avoid conflicts.
    271                 ast::Function::Specs(ast::Function::Inline));
    272         decl->fixUniqueId();
    273         return decl;
     262    std::string&& name, std::vector<ast::ptr<ast::DeclWithType>>&& params,
     263    std::vector<ast::ptr<ast::DeclWithType>>&& returns) const {
     264    ast::FunctionDecl* decl = new ast::FunctionDecl(
     265        // Auto-generated routines use the type declaration's location.
     266        getLocation(), std::move(name), {}, {}, std::move(params),
     267        std::move(returns),
     268        // Only a prototype, no body.
     269        nullptr,
     270        // Use static storage if we are at the top level.
     271        (0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
     272        proto_linkage, std::vector<ast::ptr<ast::Attribute>>(),
     273        // Auto-generated routines are inline to avoid conflicts.
     274        ast::Function::Specs(ast::Function::Inline));
     275    decl->fixUniqueId();
     276    return decl;
    274277}
    275278
    276279void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
    277         assert(nullptr != decl->stmts);
    278 
    279         definitions.push_back(decl);
     280    assert(nullptr != decl->stmts);
     281
     282    definitions.push_back(decl);
    280283}
    281284
    282285void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
    283         if (0 != functionNesting) return;
    284         ast::FunctionDecl* fwd =
    285                 (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
    286         fwd->fixUniqueId();
    287         forwards.push_back(fwd);
     286    if (0 != functionNesting) return;
     287    ast::FunctionDecl* fwd =
     288        (decl->stmts) ? ast::asForward(decl) : ast::deepCopy(decl);
     289    fwd->fixUniqueId();
     290    forwards.push_back(fwd);
    288291}
    289292
     
    297300
    298301ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
    299         return genProto(
    300                 "labelE",
    301                 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
    302                 {new ast::ObjectDecl(
    303                         getLocation(), "_ret",
    304                         new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
     302    return genProto(
     303        "labelE",
     304        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
     305        {new ast::ObjectDecl(
     306            getLocation(), "_ret",
     307            new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
    305308}
    306309
    307310ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
    308         return genProto(
    309                 "valueE",
    310                 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
    311                 {new ast::ObjectDecl(getLocation(), "_ret",
    312                                      ast::deepCopy(decl->base))});
     311    return genProto(
     312        "valueE",
     313        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
     314        {new ast::ObjectDecl(getLocation(), "_ret",
     315                             ast::deepCopy(decl->base))});
    313316}
    314317
    315318ast::FunctionDecl* EnumAttrFuncGenerator::genSuccProto() const {
    316         return genProto(
    317                 "succ",
    318                 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
    319                 {new ast::ObjectDecl(getLocation(), "_ret",
    320                                      new ast::EnumInstType(decl))});
     319    return genProto(
     320        "succ",
     321        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
     322        {new ast::ObjectDecl(getLocation(), "_ret",
     323                             new ast::EnumInstType(decl))});
    321324}
    322325
    323326ast::FunctionDecl* EnumAttrFuncGenerator::genPredProto() const {
    324         return genProto(
    325                 "pred",
    326                 {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
    327                 {new ast::ObjectDecl(getLocation(), "_ret",
    328                                      new ast::EnumInstType(decl))});
     327    return genProto(
     328        "pred",
     329        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
     330        {new ast::ObjectDecl(getLocation(), "_ret",
     331                             new ast::EnumInstType(decl))});
    329332}
    330333
    331334inline ast::EnumAttrType * getPosnType( const ast::EnumDecl * decl ) {
    332         return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
     335    return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
    333336}
    334337
    335338ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPosProto() const {
    336         return genProto(
    337                 "_successor_",
    338                 {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
    339                 {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
    340         );
     339    return genProto(
     340        "_successor_",
     341        {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
     342        {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
     343    );
    341344}
    342345
    343346ast::FunctionDecl* EnumAttrFuncGenerator::genPredPosProto() const {
    344         return genProto(
    345                 "_predessor_",
    346                 {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
    347                 {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
    348         );
     347    return genProto(
     348        "_predessor_",
     349        {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
     350        {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
     351    );
    349352}
    350353
    351354ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
    352         const ast::EnumAttribute attr, const CodeLocation& location,
    353         std::vector<ast::ptr<ast::Init>>& inits) const {
    354         ast::ArrayType* arrT = new ast::ArrayType(
    355                 attr == ast::EnumAttribute::Value
    356                         ? decl->base
    357                         : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
    358                 ast::ConstantExpr::from_int(decl->location, decl->members.size()),
    359                 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
    360 
    361         ast::ObjectDecl* objDecl =
    362                 new ast::ObjectDecl(
    363                         decl->location, decl->getUnmangeldArrayName( attr ),
    364                         arrT, new ast::ListInit( location, std::move( inits ) ),
    365                         ast::Storage::Static, ast::Linkage::AutoGen );
    366 
    367         return objDecl;
     355    const ast::EnumAttribute attr, const CodeLocation& location,
     356    std::vector<ast::ptr<ast::Init>>& inits) const {
     357    ast::ArrayType* arrT = new ast::ArrayType(
     358        attr == ast::EnumAttribute::Value
     359            ? decl->base
     360            : new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}),
     361        ast::ConstantExpr::from_int(decl->location, decl->members.size()),
     362        ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim);
     363
     364    ast::ObjectDecl* objDecl =
     365        new ast::ObjectDecl(decl->location, decl->getUnmangeldArrayName(attr),
     366                            arrT, new ast::ListInit(location, std::move(inits)),
     367                            ast::Storage::Static, ast::Linkage::AutoGen);
     368
     369    return objDecl;
    368370}
    369371
    370372void EnumAttrFuncGenerator::genValueOrLabelBody(
    371         ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
    372         ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
    373                 func->location, "?[?]",
    374                 {new ast::NameExpr(func->location, arrDecl->name),
    375                         new ast::CastExpr(
    376                                 func->location,
    377                                 new ast::VariableExpr( func->location, func->params.front() ),
    378                                 new ast::EnumAttrType( new ast::EnumInstType(decl),
    379                                         ast::EnumAttribute::Posn))});
    380         func->stmts = new ast::CompoundStmt(
    381                 func->location, {new ast::ReturnStmt(func->location, untyped)});
     373    ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const {
     374    ast::UntypedExpr* untyped = ast::UntypedExpr::createCall(
     375        func->location, "?[?]",
     376        {new ast::NameExpr(func->location, arrDecl->name),
     377         new ast::CastExpr(
     378             func->location,
     379             new ast::VariableExpr(func->location, func->params.front()),
     380             new ast::EnumAttrType(new ast::EnumInstType(decl),
     381                                   ast::EnumAttribute::Posn))});
     382    func->stmts = new ast::CompoundStmt(
     383        func->location, {new ast::ReturnStmt(func->location, untyped)});
    382384}
    383385
    384386void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
    385         auto castExpr = new ast::CastExpr(
    386                 func->location,
    387                 new ast::VariableExpr(func->location, func->params.front()),
    388                 new ast::EnumAttrType(new ast::EnumInstType(decl),
    389                                                           ast::EnumAttribute::Posn));
    390         func->stmts = new ast::CompoundStmt(
    391                 func->location, {new ast::ReturnStmt(func->location, castExpr)});
     387    auto castExpr = new ast::CastExpr(
     388        func->location,
     389        new ast::VariableExpr(func->location, func->params.front()),
     390        new ast::EnumAttrType(new ast::EnumInstType(decl),
     391                              ast::EnumAttribute::Posn));
     392    func->stmts = new ast::CompoundStmt(
     393        func->location, {new ast::ReturnStmt(func->location, castExpr)});
    392394}
    393395
    394396void EnumAttrFuncGenerator::genAttributesDecls(const ast::EnumAttribute attr) {
    395         if (attr == ast::EnumAttribute::Value ||
    396                 attr == ast::EnumAttribute::Label) {
    397                 std::vector<ast::ptr<ast::Init>> inits =
    398                         attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
    399                 ast::ObjectDecl* arrayProto =
    400                         genAttrArrayProto(attr, getLocation(), inits);
    401                 forwards.push_back(arrayProto);
    402 
    403                 ast::FunctionDecl* funcProto = ( attr == ast::EnumAttribute::Value )
    404                                                ? genValueProto()
    405                                                : genLabelProto();
    406                 produceForwardDecl(funcProto);
    407                 genValueOrLabelBody(funcProto, arrayProto);
    408                 produceDecl(funcProto);
    409         } else {
    410                 ast::FunctionDecl* funcProto = genPosnProto();
    411                 produceForwardDecl(funcProto);
    412                 genPosnBody(funcProto);
    413                 produceDecl(funcProto);
    414         }
     397    if (attr == ast::EnumAttribute::Value ||
     398        attr == ast::EnumAttribute::Label) {
     399        std::vector<ast::ptr<ast::Init>> inits =
     400            attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
     401        ast::ObjectDecl* arrayProto =
     402            genAttrArrayProto(attr, getLocation(), inits);
     403        forwards.push_back(arrayProto);
     404
     405        ast::FunctionDecl* funcProto = attr == ast::EnumAttribute::Value
     406                                           ? genValueProto()
     407                                           : genLabelProto();
     408        produceForwardDecl(funcProto);
     409        genValueOrLabelBody(funcProto, arrayProto);
     410        produceDecl(funcProto);
     411    } else {
     412        ast::FunctionDecl* funcProto = genPosnProto();
     413        produceForwardDecl(funcProto);
     414        genPosnBody(funcProto);
     415        produceDecl(funcProto);
     416    }
    415417}
    416418
    417419ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPredFunc(bool succ) {
    418         ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
    419         produceForwardDecl(funcDecl);
    420 
    421         const CodeLocation& location = getLocation();
    422 
    423         auto& params = funcDecl->params;
    424         assert(params.size() == 1);
    425         auto param = params.front().strict_as<ast::ObjectDecl>();
    426 
    427 
    428         auto rets = funcDecl->returns;
    429         assert(params.size() == 1);
    430         auto ret = rets.front().strict_as<ast::ObjectDecl>();
    431         auto retType = ret->type.strict_as<ast::EnumAttrType>();
    432 
    433         auto addOneExpr = ast::UntypedExpr::createCall( location,
    434                 succ? "?+?": "?-?",
    435                 {new ast::VariableExpr(location, param),
    436                 ast::ConstantExpr::from_int(location, 1)}
    437         );
    438 
    439         funcDecl->stmts = new ast::CompoundStmt(
    440                 location, {
    441                         new ast::ReturnStmt(
    442                                 location,
    443                                 new ast::CastExpr(location, addOneExpr, retType)
    444                         )
    445                 }
    446         );
    447 
    448         return funcDecl;
     420    ast::FunctionDecl* funcDecl = succ ? genSuccPosProto() : genPredPosProto();
     421    produceForwardDecl(funcDecl);
     422
     423    const CodeLocation& location = getLocation();
     424
     425    auto& params = funcDecl->params;
     426    assert(params.size() == 1);
     427    auto param = params.front().strict_as<ast::ObjectDecl>();
     428
     429
     430    auto rets = funcDecl->returns;
     431    assert(params.size() == 1);
     432    auto ret = rets.front().strict_as<ast::ObjectDecl>();
     433    auto retType = ret->type.strict_as<ast::EnumAttrType>();
     434
     435    auto addOneExpr = ast::UntypedExpr::createCall( location,
     436        succ? "?+?": "?-?",
     437        {new ast::VariableExpr(location, param),
     438        ast::ConstantExpr::from_int(location, 1)}
     439    );
     440
     441    funcDecl->stmts = new ast::CompoundStmt(
     442        location, {
     443            new ast::ReturnStmt(
     444                location,
     445                new ast::CastExpr(location, addOneExpr, retType)
     446            )
     447        }
     448    );
     449
     450    return funcDecl;
    449451}
    450452
    451453void EnumAttrFuncGenerator::genAttrFunctions() {
    452         if (decl->base) {
    453                 genAttributesDecls(ast::EnumAttribute::Value);
    454                 genAttributesDecls(ast::EnumAttribute::Label);
    455                 genAttributesDecls(ast::EnumAttribute::Posn);
    456         }
     454    if (decl->base) {
     455        genAttributesDecls(ast::EnumAttribute::Value);
     456        genAttributesDecls(ast::EnumAttribute::Label);
     457        genAttributesDecls(ast::EnumAttribute::Posn);
     458    }
    457459}
    458460
    459461void EnumAttrFuncGenerator::genSuccPredDecl() {
    460         if (decl->base) {
    461                 auto succProto = genSuccProto();
    462                 auto predProto = genPredProto();
    463 
    464                 produceForwardDecl(succProto);
    465                 produceForwardDecl(predProto);
    466         }
     462    if (decl->base) {
     463        auto succProto = genSuccProto();
     464        auto predProto = genPredProto();
     465
     466        produceForwardDecl(succProto);
     467        produceForwardDecl(predProto);
     468    }
    467469}
    468470
    469471void EnumAttrFuncGenerator::genSuccPredPosn() {
    470         if (decl->base) {
    471                 ast::FunctionDecl* succ = genSuccPredFunc(true);
    472                 ast::FunctionDecl* pred = genSuccPredFunc(false);
    473 
    474                 produceDecl(succ);
    475                 produceDecl(pred);
    476         }
     472    if (decl->base) {
     473        ast::FunctionDecl* succ = genSuccPredFunc(true);
     474        ast::FunctionDecl* pred = genSuccPredFunc(false);
     475
     476        produceDecl(succ);
     477        produceDecl(pred);
     478    }
    477479}
    478480
    479481void EnumAttrFuncGenerator::generateAndAppendFunctions(
    480         std::list<ast::ptr<ast::Decl>>& decls) {
    481         // Generate the functions (they go into forwards and definitions).
    482         genAttrStandardFuncs();
    483         genAttrFunctions();
    484         genSuccPredDecl();
    485         genSuccPredPosn(); // Posn
    486         // Now export the lists contents.
    487         decls.splice(decls.end(), forwards);
    488         decls.splice(decls.end(), definitions);
     482    std::list<ast::ptr<ast::Decl>>& decls) {
     483    // Generate the functions (they go into forwards and definitions).
     484    genAttrStandardFuncs();
     485    genAttrFunctions();
     486    genSuccPredDecl();
     487    genSuccPredPosn(); // Posn
     488    // Now export the lists contents.
     489    decls.splice(decls.end(), forwards);
     490    decls.splice(decls.end(), definitions);
    489491}
    490492
    491493// ---------------------------------------------------------
    492494
    493 struct ImplementEnumFunc final :
    494                 public ast::WithDeclsToAdd<>, public ast::WithShortCircuiting {
    495         void previsit(const ast::EnumDecl* enumDecl);
    496         void previsit(const ast::FunctionDecl* functionDecl);
    497         void postvisit(const ast::FunctionDecl* functionDecl);
    498 
    499 private:
    500         // Current level of nested functions.
    501         unsigned int functionNesting = 0;
     495struct ImplementEnumFunc final : public ast::WithDeclsToAdd<>,
     496                                public ast::WithShortCircuiting {
     497    void previsit(const ast::EnumDecl* enumDecl);
     498    void previsit(const ast::FunctionDecl* functionDecl);
     499    void postvisit(const ast::FunctionDecl* functionDecl);
     500
     501   private:
     502    // Current level of nested functions.
     503    unsigned int functionNesting = 0;
    502504};
    503505
    504506void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
    505         if (!enumDecl->body) return;
    506         if (!enumDecl->base) return;
    507 
    508         ast::EnumInstType enumInst(enumDecl->name);
    509         enumInst.base = enumDecl;
    510 
    511         EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
    512         gen.generateAndAppendFunctions(declsToAddAfter);
     507    if (!enumDecl->body) return;
     508    if (!enumDecl->base) return;
     509
     510    ast::EnumInstType enumInst(enumDecl->name);
     511    enumInst.base = enumDecl;
     512
     513    EnumAttrFuncGenerator gen(enumDecl, &enumInst, functionNesting);
     514    gen.generateAndAppendFunctions(declsToAddAfter);
    513515}
    514516
    515517void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
    516         functionNesting += 1;
     518    functionNesting += 1;
    517519}
    518520
    519521void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
    520         functionNesting -= 1;
    521 }
    522 
    523 } // namespace
     522    functionNesting -= 1;
     523}
     524
     525}  // namespace
    524526
    525527void implementEnumFunc(ast::TranslationUnit& translationUnit) {
    526         ast::Pass<ImplementEnumFunc>::run(translationUnit);
    527 }
    528 
    529 } // namespace Validate
     528    ast::Pass<ImplementEnumFunc>::run(translationUnit);
     529}
     530}  // namespace Validate
  • src/Virtual/VirtualDtor.cpp

    r7042c60 rcf191ac  
    2828
    2929struct CtorDtor {
    30         FunctionDecl * dtorSetup;  // dtor init routine to add after last dtor for a struct
    31         FunctionDecl * deleteFn;
    32         FunctionDecl * lastDtor;    // pointer to last occurence of dtor to know where to insert after
    33 
    34         CtorDtor() : dtorSetup(nullptr), deleteFn(nullptr), lastDtor(nullptr) {}
     30    FunctionDecl * dtorSetup;  // dtor init routine to add after last dtor for a struct
     31    FunctionDecl * deleteFn;
     32    FunctionDecl * lastDtor;    // pointer to last occurence of dtor to know where to insert after
     33
     34    CtorDtor() : dtorSetup(nullptr), deleteFn(nullptr), lastDtor(nullptr) {}
    3535};
    3636
    3737class CtorDtorTable {
    38         unordered_map<const StructDecl *, CtorDtor> & structMap;
    39 
    40 public:
    41         // if dtor is last dtor for this decl return the routine to add afterwards
    42         // otherwise return nullptr
    43         FunctionDecl * getToAddLater( const StructDecl * decl, FunctionDecl * dtor, FunctionDecl ** retDeleteFn ) {
    44                 auto iter = structMap.find( decl );
    45                 if ( iter == structMap.end() || iter->second.lastDtor != dtor ) return nullptr; // check if this is needed
    46                 *retDeleteFn = iter->second.deleteFn;
    47                 return iter->second.dtorSetup;
     38    unordered_map<const StructDecl *, CtorDtor> & structMap;
     39
     40  public:
     41    // if dtor is last dtor for this decl return the routine to add afterwards
     42    // otherwise return nullptr
     43    FunctionDecl * getToAddLater( const StructDecl * decl, FunctionDecl * dtor, FunctionDecl ** retDeleteFn ) {
     44        auto iter = structMap.find( decl );
     45        if ( iter == structMap.end() || iter->second.lastDtor != dtor ) return nullptr; // check if this is needed
     46        *retDeleteFn = iter->second.deleteFn;
     47        return iter->second.dtorSetup;
     48    }
     49
     50    // return if the dtorSetup field has been defined for this decl
     51    bool inTable( const StructDecl * decl ) {
     52        auto iter = structMap.find( decl );
     53        return iter->second.dtorSetup != nullptr;
     54    }
     55
     56    void addLater( const StructDecl * decl, FunctionDecl * dtorSetup, FunctionDecl * deleteFn ) {
     57        auto iter = structMap.find( decl );
     58        iter->second.dtorSetup = dtorSetup;
     59        iter->second.deleteFn = deleteFn;
     60    }
     61
     62    void addDtor( const StructDecl * decl, FunctionDecl * dtor ) {
     63        auto iter = structMap.find( decl );
     64        iter->second.lastDtor = dtor;
     65    }
     66
     67    CtorDtorTable( unordered_map<const StructDecl *, CtorDtor> & structMap ) : structMap(structMap) {}
     68};
     69
     70struct CollectStructDecls : public ast::WithGuards {
     71    unordered_map<const StructDecl *, CtorDtor> & structDecls;
     72    StructDecl * parentDecl;
     73    bool insideStruct = false;
     74    bool namedDecl = false;
     75
     76    const StructDecl ** virtualDtor;
     77
     78    // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
     79    void previsit( const StructDecl * decl ) {
     80        if ( !decl->body ) return;
     81        if( decl->name == "virtual_dtor" ) {
     82            structDecls.emplace( make_pair( decl, CtorDtor() ) );
     83            *virtualDtor = decl;
     84        } else {
     85            GuardValue(insideStruct);
     86            insideStruct = true;
     87            parentDecl = mutate( decl );
     88        }
    4889        }
    4990
    50         // return if the dtorSetup field has been defined for this decl
    51         bool inTable( const StructDecl * decl ) {
    52                 auto iter = structMap.find( decl );
    53                 return iter->second.dtorSetup != nullptr;
     91    // this catches structs of the form:
     92    //     struct derived_type { virtual_dtor a; };
     93    // since they should be:
     94    //     struct derived_type { inline virtual_dtor; };
     95    void previsit ( const ObjectDecl * decl ) {
     96        if ( insideStruct && ! decl->name.empty() ) {
     97            GuardValue(namedDecl);
     98            namedDecl = true;
     99        }
     100    }
     101
     102    // this collects the derived actor and message struct decl ptrs
     103    void postvisit( const StructInstType * node ) {
     104        if ( ! *virtualDtor ) return;
     105        if ( insideStruct && !namedDecl ) {
     106            auto structIter = structDecls.find( node->aggr() );   
     107            if ( structIter != structDecls.end() )
     108                structDecls.emplace( make_pair( parentDecl, CtorDtor() ) );
     109        }
    54110        }
    55111
    56         void addLater( const StructDecl * decl, FunctionDecl * dtorSetup, FunctionDecl * deleteFn ) {
    57                 auto iter = structMap.find( decl );
    58                 iter->second.dtorSetup = dtorSetup;
    59                 iter->second.deleteFn = deleteFn;
    60         }
    61 
    62         void addDtor( const StructDecl * decl, FunctionDecl * dtor ) {
    63                 auto iter = structMap.find( decl );
    64                 iter->second.lastDtor = dtor;
    65         }
    66 
    67         CtorDtorTable( unordered_map<const StructDecl *, CtorDtor> & structMap ) : structMap(structMap) {}
    68 };
    69 
    70 struct CollectStructDecls : public ast::WithGuards {
    71         unordered_map<const StructDecl *, CtorDtor> & structDecls;
    72         StructDecl * parentDecl;
    73         bool insideStruct = false;
    74         bool namedDecl = false;
    75 
    76         const StructDecl ** virtualDtor;
    77 
    78         // finds and sets a ptr to the actor, message, and request structs, which are needed in the next pass
    79         void previsit( const StructDecl * decl ) {
    80                 if ( !decl->body ) return;
    81                 if( decl->name == "virtual_dtor" ) {
    82                         structDecls.emplace( make_pair( decl, CtorDtor() ) );
    83                         *virtualDtor = decl;
    84                 } else {
    85                         GuardValue(insideStruct);
    86                         insideStruct = true;
    87                         parentDecl = mutate( decl );
    88                 }
    89         }
    90 
    91         // this catches structs of the form:
    92         //     struct derived_type { virtual_dtor a; };
    93         // since they should be:
    94         //     struct derived_type { inline virtual_dtor; };
    95         void previsit ( const ObjectDecl * decl ) {
    96                 if ( insideStruct && ! decl->name.empty() ) {
    97                         GuardValue(namedDecl);
    98                         namedDecl = true;
    99                 }
    100         }
    101 
    102         // this collects the derived actor and message struct decl ptrs
    103         void postvisit( const StructInstType * node ) {
    104                 if ( ! *virtualDtor ) return;
    105                 if ( insideStruct && !namedDecl ) {
    106                         auto structIter = structDecls.find( node->aggr() );
    107                         if ( structIter != structDecls.end() )
    108                                 structDecls.emplace( make_pair( parentDecl, CtorDtor() ) );
    109                 }
    110         }
    111 
    112112  public:
    113         CollectStructDecls( unordered_map<const StructDecl *, CtorDtor> & structDecls, const StructDecl ** virtualDtor ):
    114                 structDecls( structDecls ), virtualDtor(virtualDtor) {}
     113    CollectStructDecls( unordered_map<const StructDecl *, CtorDtor> & structDecls, const StructDecl ** virtualDtor ):
     114        structDecls( structDecls ), virtualDtor(virtualDtor) {}
    115115};
    116116
    117117// generates the forward decl of virtual dtor setting routine and delete routine
    118118// generates the call to the virtual dtor routine in each appropriate ctor
    119 // collects data needed for next pass that does the circular defn resolution
     119// collects data needed for next pass that does the circular defn resolution 
    120120//     for dtor setters and delete fns (via table above)
    121121struct GenFuncsCreateTables : public ast::WithDeclsToAdd<> {
    122         unordered_map<const StructDecl *, CtorDtor> & structDecls;
    123         CtorDtorTable & torDecls;
    124         const StructDecl ** virtualDtor;
    125 
    126         // collects the dtor info for actors/messages
    127         // gens the dtor fwd decl and dtor call in ctor
    128         void previsit( const FunctionDecl * decl ) {
    129                 if ( (decl->name != "?{}" && decl->name != "^?{}") || decl->params.size() == 0
    130                         || !decl->stmts || (decl->name == "^?{}" && decl->params.size() != 1)) return;
    131 
    132                 // the first param should be a reference
    133                 const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
    134                 if ( !ref ) return;
    135 
    136                 // the reference should be to a struct instance
    137                 const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
    138                 if ( !instType ) return;
    139 
    140                 // return if not ctor/dtor for an actor or message
    141                 auto structIter = structDecls.find( instType->aggr() );
    142                 if ( structIter == structDecls.end() ) return;
    143 
    144                 // If first param not named we need to name it to use it
    145                 if ( decl->params.at(0)->name == "" )
    146                         mutate( decl->params.at(0).get() )->name = "__CFA_Virt_Dtor_param";
    147 
    148                 if ( decl->name == "^?{}") {
    149                         torDecls.addDtor( structIter->first, mutate( decl ) );
    150 
    151                         CompoundStmt * dtorBody = mutate( decl->stmts.get() );
    152                         // Adds the following to the start of any actor/message dtor:
    153                         //  __CFA_dtor_shutdown( this );
    154                         dtorBody->push_front(
    155                                 new IfStmt( decl->location,
    156                                         new UntypedExpr (
    157                                                 decl->location,
    158                                                 new NameExpr( decl->location, "__CFA_dtor_shutdown" ),
    159                                                 {
    160                                                         new NameExpr( decl->location, decl->params.at(0)->name )
    161                                                 }
    162                                         ),
    163                                         new ReturnStmt( decl->location, nullptr )
    164                                 )
    165                         );
    166                         return;
    167                 }
    168 
    169                 // not dtor by this point so must be ctor
    170                 CompoundStmt * ctorBody = mutate( decl->stmts.get() );
    171                 // Adds the following to the end of any actor/message ctor:
    172                 //  __CFA_set_dtor( this );
    173                 ctorBody->push_back( new ExprStmt(
    174                         decl->location,
    175                         new UntypedExpr (
    176                                 decl->location,
    177                                 new NameExpr( decl->location, "__CFA_set_dtor" ),
    178                                 {
    179                                         new NameExpr( decl->location, decl->params.at(0)->name )
    180                                 }
    181                         )
    182                 ));
    183 
    184                 if ( torDecls.inTable( structIter->first ) ) return;
    185 
    186                 // Generates the following:
    187                 // void __CFA_set_dtor( Derived_type & this ){
    188                 //     void (*__my_dtor)( Derived_type & ) = ^?{};
    189                 //     this.__virtual_dtor = (void (*)( Base_type & ))__my_dtor;
    190                 //     this.__virtual_obj_start = (void *)(&this);
    191                 // }
    192                 CompoundStmt * setDtorBody = new CompoundStmt( decl->location );
    193 
    194                 // Function type is: (void (*)(Derived_type &))
    195                 FunctionType * derivedDtor = new FunctionType();
    196                 derivedDtor->params.push_back( ast::deepCopy( ref ) );
    197 
    198                 // Generates:
    199                 //      void (*__my_dtor)( Derived_type & ) = ^?{};
    200                 setDtorBody->push_back( new DeclStmt(
    201                         decl->location,
    202                         new ObjectDecl(
    203                                 decl->location,
    204                                 "__my_dtor",
    205                                 new PointerType( derivedDtor ),
    206                                 new SingleInit( decl->location, new NameExpr( decl->location, "^?{}" ) )
    207                         )
    208                 ));
    209 
    210                 // Function type is: (void (*)( Base_type & ))
    211                 FunctionType * baseDtor = new FunctionType();
    212                 baseDtor->params.push_back( new ReferenceType( new StructInstType( *virtualDtor ) ) );
    213 
    214                 // Generates:
    215                 //     __CFA_set_virt_dtor( this, (void (*)( Base_type & ))__my_dtor )
    216                 setDtorBody->push_back( new ExprStmt(
    217                         decl->location,
    218                         new UntypedExpr (
    219                                 decl->location,
    220                                 new NameExpr( decl->location, "__CFA_set_virt_dtor" ),
    221                                 {
    222                                         new NameExpr( decl->location, "this" ),
    223                                         new CastExpr( decl->location, new NameExpr( decl->location, "__my_dtor" ), new PointerType( baseDtor ), ExplicitCast )
    224                                 }
    225                         )
    226                 ));
    227 
    228                 // Generates:
    229                 //     __CFA_set_virt_start( (void *)(&this) );
    230                 setDtorBody->push_back( new ExprStmt(
    231                         decl->location,
    232                         new UntypedExpr (
    233                                 decl->location,
    234                                 new NameExpr( decl->location, "__CFA_set_virt_start" ),
    235                                 {
    236                                         new NameExpr( decl->location, "this" ),
    237                                         new CastExpr(
    238                                                 decl->location,
    239                                                 new AddressExpr( decl->location, new NameExpr( decl->location, "this" )),
    240                                                 new PointerType( new ast::VoidType() ), ExplicitCast
    241                                                 )
    242                                 }
    243                         )
    244                 ));
    245 
    246                 // put it all together into the complete function decl from above
    247                 FunctionDecl * setDtorFunction = new FunctionDecl(
    248                         decl->location,
    249                         "__CFA_set_dtor",
    250                         {
    251                                 new ObjectDecl(
    252                                         decl->location,
    253                                         "this",
    254                                         ast::deepCopy( ref )
    255                                 ),
    256                         },                      // params
    257                         {},
    258                         nullptr,               // body
    259                         { Storage::Static },    // storage
    260                         Linkage::Cforall,       // linkage
    261                         {},                     // attributes
    262                         { Function::Inline }
    263                 );
    264 
    265                 declsToAddBefore.push_back( ast::deepCopy( setDtorFunction ) );
    266 
    267                 setDtorFunction->stmts = setDtorBody;
    268 
    269                 // The following generates the following specialized delete routine:
    270                 // static inline void delete( derived_type * ptr ) {
    271                 //     if ( ptr )
    272                 //         ^(*ptr){};
    273                 //     __CFA_virt_free( *ptr );
    274                 // }
    275                 CompoundStmt * deleteFnBody = new CompoundStmt( decl->location );
    276 
    277                 // Generates:
    278                 //     if ( ptr )
    279                 //         ^(*ptr){};
    280                 deleteFnBody->push_back(
    281                         new IfStmt(
    282                                 decl->location,
    283                                 UntypedExpr::createCall(
    284                                         decl->location,
    285                                         "?!=?",
    286                                         {
    287                                                 new NameExpr( decl->location, "ptr" ),
    288                                                 ConstantExpr::null( decl->location, new PointerType( ast::deepCopy( instType ) ) )
    289                                         }
    290                                 ),
    291                                 new ExprStmt(
    292                                         decl->location,
    293                                         UntypedExpr::createCall(
    294                                                 decl->location,
    295                                                 "^?{}",
    296                                                 {
    297                                                         UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
    298                                                 }
    299                                         )
    300                                 )
    301                         )
    302                 );
    303 
    304                 // Generates:
    305                 //     __CFA_virt_free( *ptr );
    306                 deleteFnBody->push_back( new ExprStmt(
    307                                 decl->location,
    308                                 UntypedExpr::createCall(
    309                                         decl->location,
    310                                         "__CFA_virt_free",
    311                                         {
    312                                                 UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
    313                                         }
    314                                 )
    315                         )
    316                 );
    317 
    318                 FunctionDecl * deleteFn = new FunctionDecl(
    319                         decl->location,
    320                         "delete",
    321                         {
    322                                 new ObjectDecl(
    323                                         decl->location,
    324                                         "ptr",
    325                                         new PointerType( ast::deepCopy( instType ) )
    326                                 ),
    327                         },                      // params
    328                         {},
    329                         nullptr,               // body
    330                         { Storage::Static },    // storage
    331                         Linkage::Cforall,       // linkage
    332                         {},                     // attributes
    333                         { Function::Inline }
    334                 );
    335 
    336                 declsToAddBefore.push_back( ast::deepCopy( deleteFn ) );
    337 
    338                 deleteFn->stmts = deleteFnBody;
    339 
    340                 torDecls.addLater( structIter->first, setDtorFunction, deleteFn );
    341         }
     122    unordered_map<const StructDecl *, CtorDtor> & structDecls;
     123    CtorDtorTable & torDecls;
     124    const StructDecl ** virtualDtor;
     125
     126    // collects the dtor info for actors/messages
     127    // gens the dtor fwd decl and dtor call in ctor
     128    void previsit( const FunctionDecl * decl ) {
     129        if ( (decl->name != "?{}" && decl->name != "^?{}") || decl->params.size() == 0
     130            || !decl->stmts || (decl->name == "^?{}" && decl->params.size() != 1)) return;
     131
     132        // the first param should be a reference
     133        const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
     134        if ( !ref ) return;
     135
     136        // the reference should be to a struct instance
     137        const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
     138        if ( !instType ) return;
     139
     140        // return if not ctor/dtor for an actor or message
     141        auto structIter = structDecls.find( instType->aggr() );
     142        if ( structIter == structDecls.end() ) return;
     143
     144        // If first param not named we need to name it to use it
     145        if ( decl->params.at(0)->name == "" )
     146            mutate( decl->params.at(0).get() )->name = "__CFA_Virt_Dtor_param";
     147
     148        if ( decl->name == "^?{}") {
     149            torDecls.addDtor( structIter->first, mutate( decl ) );
     150
     151            CompoundStmt * dtorBody = mutate( decl->stmts.get() );
     152            // Adds the following to the start of any actor/message dtor:
     153            //  __CFA_dtor_shutdown( this );
     154            dtorBody->push_front(
     155                new IfStmt( decl->location,
     156                    new UntypedExpr (
     157                        decl->location,
     158                        new NameExpr( decl->location, "__CFA_dtor_shutdown" ),
     159                        {
     160                            new NameExpr( decl->location, decl->params.at(0)->name )
     161                        }
     162                    ),
     163                    new ReturnStmt( decl->location, nullptr )
     164                )
     165            );
     166            return;
     167        }
     168
     169        // not dtor by this point so must be ctor
     170        CompoundStmt * ctorBody = mutate( decl->stmts.get() );
     171        // Adds the following to the end of any actor/message ctor:
     172        //  __CFA_set_dtor( this );
     173        ctorBody->push_back( new ExprStmt(
     174            decl->location,
     175            new UntypedExpr (
     176                decl->location,
     177                new NameExpr( decl->location, "__CFA_set_dtor" ),
     178                {
     179                    new NameExpr( decl->location, decl->params.at(0)->name )
     180                }
     181            )
     182        ));
     183       
     184        if ( torDecls.inTable( structIter->first ) ) return;
     185
     186        // Generates the following:
     187        // void __CFA_set_dtor( Derived_type & this ){
     188        //     void (*__my_dtor)( Derived_type & ) = ^?{};
     189        //     this.__virtual_dtor = (void (*)( Base_type & ))__my_dtor;
     190        //     this.__virtual_obj_start = (void *)(&this);
     191        // }
     192        CompoundStmt * setDtorBody = new CompoundStmt( decl->location );
     193
     194        // Function type is: (void (*)(Derived_type &))
     195        FunctionType * derivedDtor = new FunctionType();
     196        derivedDtor->params.push_back( ast::deepCopy( ref ) );
     197
     198        // Generates:
     199        //      void (*__my_dtor)( Derived_type & ) = ^?{};
     200        setDtorBody->push_back( new DeclStmt(
     201            decl->location,
     202            new ObjectDecl(
     203                decl->location,
     204                "__my_dtor",
     205                new PointerType( derivedDtor ),
     206                new SingleInit( decl->location, new NameExpr( decl->location, "^?{}" ) )
     207            )
     208        ));
     209
     210        // Function type is: (void (*)( Base_type & ))
     211        FunctionType * baseDtor = new FunctionType();
     212        baseDtor->params.push_back( new ReferenceType( new StructInstType( *virtualDtor ) ) );
     213
     214        // Generates:
     215        //     __CFA_set_virt_dtor( this, (void (*)( Base_type & ))__my_dtor )
     216        setDtorBody->push_back( new ExprStmt(
     217            decl->location,
     218            new UntypedExpr (
     219                decl->location,
     220                new NameExpr( decl->location, "__CFA_set_virt_dtor" ),
     221                {
     222                    new NameExpr( decl->location, "this" ),
     223                    new CastExpr( decl->location, new NameExpr( decl->location, "__my_dtor" ), new PointerType( baseDtor ), ExplicitCast )
     224                }
     225            )
     226        ));
     227
     228        // Generates:
     229        //     __CFA_set_virt_start( (void *)(&this) );
     230        setDtorBody->push_back( new ExprStmt(
     231            decl->location,
     232            new UntypedExpr (
     233                decl->location,
     234                new NameExpr( decl->location, "__CFA_set_virt_start" ),
     235                {
     236                    new NameExpr( decl->location, "this" ),
     237                    new CastExpr(
     238                        decl->location,
     239                        new AddressExpr( decl->location, new NameExpr( decl->location, "this" )),
     240                        new PointerType( new ast::VoidType() ), ExplicitCast
     241                        )
     242                }
     243            )
     244        ));
     245
     246        // put it all together into the complete function decl from above
     247        FunctionDecl * setDtorFunction = new FunctionDecl(
     248            decl->location,
     249            "__CFA_set_dtor",
     250            {
     251                new ObjectDecl(
     252                    decl->location,
     253                    "this",
     254                    ast::deepCopy( ref )
     255                ),
     256            },                      // params
     257            {},
     258            nullptr,               // body
     259            { Storage::Static },    // storage
     260            Linkage::Cforall,       // linkage
     261            {},                     // attributes
     262            { Function::Inline }
     263        );
     264
     265        declsToAddBefore.push_back( ast::deepCopy( setDtorFunction ) );
     266
     267        setDtorFunction->stmts = setDtorBody;
     268
     269        // The following generates the following specialized delete routine:
     270        // static inline void delete( derived_type * ptr ) {
     271        //     if ( ptr )
     272        //         ^(*ptr){};
     273        //     __CFA_virt_free( *ptr );
     274        // }
     275        CompoundStmt * deleteFnBody = new CompoundStmt( decl->location );
     276
     277        // Generates:
     278        //     if ( ptr )
     279        //         ^(*ptr){};
     280        deleteFnBody->push_back(
     281            new IfStmt(
     282                decl->location,
     283                UntypedExpr::createCall(
     284                    decl->location,
     285                    "?!=?",
     286                    {
     287                        new NameExpr( decl->location, "ptr" ),
     288                        ConstantExpr::null( decl->location, new PointerType( ast::deepCopy( instType ) ) )
     289                    }
     290                ),
     291                new ExprStmt(
     292                    decl->location,
     293                    UntypedExpr::createCall(
     294                        decl->location,
     295                        "^?{}",
     296                        {
     297                            UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
     298                        }
     299                    )
     300                )
     301            )
     302        );
     303
     304        // Generates:
     305        //     __CFA_virt_free( *ptr );
     306        deleteFnBody->push_back( new ExprStmt(
     307                decl->location,
     308                UntypedExpr::createCall(
     309                    decl->location,
     310                    "__CFA_virt_free",
     311                    {
     312                        UntypedExpr::createDeref( decl->location, new NameExpr( decl->location, "ptr" ))
     313                    }
     314                )
     315            )
     316        );
     317
     318        FunctionDecl * deleteFn = new FunctionDecl(
     319            decl->location,
     320            "delete",
     321            {
     322                new ObjectDecl(
     323                    decl->location,
     324                    "ptr",
     325                    new PointerType( ast::deepCopy( instType ) )
     326                ),
     327            },                      // params
     328            {},
     329            nullptr,               // body
     330            { Storage::Static },    // storage
     331            Linkage::Cforall,       // linkage
     332            {},                     // attributes
     333            { Function::Inline }
     334        );
     335
     336        declsToAddBefore.push_back( ast::deepCopy( deleteFn ) );
     337
     338        deleteFn->stmts = deleteFnBody;
     339
     340        torDecls.addLater( structIter->first, setDtorFunction, deleteFn );
     341    }
    342342
    343343  public:
    344         GenFuncsCreateTables( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls, const StructDecl ** virtualDtor ):
    345         structDecls(structDecls), torDecls(torDecls), virtualDtor(virtualDtor) {}
     344    GenFuncsCreateTables( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls, const StructDecl ** virtualDtor ):
     345    structDecls(structDecls), torDecls(torDecls), virtualDtor(virtualDtor) {}
    346346};
    347347
     
    349349// generates the trailing definitions of dtor setting routines for virtual dtors on messages and actors
    350350// generates the function defns of __CFA_set_dtor
    351 // separate pass is needed since  __CFA_set_dtor needs to be defined after
     351// separate pass is needed since  __CFA_set_dtor needs to be defined after 
    352352//   the last dtor defn which is found in prior pass
    353353struct GenSetDtor : public ast::WithDeclsToAdd<> {
    354         unordered_map<const StructDecl *, CtorDtor> & structDecls; // set of decls that inherit from virt dtor
    355         CtorDtorTable & torDecls;
    356 
    357         // handles adding the declaration of the dtor init routine after the last dtor detected
    358         void postvisit( const FunctionDecl * decl ) {
    359                 if ( decl->name != "^?{}" || !decl->stmts || decl->params.size() != 1 ) return;
    360 
    361                 // the one param should be a reference
    362                 const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
    363                 if ( !ref ) return;
    364 
    365                 // the reference should be to a struct instance
    366                 const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
    367                 if ( !instType ) return;
    368 
    369                 FunctionDecl * deleteRtn;
    370 
    371                 // returns nullptr if not in table
    372                 FunctionDecl * maybeAdd = torDecls.getToAddLater( instType->aggr(), mutate( decl ), &deleteRtn );
    373                 if ( maybeAdd ) {
    374                         declsToAddAfter.push_back( maybeAdd );
    375                         declsToAddAfter.push_back( deleteRtn );
    376                 }
    377         }
    378 
    379 public:
    380         GenSetDtor( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls ):
    381                 structDecls(structDecls), torDecls(torDecls) {}
     354    unordered_map<const StructDecl *, CtorDtor> & structDecls; // set of decls that inherit from virt dtor
     355    CtorDtorTable & torDecls;
     356
     357    // handles adding the declaration of the dtor init routine after the last dtor detected
     358    void postvisit( const FunctionDecl * decl ) {
     359        if ( decl->name != "^?{}" || !decl->stmts || decl->params.size() != 1 ) return;
     360
     361        // the one param should be a reference
     362        const ReferenceType * ref = dynamic_cast<const ReferenceType *>(decl->params.at(0)->get_type());
     363        if ( !ref ) return;
     364
     365        // the reference should be to a struct instance
     366        const StructInstType * instType = dynamic_cast<const StructInstType *>(ref->base.get());
     367        if ( !instType ) return;
     368
     369        FunctionDecl * deleteRtn;
     370
     371        // returns nullptr if not in table
     372        FunctionDecl * maybeAdd = torDecls.getToAddLater( instType->aggr(), mutate( decl ), &deleteRtn );
     373        if ( maybeAdd ) {
     374            declsToAddAfter.push_back( maybeAdd );
     375            declsToAddAfter.push_back( deleteRtn );
     376        }
     377    }
     378
     379  public:
     380    GenSetDtor( unordered_map<const StructDecl *, CtorDtor> & structDecls, CtorDtorTable & torDecls ):
     381        structDecls(structDecls), torDecls(torDecls) {}
    382382};
    383383
    384384void implementVirtDtors( TranslationUnit & translationUnit ) {
    385         // unordered_map to collect all derived types and associated data
    386         unordered_map<const StructDecl *, CtorDtor> structDecls;
    387         CtorDtorTable torDecls( structDecls );
    388 
    389         const StructDecl * virtualDtorPtr = nullptr;
    390         const StructDecl ** virtualDtor = &virtualDtorPtr;
    391 
    392         // first pass collects all structs that inherit from virtual_dtor
    393         Pass<CollectStructDecls>::run( translationUnit, structDecls, virtualDtor );
    394 
    395         // second pass locates all dtor/ctor routines that need modifying or need fns inserted before/after
    396         Pass<GenFuncsCreateTables>::run( translationUnit, structDecls, torDecls, virtualDtor );
    397 
    398         // The third pass adds the forward decls needed to resolve circular defn problems
    399         Pass<GenSetDtor>::run( translationUnit, structDecls, torDecls );
     385    // unordered_map to collect all derived types and associated data
     386    unordered_map<const StructDecl *, CtorDtor> structDecls;
     387    CtorDtorTable torDecls( structDecls );
     388
     389    const StructDecl * virtualDtorPtr = nullptr;
     390    const StructDecl ** virtualDtor = &virtualDtorPtr;
     391
     392    // first pass collects all structs that inherit from virtual_dtor
     393    Pass<CollectStructDecls>::run( translationUnit, structDecls, virtualDtor );
     394
     395    // second pass locates all dtor/ctor routines that need modifying or need fns inserted before/after
     396    Pass<GenFuncsCreateTables>::run( translationUnit, structDecls, torDecls, virtualDtor );
     397
     398    // The third pass adds the forward decls needed to resolve circular defn problems
     399    Pass<GenSetDtor>::run( translationUnit, structDecls, torDecls );
    400400}
     401
    401402
    402403} // namespace Virtual
  • tests/alloc.cfa

    r7042c60 rcf191ac  
    1010// Created On       : Wed Feb  3 07:56:22 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 23 14:04:11 2024
    13 // Update Count     : 492
     12// Last Modified On : Fri Oct 14 09:31:39 2022
     13// Update Count     : 491
    1414//
    1515
     
    240240        free( stp );
    241241
    242         posix_memalign( &stp, Alignment );                                      // CFA posix_memalign
     242        posix_memalign( &stp, Alignment );                  // CFA posix_memalign
    243243        *stp = (Struct){ 42, 42.5 };
    244244        assert( (uintptr_t)stp % Alignment == 0 );
     
    275275        sout | nl;
    276276
    277         stp = alloc( dim, Alignment`align );                            // CFA array memalign
     277        stp = alloc( dim, Alignment`align );                // CFA array memalign
    278278        assert( (uintptr_t)stp % Alignment == 0 );
    279279        for ( i; dim ) { stp[i] = (Struct){ 42, 42.5 }; }
     
    316316        sout | nl;
    317317
    318         memset( st, fill );                                                                     // CFA memset, type safe
     318        memset( &st, fill );                                // CFA memset, type safe
    319319        sout | "CFA memset" | hex(st.x) | hex(st.y);
    320         memcpy( st1, st );                                                                      // CFA memcpy, type safe
     320        memcpy( &st1, &st );                                // CFA memcpy, type safe
    321321        sout | "CFA memcpy" | hex(st1.x) | hex(st1.y);
    322322
Note: See TracChangeset for help on using the changeset viewer.