Changeset 7042c60


Ignore:
Timestamp:
Apr 25, 2024, 3:48:17 PM (17 months ago)
Author:
JiadaL <j82liang@…>
Branches:
master
Children:
eb7586e
Parents:
cf191ac (diff), 55c97e4 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

resolve conflict

Files:
1 added
1 deleted
46 edited

Legend:

Unmodified
Added
Removed
  • doc/LaTeXmacros/common.sty

    rcf191ac r7042c60  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sun Feb 25 23:30:09 2024
    14 %% Update Count     : 645
     13%% Last Modified On : Thu Apr 18 09:14:02 2024
     14%% Update Count     : 657
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    108108\renewcommand\subparagraph{\@startsection{subparagraph}{4}{\z@}{-1.5ex \@plus -1ex \@minus -.2ex}{-1em}{\normalfont\normalsize\bfseries\itshape}}
    109109
    110 % index macros
    111110\newcommand{\italic}[1]{\emph{\hyperpage{#1}}}
    112111\newcommand{\Definition}[1]{\textbf{\hyperpage{#1}}}
    113 \newcommand{\see}[1]{(see #1)}
     112\newcommand{\see}{\protect\@ifstar\@ssee\@see}
     113\newcommand{\@ssee}[1]{(See #1)}
     114\newcommand{\@see}[1]{(see #1)}
     115
     116% index macros
    114117
    115118% Define some commands that produce formatted index entries suitable for cross-references.
     
    152155\newcommand{\newtermFontInline}{\emph}
    153156\newcommand{\newterm}{\protect\@ifstar\@snewterm\@newterm}
     157\newcommand{\@snewterm}[2][\@empty]{{\newtermFontInline{#2}}\ifx#1\@empty\index{#2}\else\index{#1@{\protect#2}}\fi}
    154158\newcommand{\@newterm}[2][\@empty]{\lowercase{\def\temp{#2}}{\newtermFontInline{#2}}\ifx#1\@empty\index{\temp}\else\index{#1@{\protect#2}}\fi}
    155 \newcommand{\@snewterm}[2][\@empty]{{\newtermFontInline{#2}}\ifx#1\@empty\index{#2}\else\index{#1@{\protect#2}}\fi}
    156159
    157160% \snake{<identifier>}
     
    202205
    203206\newenvironment{cquote}{%
    204         \list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=4pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}%
     207        \list{}{\topsep=\lst@aboveskip\parskip=0pt\partopsep=0pt\itemsep=0pt\parsep=0pt\listparindent=0pt\leftmargin=\parindentlnth\rightmargin=0pt}%
    205208        \item\relax
     209        \lstset{resetmargins=true}
    206210}{%
    207211        \endlist
     
    345349\fi%
    346350
     351\usepackage{tabularx}                                   % if @ is used for lstMakeShortInline, allows @{}
     352
    347353% Local Variables: %
    348354% tab-width: 4 %
  • doc/LaTeXmacros/common.tex

    rcf191ac r7042c60  
    1111%% Created On       : Sat Apr  9 10:06:17 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon Feb 26 08:06:05 2024
    14 %% Update Count     : 615
     13%% Last Modified On : Thu Apr 18 09:15:38 2024
     14%% Update Count     : 664
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    109109\renewcommand\subparagraph{\@startsection{subparagraph}{4}{\z@}{-1.5ex \@plus -1ex \@minus -.2ex}{-1em}{\normalfont\normalsize\bfseries\itshape}}
    110110
    111 % index macros
    112111\newcommand{\italic}[1]{\emph{\hyperpage{#1}}}
    113112\newcommand{\Definition}[1]{\textbf{\hyperpage{#1}}}
    114 \newcommand{\see}[1]{(see #1)}
     113\newcommand{\see}{\protect\@ifstar\@ssee\@see}
     114\newcommand{\@ssee}[1]{(See #1)}
     115\newcommand{\@see}[1]{(see #1)}
     116
     117% index macros
    115118
    116119% Define some commands that produce formatted index entries suitable for cross-references.
     
    153156\newcommand{\newtermFontInline}{\emph}
    154157\newcommand{\newterm}{\protect\@ifstar\@snewterm\@newterm}
     158\newcommand{\@snewterm}[2][\@empty]{{\newtermFontInline{#2}}\ifx#1\@empty\index{#2}\else\index{#1@{\protect#2}}\fi}
    155159\newcommand{\@newterm}[2][\@empty]{\lowercase{\def\temp{#2}}{\newtermFontInline{#2}}\ifx#1\@empty\index{\temp}\else\index{#1@{\protect#2}}\fi}
    156 \newcommand{\@snewterm}[2][\@empty]{{\newtermFontInline{#2}}\ifx#1\@empty\index{#2}\else\index{#1@{\protect#2}}\fi}
    157160
    158161% \snake{<identifier>}
     
    201204\newcommand{\VS}{\abbrevFont{vs}}
    202205\newcommand{\vs}{\VS\CheckPeriod}
    203 \makeatother
    204206
    205207\newenvironment{cquote}{%
    206         \list{}{\lstset{resetmargins=true,aboveskip=0pt,belowskip=0pt}\topsep=4pt\parsep=0pt\leftmargin=\parindentlnth\rightmargin\leftmargin}%
     208        \list{}{\topsep=\lst@aboveskip\parskip=0pt\partopsep=0pt\itemsep=0pt\parsep=0pt\listparindent=0pt\leftmargin=\parindentlnth\rightmargin=0pt}%
    207209        \item\relax
     210        \lstset{resetmargins=true}
    208211}{%
    209212        \endlist
    210213}% cquote
     214\makeatother
    211215
    212216\newenvironment{rationale}{%
     
    349353\fi%
    350354
     355\usepackage{tabularx}                                   % if @ is used for lstMakeShortInline, allows @{}
     356
    351357% Local Variables: %
    352358% tab-width: 4 %
  • doc/LaTeXmacros/lstlang.sty

    rcf191ac r7042c60  
    88%% Created On       : Sat May 13 16:34:42 2017
    99%% Last Modified By : Peter A. Buhr
    10 %% Last Modified On : Tue Mar 12 17:29:58 2024
    11 %% Update Count     : 42
     10%% Last Modified On : Mon Apr 15 11:28:44 2024
     11%% Update Count     : 43
    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, _Decimal32, _Decimal64, _Decimal128, disable, dtype, enable, exception, __extension__,
     118                __const, __const__, continue, coroutine, _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

    rcf191ac r7042c60  
    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}},
    521531}
    522532
  • doc/theses/jiada_liang_MMath/CFAenum.tex

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

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

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

    rcf191ac r7042c60  
    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@, @12345@, \etc.
    4 Constants 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.
     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@, @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.
     4Con\-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.)
    56Hence, each primary constant has a symbolic name referring to its internal representation, and these names are dictated by language syntax related to types.
    6 In theory, there are an infinite set of primary names per type.
    7 
    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.
     7In theory, there are an infinite set of primary constant names per type.
     8
     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.
    910Many 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.
    10 In 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.)
     11Its purpose is for readability and to eliminate duplication of the primary constant throughout a program.
     12For example, a meaningful secondary name replaces a primary name throughout a program;
     13thereafter, changing the binding of the secondary to primary name automatically distributes the rebinding, preventing errors.
     14In 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@.
    1215Because 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{
    1316The term rvalue defines an expression that can only appear on the right-hand side of an assignment expression.}.
    1417
    15 Secondary 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.
     18Secondary 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.
    1619Many programming languages capture these groupings through a mechanism called an \Newterm{enumeration}.
    1720\begin{quote}
    1821enumerate (verb, transitive).
    1922To count, ascertain the number of;
    20 \emph{more
    21 usually, to mention (a number of things or persons) separately, as if for the
    22 purpose of counting};
    23 to specify as in a list or catalogue.~\cite{OED}
     23more usually, to mention (a number of things or persons) separately, as if for the purpose of counting;
     24to specify as in a list or catalogue.~\cite{OEDenumerate}
    2425\end{quote}
    25 Within an enumeration set, the enumeration names must be unique, and instances of an enumerated type are restricted to hold only the secondary names.
     26Within 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.
    2627It is possible to enumerate among set names without having an ordering among the set elements.
    2728For example, the week, the weekdays, the weekend, and every second day of the week.
     
    2930for ( cursor in Mon, Tue, Wed, Thu, Fri, Sat, Sun } ... $\C[3.75in]{// week}$
    3031for ( cursor in Mon, Tue, Wed, Thu, Fri } ...   $\C{// weekday}$
    31 for ( cursor in Thu, Fri } ...                                  $\C{// weekend}$
     32for ( cursor in Sat, Sun } ...                                  $\C{// weekend}$
    3233for ( cursor in Mon, Wed, Fri, Sun } ...                $\C{// every second day of week}\CRT$
    3334\end{cfa}
    34 This independence from internal representation allows multiple names to have the same representation (eight note, quaver), giving synonyms.
     35This independence from internal representation allows multiple names to have the same representation (eighth note, quaver), giving synonyms.
    3536A set can have a partial or total ordering, making it possible to compare set elements, \eg Monday is before Friday and Friday is after.
    36 Ordering allows iterating among the enumeration set using relational operators and advancement, \eg
     37Ordering allows iterating among the enumeration set using relational operators and advancement, \eg:
    3738\begin{cfa}
    3839for ( cursor = Monday; cursor @<=@ Friday; cursor = @succ@( cursor ) ) ...
    3940\end{cfa}
    40 Here the internal representations for the secondary names are \emph{generated} rather than listing a subset of names.
     41Here the internal representation for the secondary names are logically \emph{generated} rather than listing a subset of names.
     42
     43Hence, the fundamental aspects of an enumeration are:
     44\begin{enumerate}
     45\item
     46\begin{sloppypar}
     47It provides a finite set of secondary names, which become its primary constants.
     48This differentiates an enumeration from general types with an infinite set
     49of primary constants.
     50\end{sloppypar}
     51\item
     52The secondary names are constants, which follows transitively from their binding (aliasing) to primary names, which are constants.
     53\item
     54Defines a type for generating instants (variables).
     55\item
     56For safety, an enumeration instance should be restricted to hold only its type's secondary names.
     57\item
     58There 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}
    4160
    4261
    4362\section{Terminology}
    44 
    45 The term \Newterm{enumeration} defines the set of secondary names, and the term \Newterm{enumerator} represents an arbitrary secondary name.
    46 As well, an enumerated type has three fundamental properties, \Newterm{label}, \Newterm{order}, and \Newterm{value}.
     63\label{s:Terminology}
     64
     65The 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}.
     66As well, an enumerated type can have three fundamental properties, \Newterm{label}, \Newterm{order}, and \Newterm{value}.
    4767\begin{cquote}
    4868\sf\setlength{\tabcolsep}{3pt}
    4969\begin{tabular}{rcccccccr}
    5070\it\color{red}enumeration       & \multicolumn{8}{c}{\it\color{red}enumerators} \\
    51 $\downarrow$\hspace*{25pt}      & \multicolumn{8}{c}{$\downarrow$}                              \\
    52 @enum@ Week \{                          & Mon,  & Tue,  & Wed,  & Thu,  & Fri,  & Sat,  & Sun = 42      & \};   \\
     71$\downarrow$\hspace*{15pt}      & \multicolumn{8}{c}{$\downarrow$}                              \\
     72@enum@ Week \{                          & Mon,  & Tue,  & Wed,  & Thu,  & Fri,  & Sat,  & Sun {\color{red}= 42} & \};   \\
    5373\it\color{red}label                     & Mon   & Tue   & Wed   & Thu   & Fri   & Sat   & Sun           &               \\
    5474\it\color{red}order                     & 0             & 1             & 2             & 3             & 4             & 5             & 6                     &               \\
    55 \it\color{red}value                     & 0             & 1             & 2             & 3             & 4             & 5             & 42            &
     75\it\color{red}value                     & 0             & 1             & 2             & 3             & 4             & 5             & {\color{red}42}               &
    5676\end{tabular}
    5777\end{cquote}
     
    7292\section{Motivation}
    7393
    74 Some programming languages only provide secondary renaming, which can be simulated by an enumeration without ordering.
    75 \begin{cfa}
    76 const Size = 20, Pi = 3.14159;
    77 enum { Size = 20, Pi = 3.14159 };   // unnamed enumeration $\(\Rightarrow\)$ no ordering
    78 \end{cfa}
    79 In both cases, it is possible to compare the secondary names, \eg @Size < Pi@, if that is meaningful;
    80 however, without an enumeration type-name, it is impossible to create an iterator cursor.
    81 
    82 Secondary renaming can similate an enumeration, but with extra effort.
     94Many programming languages provide an enumeration-like mechanism, which may or may not cover the previous five fundamental enumeration aspects.
     95Hence, the term \emph{enumeration} can be confusing and misunderstood.
     96Furthermore, some languages conjoin the enumeration with other type features, making it difficult to tease apart which featuring is being used.
     97This section discusses some language features that are sometimes called an enumeration but do not provide all enumeration aspects.
     98
     99
     100\subsection{Aliasing}
     101
     102Some languages provide simple secondary aliasing (renaming), \eg:
     103\begin{cfa}
     104const Size = 20, Pi = 3.14159, Name = "Jane";
     105\end{cfa}
     106The secondary name is logically replaced in the program text by its corresponding primary name.
     107Therefore, 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
     109Aliasing 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.
     110With aliasing, each secondary name is part of the language, and hence, participates fully, such as name overloading in the type system.
     111Aliasing is not an immutable variable, \eg:
     112\begin{cfa}
     113extern @const@ int Size = 20;
     114extern void foo( @const@ int @&@ size );
     115foo( Size ); // take the address of (reference) Size
     116\end{cfa}
     117Taking the address of an immutable variable makes it an \Newterm{lvalue}, which implies it has storage.
     118With separate compilation, it is necessary to choose one translation unit to perform the initialization.
     119If aliasing does require storage, its address and initialization are opaque (compiler only), similar to \CC rvalue reference @&&@.
     120
     121Aliasing does provide readability and automatic resubstitution.
     122It also provides simple enumeration properties, but with extra effort.
    83123\begin{cfa}
    84124const Mon = 1, Tue = 2, Wed = 3, Thu = 4, Fri = 5, Sat = 6, Sun = 7;
    85125\end{cfa}
    86 Furthermore, reordering the enumerators requires manual renumbering.
     126Any reordering of the enumerators requires manual renumbering.
    87127\begin{cfa}
    88128const Sun = 1, Mon = 2, Tue = 3, Wed = 4, Thu = 5, Fri = 6, Sat = 7;
    89129\end{cfa}
    90 Finally, there is no common type to create a type-checked instance or iterator cursor.
    91 Hence, there is only a weak equivalence between secondary naming and enumerations, justifying the enumeration type in a programming language.
    92 
    93 A variant (algebraic) type is often promoted as a kind of enumeration, \ie a varient type can simulate an enumeration.
    94 A 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}
    105 Crucially, the union implies instance storage is shared by all of the variant types.
    106 Hence, 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}.
    107 Knowing which type is in a variant instance is crucial for correctness.
    108 Occasionally, it is possible to statically determine all regions where each variant type is used, so a tag and runtime checking is unnecessary;
    109 otherwise, 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.
    110 
    111 The tag can be implicitly set by the compiler on assignment, or explicitly set by the program\-mer.
    112 Type 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}]
    114 Variant 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}
    121 For safety, either all variant types must be listed or a @default@ case must exist with no field accesses.
    122 
    123 To 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}
    125 variant Weekday {
    126         int tag; // implicit 0 => Mon, ..., 6 => Sun
    127         @case Mon;@ // no type
    128         ...
    129         @case Sun;@
    130 };
    131 \end{cfa}
    132 The type system ensures tag setting and testing are correctly done.
    133 However, the enumeration operations are limited to the available tag operations, \eg pattern matching.
    134 \begin{cfa}
    135 Week week = Mon;
    136 if ( @dynamic_cast(Mon)@week ) ... // test tag == Mon
    137 \end{cfa}
    138 While enumerating among tag names is possible:
    139 \begin{cfa}[morekeywords={in}]
    140 for ( cursor in Mon, Wed, Fri, Sun ) ...
    141 \end{cfa}
    142 ordering 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@.
    143 
    144 However, 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.
    145 Iterating using tag ordering and heterogeneous types, also requires pattern matching.
    146 \begin{cfa}[morekeywords={match}]
    147 for ( 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}
    156 If the variant type is changed by adding/removing types or the loop range changes, the pattern matching must be adjusted.
    157 As well, if the start/stop values are dynamic, it may be impossible to statically determine if all variant types are listed.
    158 
    159 Re-purposing the notion of enumerating into variant types is ill formed and confusing.
    160 Hence, there is only a weak equivalence between an enumeration and variant type, justifying the enumeration type in a programming language.
     130For these reasons, aliasing is sometimes called an enumeration.
     131However, there is no type to create a type-checked instance or iterator cursor, so there is no ability for enumerating.
     132Hence, there are multiple enumeration aspects not provided by aliasing, justifying a separate enumeration type in a programming language.
     133
     134
     135\subsection{Algebraic Data Type}
     136
     137An 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.
     138For example, in Haskell:
     139\begin{haskell}
     140data S = S { i::Int, d::Double }                $\C{// structure}$
     141data @Foo@ = A Int | B Double | C S             $\C{// ADT, composed of three types}$
     142foo = A 3;                                                              $\C{// type Foo is inferred}$
     143bar = B 3.5
     144baz = C S{ i = 7, d = 7.5 }
     145\end{haskell}
     146the ADT has three variants (constructors), @A@, @B@, @C@ with associated types @Int@, @Double@, and @S@.
     147The constructors create an initialized value of the specific type that is bound to the immutable variables @foo@, @bar@, and @baz@.
     148Hence, 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}
     153prtfoo 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}
     164main = do
     165    prtfoo foo
     166    prtfoo bar
     167    prtfoo baz
     1683
     1693.5
     1707
     1717.5
     172\end{haskell}
     173\end{tabular}
     174\end{cquote}
     175For safety, most languages require all assocaited types to be listed or a default case with no field accesses.
     176
     177A less frequent case is multiple constructors with the same type.
     178\begin{haskell}
     179data Bar = X Int | Y Int | Z Int;
     180foo = X 3;
     181bar = Y 3;
     182baz = Z 5;
     183\end{haskell}
     184Here, 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.
     185
     186Note, the term \Newterm{variant} is often associated with ADTs.
     187However, there are multiple languages with a @variant@ type that is not an ADT \see{Algol68~\cite{Algol68} or \CC \lstinline{variant}}.
     188In these languages, the variant is often a union using RTTI tags, which cannot be used to simulate an enumeration.
     189Hence, 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
     194The association between ADT and enumeration occurs if all the constructors have a unit (empty) type, \eg @struct unit {}@.
     195Note, the unit type is not the same as \lstinline{void}, \eg:
     196\begin{cfa}
     197void foo( void );
     198struct unit {} u;  // empty type
     199unit bar( unit );
     200foo( foo() );        // void argument does not match with void parameter
     201bar( bar( u ) );   // unit argument does match with unit parameter
     202\end{cfa}
     203
     204For example, in the Haskell ADT:
     205\begin{haskell}
     206data Week = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving(Enum, Eq, Show)
     207\end{haskell}
     208the 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.
     209The 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}
     217day = Tue
     218main = 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}
     229Tue
     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
     245The 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.
     246While the enumeration is constructed using the ADT mechanism, it is so restricted it is not really an ADT.
     247Furthermore, a general ADT cannot be an enumeration because the constructors generate different values making enumerating meaningless.
     248While functional programming languages regularly repurpose the ADT type into an enumeration type, this process seems contrived and confusing.
     249Hence, there is only a weak equivalence between an enumeration and ADT, justifying a separate enumeration type in a programming language.
    161250
    162251
    163252\section{Contributions}
    164253
    165 The 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.
     254The 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.
    166255On the surface, enumerations seem like a simple type.
    167256However, when extended with advanced features, enumerations become complex for both the type system and the runtime implementation.
    168257
     258The contribution of this work are:
    169259\begin{enumerate}
    170260\item
     
    175265typing
    176266\item
    177 subset
     267subseting
    178268\item
    179269inheritance
  • doc/theses/jiada_liang_MMath/relatedwork.tex

    rcf191ac r7042c60  
    2323\section{Pascal}
    2424\label{s:Pascal}
    25 \lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    2625
    2726Classic Pascal has the \lstinline[language=pascal]{const} declaration binding a name to a constant literal/expression.
     
    5150
    5251\section{Ada}
    53 \lstnewenvironment{ada}[1][]{\lstset{language=[2005]Ada,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},literate={'}{\ttfamily'\!}1}\lstset{#1}}{}
    54 
    55 An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
     52
     53An Ada enumeration type is a set of ordered unscoped identifiers (enumerators) bound to \emph{unique} \Newterm{literals}.\footnote{%
     54Ada 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).}
    5655\begin{ada}
    57 type RGB is ( Red, Green, Blue ); -- 3 literals (enumerators)
     56type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun ); -- literals (enumerators)
    5857\end{ada}
    5958Object initialization and assignment are restricted to the enumerators of this type.
    60 Enumerators without an explicitly designated constant value are auto-initialized: from left to right, starting at zero or the next explicitly initialized constant, incrementing by 1.
    61 To explicitly set enumerator values, \emph{all} enumerators must be set in \emph{ascending} order, \ie there is no auto-initialization.
     59While Ada enumerators are unscoped, like C, Ada enumerators are overloadable.
    6260\begin{ada}
    63 type RGB is ( Red, Green, Blue );
    64 @for RGB use ( Red => 10, Green => 20, Blue => 30 );@ -- ascending order
    65 \end{ada}
    66 Hence, the position, value, label tuples are:
    67 \begin{ada}
    68 (0, 10, RED)  (1, 20, GREEN)  (2, 30, BLUE)
    69 \end{ada}
    70 Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same, \eg @Red@ and @RED@ (a questionable design decision).
    71 
    72 Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope.
    73 The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of enumerators, which is always ascending.
    74 
    75 Ada enumerators are overloadable.
    76 \begin{ada}
     61type RGB is ( @Red@, @Green@, Blue );
    7762type Traffic_Light is ( @Red@, Yellow, @Green@ );
    7863\end{ada}
    79 Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded names.
     64Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded identifiers.
    8065\VRef[Figure]{f:AdaEnumeration} shows how ambiguity is handled using a cast, \ie \lstinline[language=ada]{RGB'(Red)}.
    8166
     
    10287\end{figure}
    10388
    104 Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package names.
     89Enumerators without initialization are auto-initialized from left to right, starting at zero, incrementing by 1.
     90Enumerators with initialization must set \emph{all} enumerators in \emph{ascending} order, \ie there is no auto-initialization.
     91\begin{ada}
     92type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
     93for Week use ( Mon => 0, Tue => 1, Wed => 2, Thu => @10@, Fri => 11, Sat => 14, Sun => 15 );
     94\end{ada}
     95The enumeration operators are the equality and relational operators, @=@, @/=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of acsending enumerators.
     96
     97Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package identifiers.
    10598\begin{ada}
    10699OtherRed : RGB renames Red;
     
    113106There are three pairs of inverse enumeration pseudo-functions (attributes): @'Pos@ and @'Val@, @'Enum_Rep@ and @'Enum_Val@, and @'Image@ and @'Value@,
    114107\begin{cquote}
    115 \lstDeleteShortInline@
    116108\setlength{\tabcolsep}{15pt}
    117109\begin{tabular}{@{}ll@{}}
     
    128120\end{ada}
    129121\end{tabular}
    130 \lstMakeShortInline@
    131122\end{cquote}
    132123These attributes are important for IO.
     
    138129\end{ada}
    139130which is syntactic sugar for the label and not character literals from the predefined type @Character@.
    140 The purpose is strictly readability using character literals rather than names.
     131The purpose is strictly readability using character literals rather than identifiers.
    141132\begin{ada}
    142133Op : Operator := '+';
     
    171162An enumeration type can be used in the Ada \lstinline[language=ada]{case} (all enumerators must appear or a default) or iterating constructs.
    172163\begin{cquote}
    173 \lstDeleteShortInline@
    174164\setlength{\tabcolsep}{15pt}
    175165\begin{tabular}{@{}ll@{}}
     
    211201\end{ada}
    212202\end{tabular}
    213 \lstMakeShortInline@
    214203\end{cquote}
    215204
     
    225214\section{\CC}
    226215\label{s:C++RelatedWork}
    227 \lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    228216
    229217\CC has the equivalent of Pascal typed @const@ declarations \see{\VRef{s:Pascal}}, with static and dynamic initialization.
    230218\begin{c++}
    231 const auto one = 0 + 1;                                 $\C{// static intialization}$
     219const auto one = 0 + 1;                                 $\C{// static initialization}$
    232220const auto NULL = nullptr;
    233221const auto PI = 3.14159;
     
    237225                                Sat = Fri + 1, Sun = Sat + 1;
    238226int sa[Sun];
    239 const auto r = random();                                $\C{// dynamic intialization}$
     227const auto r = random();                                $\C{// dynamic initialization}$
    240228int da[r];                                                              $\C{// VLA}$
    241229\end{c++}
     
    319307\section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE
    320308\label{s:Csharp}
    321 \lstnewenvironment{csharp}[1][]{\lstset{language=[Sharp]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    322309
    323310% https://www.tutorialsteacher.com/codeeditor?cid=cs-mk8Ojx
     
    362349\begin{figure}
    363350\centering
    364 \lstDeleteShortInline@
    365351\begin{tabular}{@{}l|l@{}}
    366352\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
     
    414400\end{csharp}
    415401\end{tabular}
    416 \lstMakeShortInline@
    417402\caption{\Csharp: Free Routine Versus Class Enumeration}
    418403\label{CsharpFreeVersusClass}
     
    421406
    422407\section{Golang}
    423 \lstnewenvironment{Go}[1][]{\lstset{language=Go,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    424408
    425409Golang provides pseudo-enumeration similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
     
    429413const ( S = 0; T; USA = "USA"; U; V = 3.1; W ) $\C{// type change, implicit/explicit: 0 0 USA USA 3.1 3.1}$
    430414\end{Go}
    431 Constant names are unscoped and must be unique (no overloading).
     415Constant identifiers are unscoped and must be unique (no overloading).
    432416The first enumerator \emph{must} be explicitly initialized;
    433417subsequent enumerators can be implicitly or explicitly initialized.
     
    459443Basic switch and looping are possible.
    460444\begin{cquote}
    461 \lstDeleteShortInline@
    462445\setlength{\tabcolsep}{15pt}
    463446\begin{tabular}{@{}ll@{}}
     
    482465\end{Go}
    483466\end{tabular}
    484 \lstMakeShortInline@
    485467\end{cquote}
    486468However, the loop prints the values from 0 to 13 because there is no actual enumeration.
     
    488470
    489471\section{Java}
    490 \lstnewenvironment{Java}[1][]{\lstset{language=Java,morekeywords={enum,assert,strictfp},
    491         escapechar=\$,moredelim=**[is][\color{red}]{!}{!},}\lstset{#1}}{}
    492472
    493473Every enumeration in Java is an enumeration class.
     
    513493\begin{figure}
    514494\centering
    515 \lstDeleteShortInline@
    516495\begin{tabular}{@{}l|l@{}}
    517496\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
     
    553532\end{Java}
    554533\end{tabular}
    555 \lstMakeShortInline@
    556534\caption{Java: Free Routine Versus Class Enumeration}
    557535\label{f:JavaFreeVersusClass}
     
    606584
    607585\section{Rust}
    608 \lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
     586% https://doc.rust-lang.org/reference/items/enumerations.html
    609587
    610588Rust provides a scoped enumeration based on variant types.
     
    652630
    653631\section{Swift}
    654 \lstnewenvironment{swift}[1][]{\lstset{language=Swift,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    655632
    656633% https://www.programiz.com/swift/online-compiler
     
    1010987
    1011988
    1012 \section{Python}
    1013 \lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    1014 
    1015 A Python enumeration is a set of symbolic names bound to \emph{unique} values.
    1016 They are similar to global variables, but offer a more useful @repr()@, grouping, type-safety, and additional features.
    1017 Enumerations inherits from the @Enum@ class, \eg:
    1018 \begin{python}
    1019 class Weekday(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
    1020 class RGB(@Enum@): Red = 1; Green = 2; Blue = 3
    1021 \end{python}
    1022 
    1023 Depending on the nature of the enum a member's value may or may not be important, but either way that value can be used to get the corresponding member:
    1024 \begin{python}
    1025 print( repr( Weekday( 3 ) ) )
    1026 <Weekday.Wed: 3>
    1027 \end{python}
    1028 As you can see, the @repr()@ of a member shows the enum name, the member name, and the value.
    1029 The @str()@ of a member shows only the enum name and member name:
    1030 \begin{python}
    1031 print( str( Weekday.Thu ), Weekday.Thu )
    1032 Weekday.Thu Weekday.Thu
    1033 \end{python}
    1034 The type of an enumeration member is the enum it belongs to:
    1035 \begin{python}
    1036 print( type( Weekday.Thu ) )
    1037 <enum 'Weekday'>
    1038 print( isinstance(Weekday.Fri, Weekday) )
    1039 True
    1040 \end{python}
    1041 Enum members have an attribute that contains just their name:
    1042 \begin{python}
    1043 print(Weekday.TUESDAY.name)
    1044 TUESDAY
    1045 \end{python}
    1046 Likewise, they have an attribute for their value:
    1047 \begin{python}
    1048 Weekday.WEDNESDAY.value
    1049 3
    1050 \end{python}
    1051 
    1052 Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added.
    1053 For example, @datetime.date@ has two methods for returning the weekday: @weekday()@ and @isoweekday()@.
    1054 The difference is that one of them counts from 0-6 and the other from 1-7.
    1055 Rather than keep track of that ourselves we can add a method to the @Weekday@ enum to extract the day from the date instance and return the matching enum member:
    1056 \begin{python}
    1057 class Weekday(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = 15; Sat = 16; Sun = 17
    1058 $@$classmethod
    1059 def from_date(cls, date):
    1060         return cls(date.isoweekday())
    1061 \end{python}
    1062 Now 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}
    1068 Of course, if you're reading this on some other day, you'll see that day instead.
    1069 
    1070 This Weekday enum is great if our variable only needs one day, but what if we need several? Maybe we're writing a function to plot chores during a week, and don't want to use a @list@ -- we could use a different type of @Enum@:
    1071 \begin{python}
    1072 from enum import Flag
    1073 class WeekdayF(@Flag@): Mon = @1@; Tue = @2@; Wed = @4@; Thu = @8@; Fri = @16@; Sat = @32@; Sun = @64@
    1074 \end{python}
    1075 We've changed two things: we're inherited from @Flag@, and the values are all powers of 2.
     989\section{Python 3.13}
     990% https://docs.python.org/3/howto/enum.html
     991
     992Python 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.
     993As 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.
     994Nevertheless, an attempt has been made to discuss core enumeration features that come with Python 3.13.
     995
     996A Python enumeration type is a set of ordered scoped identifiers (enumerators) bound to \emph{unique} values.
     997An enumeration is not a basic type;
     998it is a @class@ inheriting from the @Enum@ class, where the enumerators must be explicitly initialized, \eg:
     999\begin{python}
     1000class Week(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
     1001\end{python}
     1002and/or explicitly auto initialized, \eg:
     1003\begin{python}
     1004class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @auto()@; Sat = 4; Sun = @auto()@
     1005\end{python}
     1006where @auto@ increments by 1 from the previous enumerator value.
     1007Object initialization and assignment are restricted to the enumerators of this type.
     1008An 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}
     1010class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @10@; Sat = @10@; Sun = @10@
     1011\end{python}
     1012Here, the enumeration has only 4 enumerators and 3 aliases.
     1013An 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;
     1015the extended class @OrderedEnum@ adds relational operators @<@, @<=@, @>@, and @>=@.
     1016
     1017There 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}
     1022Week.Thu.value == 10;
     1023Week.Thu.name == 'Thu';
     1024\end{python}
     1025&
     1026\begin{python}
     1027Week( 10 ) == Thu
     1028Week['Thu'].value = 10
     1029\end{python}
     1030\end{tabular}
     1031\end{cquote}
     1032
     1033As an enumeration is a \lstinline[language=python]{class}, its own methods.
     1034\begin{python}
     1035class 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())
     1040print( "today:", Week.today(date.today()))
     1041today: Week.Mon
     1042\end{python}
     1043The method @today@ retrieves the day of the week and uses it as an index to print out the corresponding label of @Week@.
    10761044
    10771045@Flag@ allows combining several members into a single variable:
    10781046\begin{python}
    1079 print( repr(WeekdayF.Sat | WeekdayF.Sun) )
    1080 <WeekdayF.Sun|Sat: 96>
     1047print( repr(WeekF.Sat | WeekF.Sun) )
     1048<WeekF.Sun|Sat: 96>
    10811049\end{python}
    10821050You can even iterate over a @Flag@ variable:
     
    10841052for day in weekend:
    10851053        print(day)
    1086 Weekday.SATURDAY
    1087 Weekday.SUNDAY
     1054WeekF.Sat
     1055WeekF.Sun
    10881056\end{python}
    10891057Okay, let's get some chores set up:
    10901058\begin{python}
    10911059>>> chores_for_ethan = {
    1092 ...    'feed the cat': Weekday.MONDAY | Weekday.WEDNESDAY | Weekday.FRIDAY,
    1093 ...    'do the dishes': Weekday.TUESDAY | Weekday.THURSDAY,
    1094 ...    'answer SO questions': Weekday.SATURDAY,
     1060...    'feed the cat': Week.MONDAY | Week.WEDNESDAY | Week.FRIDAY,
     1061...    'do the dishes': Week.TUESDAY | Week.THURSDAY,
     1062...    'answer SO questions': Week.SATURDAY,
    10951063...    }
    10961064\end{python}
     
    11011069...        if day in days:
    11021070...            print(chore)
    1103 >>> show_chores(chores_for_ethan, Weekday.SATURDAY)
     1071>>> show_chores(chores_for_ethan, Week.SATURDAY)
    11041072answer SO questions
    11051073\end{python}
    1106 In 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
     1074Auto incrmenet for @Flag@ is by powers of 2.
     1075\begin{python}
     1076class WeekF(Flag): Mon = auto(); Tue = auto(); Wed = auto(); Thu = auto(); Fri = auto();  \
     1077                                                        Sat = auto(); Sun = auto(); Weekend = Sat | Sun
     1078for d in WeekF:
     1079        print( f"{d.name}: {d.value}", end=" ")
     1080Mon: 1 Tue: 2 Wed: 4 Thu: 8 Fri: 16 Sat: 32 Sun: 64 WeekA.Weekend
    11181081\end{python}
    11191082
     
    11231086@Enum@ allows such access:
    11241087\begin{python}
    1125 >>> Color(1)
    1126 <Color.RED: 1>
    1127 >>> Color(3)
    1128 <Color.BLUE: 3>
     1088print(RGB(1), RGB(3), )
     1089RGB.RED RGB.GREEN
    11291090\end{python}
    11301091If you want to access enum members by name, use item access:
    11311092\begin{python}
    1132 Color['RED']
    1133 <Color.RED: 1>
    1134 
    1135 Color['GREEN']
    1136 <Color.GREEN: 2>
     1093print( RGBa['RED'], RGBa['GREEN'] )
     1094RGB.RED RGB.GREEN
    11371095\end{python}
    11381096If you have an enum member and need its name or value:
    11391097\begin{python}
    1140 >>> member = Color.RED
    1141 >>> member.name
    1142 'RED'
    1143 >>> member.value
    1144 1
    1145 \end{python}
    1146 
    1147 \subsection{Duplicating enum members and values}
    1148 
    1149 An enum member can have other names associated with it.
    1150 Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@.
    1151 By-value lookup of the value of @A@ will return the member @A@.
    1152 By-name lookup of @A@ will return the member @A@.
    1153 By-name lookup of @B@ will also return the member @A@:
    1154 \begin{python}
    1155 class 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 
    1164 Note: Attempting to create a member with the same name as an already defined attribute (another member, a method, etc.) or attempting to create an attribute with the same name as a member is not allowed.
     1098member = RGBa.RED
     1099print( f"{member.name} {member.value}" )
     1100RED 1
     1101\end{python}
     1102
    11651103
    11661104\subsection{Ensuring unique enumeration values}
     
    12071145>>> list(Shape)
    12081146[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
    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}
    1213 Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Weekday.WEEKEND@ aren't shown.
     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}
     1151Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Week.WEEKEND@ aren't shown.
    12141152
    12151153The special attribute @__members__@ is a read-only ordered mapping of names to members.
     
    22122150
    22132151\section{OCaml}
    2214 \lstnewenvironment{ocaml}[1][]{\lstset{language=OCaml,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    22152152
    22162153% https://ocaml.org/docs/basic-data-types#enumerated-data-types
     
    22182155
    22192156OCaml provides a variant (union) type, where multiple heterogeneously-typed objects share the same storage.
    2220 The 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)
     2157The simplest form of the variant type is a list of nullary datatype constructors, which is like an unscoped, opaque enumeration.
     2158
    22232159OCaml provides a variant (union) type, which is an aggregation of heterogeneous types.
    2224 A basic variant is a list of nullary datatype constructors, which is like an unscoped, pure enumeration.
     2160A basic variant is a list of nullary datatype constructors, which is like an unscoped, opaque enumeration.
    22252161\begin{ocaml}
    22262162type weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun
     
    22462182type colour = Red | Green of @string@ | Blue of @int * float@
    22472183\end{ocaml}
    2248 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. 
     2184A variant with parameter is stored in a memory block, prefixed by an int tag and has its parameters stores as words in the block.
    22492185@colour@ is a summation of a nullary type, a unary product type of @string@, and a cross product of @int@ and @float@.
    22502186(Mathematically, a @Blue@ value is a Cartesian product of the types @int@ type and @float@.)
     
    22592195@Red, abc, 1 1.5@
    22602196\end{ocaml}
    2261 
    22622197
    22632198A variant type can have a recursive definition.
     
    22802215
    22812216In summary, an OCaml variant is a singleton value rather than a set of possibly ordered values, and hence, has no notion of enumerabilty.
    2282 Therefore it is not an enumeration, except for the simple pure (nullary) case.
     2217Therefore it is not an enumeration, except for the simple opaque (nullary) case.
    22832218
    22842219\begin{comment}
     
    24662401With valediction,
    24672402  - Gregor Richards
     2403
     2404
     2405Date: Tue, 16 Apr 2024 11:04:51 -0400
     2406Subject: Re: C unnamed enumeration
     2407To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
     2408CC: <ajbeach@uwaterloo.ca>, <j82liang@uwaterloo.ca>, <mlbrooks@uwaterloo.ca>,
     2409        <f37yu@uwaterloo.ca>
     2410From: Gregor Richards <gregor.richards@uwaterloo.ca>
     2411
     2412On 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
     2416Your tagless variant bears no resemblance to variants in any functional
     2417programming language. A variant is a tag AND a union. You might not need to put
     2418anything in the union, in which case it's a pointless union, but the named tag
     2419is absolutely mandatory. That's the thing that varies.
     2420
     2421I was unaware of std::variant. As far as functional languages are concerned,
     2422std::variant IS NOT A VARIANT. Perhaps it would be best to use the term ADT for
     2423the functional language concept, because that term has no other meanings.
     2424
     2425An ADT cannot not have a named tag. That's meaningless. The tag is the data
     2426constructor, which is the thing you actually define when you define an ADT. It
     2427is strictly the union that's optional.
     2428
     2429With valediction,
     2430  - Gregor Richards
    24682431\end{comment}
    24692432
     
    24872450\hline
    24882451\hline
    2489 pure                    &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
     2452opaque                  &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
    24902453\hline
    24912454typed                   &               &               &               &               &               &               &               &               &               &               & @int@ & integral      & @T@   \\
  • doc/theses/jiada_liang_MMath/uw-ethesis.bib

    rcf191ac r7042c60  
    22% For use with BibTeX
    33
     4Oxford 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

    rcf191ac r7042c60  
    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}
    97113
    98114\newcommand{\newtermFont}{\emph}
  • doc/uC++toCFA/Makefile

    rcf191ac r7042c60  
    5656        dvips ${Build}/$< -o $@
    5757
    58 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \
    59                 ${Macros}/common.sty ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
     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}
    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

    rcf191ac r7042c60  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Thu Jan 11 14:46:14 2024
    14 %% Update Count     : 5942
     13%% Last Modified On : Sat Apr 13 11:11:39 2024
     14%% Update Count     : 5969
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    141141\CFA uses parametric polymorphism and allows overloading of variables and routines:
    142142\begin{cfa}
    143 int i;  char i;  double i;              // overload name i
     143int i;  char i;  double i;      $\C[2in]{// overload name i}$
    144144int i();  double i();  char i();
    145 i += 1;                 $\C[1.5in]{// 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{// 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 
    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;}} \\
     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;}} \\
    158157\begin{uC++}
    159158**p2i = 3;
     
    201200
    202201\CFA output streams automatically separate values and insert a newline at the end of the print.
    203 
    204 \begin{cquote}
    205 \begin{tabular}{l|l}
     202\begin{cquote}
     203\begin{tabular}{@{}l|l@{}}
    206204\begin{uC++}
    207205#include <@iostream@>
     
    226224
    227225\begin{cquote}
    228 \begin{tabular}{l|l}
     226\begin{tabular}{@{}l|l@{}}
    229227\begin{uC++}
    230228for ( @;;@ ) { ... }  /  while ( @true@ ) { ... }
     
    280278Currently, \CFA uses macros @ExceptionDecl@ and @ExceptionInst@ to declare and instantiate an exception.
    281279\begin{cquote}
    282 \begin{tabular}{l|ll}
     280\begin{tabular}{@{}l|ll@{}}
    283281\begin{uC++}
    284282
     
    321319
    322320\begin{cquote}
    323 \begin{tabular}{l|ll}
     321\begin{tabular}{@{}l|ll@{}}
    324322\begin{uC++}
    325323
     
    360358
    361359\begin{cquote}
    362 \begin{tabular}{l|l}
     360\begin{tabular}{@{}l|l@{}}
    363361\begin{uC++}
    364362struct S {
     
    383381
    384382\begin{cquote}
    385 \begin{tabular}{l|l}
    386 \multicolumn{2}{l}{\lstinline{string s1, s2;}} \\
     383\begin{tabular}{@{}l|l@{}}
     384\multicolumn{2}{@{}l@{}}{\lstinline{string s1, s2;}} \\
    387385\begin{uC++}
    388386s1 = "hi";
     
    425423
    426424\begin{cquote}
    427 \begin{tabular}{l|l}
     425\begin{tabular}{@{}l|l@{}}
    428426\begin{uC++}
    429427struct S {
     
    456454
    457455\begin{cquote}
    458 \begin{tabular}{l|l}
     456\begin{tabular}{@{}l|l@{}}
    459457\begin{uC++}
    460458
     
    493491
    494492\begin{cquote}
    495 \begin{tabular}{l|ll}
     493\begin{tabular}{@{}l|ll@{}}
    496494\begin{uC++}
    497495
     
    532530
    533531\begin{cquote}
    534 \begin{tabular}{l|ll}
     532\begin{tabular}{@{}l|ll@{}}
    535533\begin{uC++}
    536534
     
    567565
    568566\begin{cquote}
    569 \begin{tabular}{l|ll}
     567\begin{tabular}{@{}l|ll@{}}
    570568\begin{uC++}
    571569
     
    604602
    605603\begin{cquote}
    606 \begin{tabular}{l|ll}
     604\begin{tabular}{@{}l|ll@{}}
    607605\begin{uC++}
    608606
  • doc/user/Makefile

    rcf191ac r7042c60  
    6060        dvips ${Build}/$< -o $@
    6161
    62 ${BASE}.dvi : Makefile ${GRAPHS} ${PROGRAMS} ${PICTURES} ${FIGURES} ${SOURCES} \
    63                 ${Macros}/common.sty ${Macros}/lstlang.sty ${Macros}/indexstyle ../bibliography/pl.bib build/version | ${Build}
     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}
    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

    rcf191ac r7042c60  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Mon Feb 12 11:50:26 2024
    14 %% Update Count     : 6199
     13%% Last Modified On : Tue Apr 23 14:13:10 2024
     14%% Update Count     : 6623
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    6969\lstset{language=CFA}                                                                   % CFA default lnaguage
    7070\lstnewenvironment{C++}[1][]                            % use C++ style
    71 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{®}{®},#1}}
     71{\lstset{language=C++,escapechar=§,moredelim=**[is][\protect\color{red}]{®}{®},#1}}
    7272{}
    7373
     
    130130\vspace*{\fill}
    131131\noindent
    132 \copyright\,2016, 2018, 2021 \CFA Project \\ \\
     132\copyright\,2016, 2018, 2021, 2024 \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( dtype T | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); }
     314forall( 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{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[3in]{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;}§
     1067for ( i; 5 : k; 1.5 ~ @ : j; @ -~ -5 ~ 2 ) { sout | i | j | k; } §\C{sout | nl;}\CRT§
    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
    29622963As well, \CFA-style declarations cannot be used to declare parameters for C-style routine-definitions because of the following ambiguity:
    29632964\begin{cfa}
     
    29652966int f( int (* foo) ); §\C{// foo is redefined as a parameter name}§
    29662967\end{cfa}
    2967 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.
     2968The 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©.
    29682969The 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.
    29692970The 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.
     
    30553056static [ int ] g ( int );
    30563057\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.
     3065The 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@{}}
     3068postfix function & constant argument call & variable argument call & postfix function pointer \\
     3069\hline
     3070\begin{cfa}
     3071int ?`h( int s );
     3072int ?`h( double s );
     3073int ?`m( char c );
     3074int ?`m( const char * s );
     3075int ?`t( int a, int b, int c );
     3076\end{cfa}
     3077&       
     3078\begin{cfa}
     30790`h;
     30803.5`h;
     3081'1'`m;
     3082"123" "456"`m;
     3083[1, 2, 3]`t;
     3084\end{cfa}
     3085&       
     3086\begin{cfa}
     3087int i = 7;
     3088i`h;
     3089(i + 3)`h;
     3090(i + 3.5)`h;
     3091\end{cfa}
     3092&       
     3093\begin{cfa}
     3094int (* ?`p)( int i );
     3095?`p = ?`h;
     30963`p;
     3097i`p;
     3098(i + 3)`p;
     3099\end{cfa}
     3100\end{tabular}
     3101\end{cquote}
     3102Note, 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}}.
     3103Similarly, 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.}
     3107The \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).
     3108The three postfixing function names ©st©, ©lb©, and ©kg©, represent units stones, pounds, and kilograms, respectively.
     3109Each 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©.
     3110All arithmetic operations manipulate stones and the postfix operations convert to the different units.
     3111A 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}
     3120struct Weight {
     3121        double stones;
     3122};
     3123
     3124
     3125Weight ?+?( Weight l, Weight r ) {
     3126        return l.stones + r.stones;
     3127}
     3128Weight ®?`st®( double w ) { return w; }
     3129double ®?`st®( Weight w ) { return w.stones; }
     3130Weight ®?`lb®( double w ) { return w / 14.0; }
     3131double ®?`lb®( Weight w ) { return w.stones * 14.0; }
     3132Weight ®?`kg®( double w ) { return w / 6.35; }
     3133double ®?`kg®( Weight w ) { return w.stones * 6.35; }
     3134int 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++}
     3145struct Weight {
     3146        double stones;
     3147        Weight() {}
     3148        Weight( double w ) { stones = w; }
     3149};
     3150Weight operator+( Weight l, Weight r ) {
     3151        return l.stones + r.stones;
     3152}
     3153Weight operator®""_st®( long double w ) { return w; }
     3154Weight operator®""_lb®( long double w ) { return w / 14.0; }
     3155Weight operator®""_kg®( long double w ) { return w / 6.35; }
     3156Weight operator®""_st®( unsigned long long int w ) { return w; }
     3157Weight operator®""_lb®( unsigned long long int w ) { return w / 14.0; }
     3158Weight operator®""_kg®( unsigned long long int w ) { return w / 6.35; }
     3159int 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}
     3171Time : comparison of time units. \\
     3172\begin{tabular}{@{}ll@{}}
     3173\CFA & \CC \\
     3174\begin{cfa}
     3175#include <fstream.hfa>
     3176#include <time.hfa>
     3177
     3178
     3179Duration s = 1`h + 2 * 10`m + 70`s / 10;
     3180sout | "1 hour + 2*10 min + 70/10 sec = " | s | "seconds";
     3181sout | "Dividing that by 2 minutes gives" | s / 2`m;
     3182sout | "Dividing that by 2 gives" | s / 2 | "seconds\n";
     3183sout | 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>
     3192using namespace std;
     3193using namespace std::chrono;
     3194seconds s = hours(1) + 2 * minutes(10) + seconds(70) / 10;
     3195cout << "1 hour + 2*10 min + 70/10 sec = " << s.count() << " seconds\n";
     3196cout << "Dividing that by 2 minutes gives " << s / minutes(2) << '\n';
     3197cout << "Dividing that by 2 gives " << (s / 2).count() << " seconds\n";
     3198cout << 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
     3210The \CC example (right) provides a \emph{restricted} capability via user literals.
     3211The \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.
     3212As 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©.
     3213Finally, there is no mechanism to use this syntax for a bidirectional conversion because \lstinline[language=C++]{operator ""} does not accept variable arguments.
    30573214
    30583215
     
    33893546
    33903547\section{Tuple}
     3548\label{s:Tuple}
    33913549
    33923550In C and \CFA, lists of elements appear in several contexts, such as the parameter list of a routine call.
     
    38093967\subsection{Polymorphism}
    38103968
    3811 Due to the implicit flattening and structuring conversions involved in argument passing, ©otype© and ©dtype© parameters are restricted to matching only with non-tuple types.
     3969Due to the implicit flattening and structuring conversions involved in argument passing, object and opaque parameters are restricted to matching only with non-tuple types.
    38123970The integration of polymorphism, type assertions, and monomorphic specialization of tuple-assertions are a primary contribution of this thesis to the design of tuples.
    38133971\begin{cfa}
    3814 forall(T, dtype U)
     3972forall(T, U &)
    38153973void f(T x, U * y);
    38163974
     
    40474205[ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = §\emph{expr}§;
    40484206\end{cfa}
    4049 \index{lvalue}
    4050 The 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.
     4207The 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.
    40514208\LstBasicStyle{\emph{expr}} is any standard arithmetic expression.
    40524209Clearly, the types of the entities being assigned must be type compatible with the value of the expression.
     
    40864243Multiple assignment has the following form:
    40874244\begin{cfa}
    4088 [ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = [ §\emph{expr}§, ... , §\emph{expr}§ ];
    4089 \end{cfa}
    4090 \index{lvalue}
    4091 The left-hand side is a tuple of \emph{lvalues}, and the right-hand side is a tuple of \emph{expr}s.
    4092 Each \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.
     4245[ §\emph{lvalue}§, ... , §\emph{lvalue}§ ] = [ §\emph{expr}§, ... , §\emph{expr}§ ];§
     4246\end{cfa}
     4247The 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.
     4248Each \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.
    40934249An example of multiple assignment is:
    40944250\begin{cfa}
     
    49255081        sout | '1' | '2' | '3';
    49265082        sout | 1 | "" | 2 | "" | 3;
    4927         sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x £" | 6 | "x Â¥"
    4928                 | 7 | "x ¡" | 8 | "x ¿" | 9 | "x «" | 10;
     5083        sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x £" | 6 | "x ¥"
     5084                | 7 | "x ¡" | 8 | "x ¿" | 9 | "x «" | 10;
    49295085        sout | 1 | ", x" | 2 | ". x" | 3 | "; x" | 4 | "! x" | 5 | "? x" | 6 | "% x"
    4930                 | 7 | "¢ x" | 8 | "» x" | 9 | ") x" | 10 | "] x" | 11 | "} x";
     5086                | 7 | "¢ x" | 8 | "» x" | 9 | ") x" | 10 | "] x" | 11 | "} x";
    49315087        sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x:" | 4 | ":x " | 5 | " x\t" | 6 | "\tx";
    49325088        sout | "x ( " | 1 | " ) x" | 2 | " , x" | 3 | " :x: " | 4;
     
    77757931\item[Rationale:] increase type safety
    77767932\item[Effect on original feature:] deletion of semantically well-defined feature.
    7777 \item[Difficulty of converting:] requires adding a cast \see{\VRef{s:StorageManagement} for better alternatives}:
     7933\item[Difficulty of converting:] requires adding a cast \see{\VRef{s:DynamicStorageManagement} for better alternatives}:
    77787934\begin{cfa}
    77797935        int * b = (int *)malloc( sizeof(int) );
     
    79878143\section{Standard Library}
    79888144\label{s:StandardLibrary}
    7989 
    7990 The \CFA standard-library wraps explicitly-polymorphic C routines into implicitly-polymorphic versions.
    7991 
    7992 
    7993 \subsection{Storage Management}
    7994 \label{s:StorageManagement}
    7995 
    7996 The 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 
    7998 C storage management provides the following capabilities:
    7999 \begin{description}
    8000 \item[filled]
    8001 after allocation with a specified character or value.
     8145\index{standard library}
     8146
     8147The \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
     8154Dynamic storage-management in C is based on explicit allocation and deallocation (©malloc©/©free©).
     8155Programmer's must manage all allocated storage via its address (pointer) and subsequently deallocate the storage via this address.
     8156Storage that is not deallocated becomes inaccessible, called a \newterm{memory leak}, which can only be detected at program termination.
     8157Storage freed twice is an error, called a \newterm{duplicate free}, which can sometimes be detected.
     8158Storage 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
     8163C dynamic storage-management provides the following properties.
     8164\begin{description}[leftmargin=*]
     8165\item[fill]
     8166storage after an allocation with a specified character or value.
     8167\item[align]
     8168an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
     8169\item[scale]
     8170an allocation size to the specified number of array elements.
     8171An array may be filled, resized, or aligned.
    80028172\item[resize]
    80038173an existing allocation to decreased or increased its size.
    8004 In 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.
    8005 For an increase in storage size, new storage after the copied data may be filled.
    8006 \item[align]
    8007 an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
    8008 \item[array]
    8009 the allocation size is scaled to the specified number of array elements.
    8010 An array may be filled, resized, or aligned.
     8174In 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.
     8175When new storage is allocated, it may be aligned and storage after copied data may be filled.
    80118176\end{description}
    8012 \VRef[Table]{t:AllocationVersusCapabilities} shows allocation routines supporting different combinations of storage-management capabilities.
     8177\VRef[Table]{t:AllocationVersusProperties} shows different combinations of storage-management properties provided by the C and \CFA allocation routines.
     8178
    80138179\begin{table}
     8180\caption{Allocation Routines versus Storage-Management Properties}
     8181\label{t:AllocationVersusProperties}
    80148182\centering
    80158183\begin{minipage}{0.75\textwidth}
    80168184\begin{tabular}{@{}r|l|l|l|l|l@{}}
    8017 \multicolumn{1}{c}{}&           & \multicolumn{1}{c|}{fill}     & resize        & alignment     & array \\
     8185                & \multicolumn{1}{c|}{routine} & \multicolumn{1}{c|}{\textbf{fill}} & \textbf{alignment}        & \textbf{scale}        & \textbf{resize} \\
    80188186\hline
    80198187C               & ©malloc©                      & no                    & no            & 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   \\
     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    \\
    80278196                & ©pvalloc©\footnote{Same as ©valloc© but rounds size to multiple of page size.}
    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   \\
     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
    80368204\end{tabular}
    80378205\end{minipage}
    8038 \caption{Allocation Routines versus Storage-Management Capabilities}
    8039 \label{t:AllocationVersusCapabilities}
     8206\vspace*{-10pt}
    80408207\end{table}
    80418208
    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.
    8043 Type-safe allocation is provided for all C allocation routines and new \CFA allocation routines, \eg in
    8044 \begin{cfa}
    8045 int * ip = (int *)malloc( sizeof(int) ); §\C{// C}§
    8046 int * ip = malloc();                                    §\C{// \CFA type-safe version of C malloc}§
    8047 int * ip = alloc();                                             §\C{// \CFA type-safe uniform alloc}§
    8048 \end{cfa}
    8049 the 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}
    8053 struct S { int i; } __attribute__(( aligned( 128 ) )); // cache-line alignment
    8054 S * sp = malloc();                                              §\C{// honour type alignment}§
    8055 \end{cfa}
    8056 the storage allocation is implicitly aligned to 128 rather than the default 16.
    8057 The 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}.
    8060 Hence, initial allocation capabilities are remembered and maintained when resize requires copying.
    8061 For 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.
    8062 Without 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}
    8069 struct S { int i; };                                    §\C{// cache-line alignment}§
    8070 void ?{}( S & s, int i ) { s.i = i; }
    8071 // assume ?|? operator for printing an S
    8072 
    8073 S & sp = *®new®( 3 );                                   §\C{// call constructor after allocation}§
    8074 sout | sp.i;
    8075 ®delete®( &sp );
    8076 
    8077 S * spa = ®anew®( 10, 5 );                              §\C{// allocate array and initialize each array element}§
    8078 for ( i; 10 ) sout | spa[i] | nonl;
    8079 sout | nl;
    8080 ®adelete®( 10, spa );
     8209
     8210\subsubsection{\CFA Interface}
     8211
     8212\CFA dynamic memory management:
     8213\begin{enumerate}[leftmargin=\parindent]
     8214\item
     8215extends 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}
     8217int * ip = (int *)malloc( sizeof(int) ); §\C[2.3in]{// C}§
     8218int * ip = malloc();                                    §\C{// \CFA type-safe call of C malloc}§
     8219int * ip = calloc();                                    §\C{// \CFA type-safe call of C calloc}§
     8220struct __attribute__(( aligned(128) )) spinlock { ... }; // cache alignment
     8221spinlock * slp = malloc();                              §\C{// correct size, alignment, and return type}\CRT§
     8222\end{cfa}
     8223Here, the alignment of the ©ip© storage is 16 (default) and 128 for ©slp©.
     8224
     8225\item
     8226introduces the notion of \newterm{sticky properties} used in resizing.
     8227All initial allocation properties are remembered and maintained for use should resize require new storage.
     8228For example, the initial alignment and fill properties in the initial allocation
     8229\begin{cfa}
     8230struct __attribute__(( aligned(4096) )) S { ... };
     8231S * sp = calloc( 10 );                                  §\C{// align 4K and zero fill}§
     8232sp = reallocarray( sp, 100 );                   §\C{// preserve 4K alignment and zero fill new storage}§
     8233\end{cfa}
     8234are preserved in the resize so the new storage has the same alignment and extra storage after the data copy is zero filled.
     8235Without 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
     8238provides 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.
     8239A resize can take advantage of unused storage after the data to preventing a free/reallocation step altogether.
     8240
     8241\item
     8242provides ©free©/©delete© functions that delete a variable number of allocations.
     8243\begin{cfa}
     8244int * ip = malloc(), * jp = malloc(), * kp = malloc();
     8245double * xp = malloc(), * yp = malloc(), * zp = malloc();
     8246free( ®ip, jp, kp, xp, yp, zp® );               §\C{// multiple deallocations}§
     8247\end{cfa}
     8248
     8249\item
     8250supports constructors for initialization of allocated storage and destructors for deallocation (like \CC).
     8251\begin{cfa}
     8252struct S { int v; };                                    §\C{// default constructors}§
     8253void ^?{}( S & ) { ... }                                §\C{// destructor}§
     8254S & sp = *®new®( 3 );                                   §\C{// allocate and call constructor}§
     8255sout | sp.v;
     8256®delete®( &sp );                                                §\C{// call destructor}§
     8257S * spa1 = ®anew®( 10, 5 ), * spa2 = ®anew®( 10, 8 ); §\C{// allocate array and call constructor for each array element}§
     8258for ( i; 10 ) sout | spa1[i].v | spa2[i].v | nonl; sout | nl;
     8259®adelete®( spa1, spa2 );                                §\C{// call destructors on all array objects}§
     8260
     82613
     82625 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8
    80818263\end{cfa}
    80828264Allocation routines ©new©/©anew© allocate a variable/array and initialize storage using the allocated type's constructor.
    80838265Note, the matching deallocation routines ©delete©/©adelete©.
    8084 
    8085 \leavevmode
     8266\CC only supports the default constructor for intializing array elements.
     8267\begin{C++}
     8268S * sp = new S[10]®{5}®;                                §\C{// disallowed}§
     8269\end{C++}
     8270\end{enumerate}
     8271
     8272In addition, \CFA provides a new allocator interface to further increase orthogonality and usability of dynamic-memory allocation.
     8273This interface helps programmers in three ways.
     8274\begin{enumerate}
     8275\item
     8276naming: \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
     8278named 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
     8280safe usage: like the \CFA's C-interface, programmers do not have to specify object size or cast allocation results.
     8281\end{enumerate}
     8282
     8283The polymorphic functions
     8284\begin{cfa}
     8285T * alloc( ... );
     8286T * alloc( size_t dim, ... );
     8287\end{cfa}
     8288are overloaded with a variable number of allocation properties.
     8289These allocation properties can be passed as named arguments when calling the \Indexc{alloc} routine.
     8290A call without parameters returns an uninitialized dynamically allocated object of type ©T© (\Indexc{malloc}).
     8291A call with only the dimension (dim) parameter returns an uninitialized dynamically allocated array of objects with type ©T© (\Indexc{aalloc}).
     8292The variable number of arguments consist of allocation properties to specialize the allocation.
     8293The properties ©resize© and ©realloc© are associated with an existing allocation variable indicating how its storage is modified.
     8294
     8295The 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.
     8299The 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}
     8301int * i0 = alloc( ®256`align® );  sout | i0 | nl;
     8302int * i1 = alloc( 3, ®4096`align® );  for (i; 3 ) sout | &i1[i] | nonl;  sout | nl;
     8303free( i0, i1 );
     8304
     83050x5555565699®00®  // 256 alignment
     83060x55555656c®000® 0x5656c004 0x5656c008  // 4K array alignment
     8307\end{cfa}
     8308
     8309\item
     8310©T_fill(T) ?`fill( /* various types */ )© to initialize storage.
     8311There are three ways to fill storage:
     8312\begin{enumerate}
     8313\item
     8314A ©char© fills every byte of each object.
     8315\item
     8316An object of the returned type fills each object.
     8317\item
     8318An object array pointer fills some or all of the corresponding object array.
     8319\end{enumerate}
     8320For example:
     8321\begin{cfa}[numbers=left]
     8322int * i0 = alloc( ®0n`fill® );  sout | *i0 | nl;  // 0n disambiguates 0p
     8323int * i1 = alloc( ®5`fill® );  sout | *i1 | nl;
     8324int * i2 = alloc( ®'\xfe'`fill® ); sout | hex( *i2 ) | nl;
     8325int * i3 = alloc( 5, ®5`fill® );  for ( i; 5 ) sout | i3[i] | nonl; sout | nl;
     8326int * i4 = alloc( 5, ®0xdeadbeefN`fill® );  for ( i; 5 ) sout | hex( i4[i] ) | nonl; sout | nl;
     8327int * i5 = alloc( 5, ®i3`fill® );  for ( i; 5 ) sout | i5[i] | nonl; sout | nl; // completely fill from i3
     8328int * i6 = alloc( 5, ®[i3, 3]`fill® );  for ( i; 5 ) sout | i6[i] | nonl; sout | nl; // partial fill from i3
     8329free( i0, i1, i2, i3, i4, i5, i6 );
     8330\end{cfa}
     8331\begin{lstlisting}[numbers=left]
     83320
     83335
     83340xfefefefe
     83355 5 5 5 5
     83360xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
     83375 5 5 5 5
     83385 5 5 -555819298 -555819298  // two undefined values
     8339\end{lstlisting}
     8340Examples 1 to 3 fill an object with a value or characters.
     8341Examples 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.
     8345The old object type may be different from the new object type, since the values are not used.
     8346For example:
     8347\begin{cfa}[numbers=left]
     8348int * ip = alloc( ®5`fill® );  sout | ip | *ip;
     8349ip = alloc( ®ip`resize®, ®256`align®, ®7`fill® );  sout | ip | *ip;
     8350double * dp = alloc( ®ip`resize®, ®4096`align®, ®13.5`fill® );  sout | dp | *dp;
     8351free( dp );  // DO NOT FREE ip AS ITS STORAGE IS MOVED TO dp
     8352\end{cfa}
     8353\begin{lstlisting}[numbers=left]
     83540x555555580a80 5
     83550x555555581100 7
     83560x555555587000 13.5
     8357\end{lstlisting}
     8358Examples 2 to 3 change the alignment, fill, and size for the initial storage of ©i©.
     8359
     8360\begin{cfa}[numbers=left]
     8361int * ia = alloc( 5, ®5`fill® );  sout | ia | nonl;  for ( i; 5 ) sout | ia[i] | nonl; sout | nl;
     8362ia = alloc( 10, ®ia`resize®, ®7`fill® );  sout | ia | nonl;  for ( i; 10 ) sout | ia[i] | nonl; sout | nl;
     8363ia = alloc( 5, ®ia`resize®, ®512`align®, ®13`fill® ); sout | ia | nonl; for ( i; 5 ) sout | ia[i] | nonl; sout | nl;;
     8364ia = alloc( 3, ®ia`resize®, ®4096`align®, ®2`fill® );  for ( i; 3 ) sout | &ia[i] | ia[i] | nonl; sout | nl;
     8365free( ia );
     8366\end{cfa}
     8367\begin{lstlisting}[numbers=left]
     83680x55555656d540 5 5 5 5 5
     83690x55555656d480 7 7 7 7 7 7 7 7 7 7
     83700x55555656fe00 13 13 13 13 13
     83710x555556570000 2 0x555556570004 2 0x555556570008 2
     8372\end{lstlisting}
     8373Examples 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 ))©
     8377used to resize, realign, and fill, where the old object data is copied to the new object.
     8378The old object type must be the same as the new object type, since the value is used.
     8379Note, for ©fill©, only the extra space after copying the data from the old object is filled with the given parameter.
     8380For example:
     8381\begin{cfa}[numbers=left]
     8382int * ip = alloc( ®5`fill® );  sout | ip | *ip;
     8383ip = alloc( ®ip`realloc®, ®256`align® );  sout | ip | *ip;
     8384ip = alloc( ®ip`realloc®, ®4096`align®, ®13`fill® );  sout | ip | *ip;
     8385free( ip );
     8386\end{cfa}
     8387\begin{lstlisting}[numbers=left]
     83880x55555556d5c0 5
     83890x555555570000 5
     83900x555555571000 5
     8391\end{lstlisting}
     8392Examples 2 to 3 change the alignment for the initial storage of ©i©.
     8393The ©13`fill© in example 3 does nothing because no new storage is added.
     8394
     8395\begin{cfa}[numbers=left]
     8396int * ia = alloc( 5, ®5`fill® );  sout | ia | nonl;  for ( i; 5 ) sout | ia[i] | nonl; sout | nl;
     8397ia = alloc( 10, ®ia`realloc®, ®7`fill® );  sout | ia | nonl;  for ( i; 10 ) sout | ia[i] | nonl; sout | nl;
     8398ia = alloc( 5, ®ia`realloc®, ®512`align®, ®13`fill® );  sout | ia | nonl; for ( i; 5 ) sout | ia[i] | nonl; sout | nl;;
     8399ia = alloc( 3, ®ia`realloc®, ®4096`align®, ®2`fill® );  for ( i; 3 ) sout | &ia[i] | ia[i] | nonl; sout | nl;
     8400free( ia );
     8401\end{cfa}
     8402\begin{lstlisting}[numbers=left]
     84030x55555656d540 5 5 5 5 5
     84040x55555656d480 7 7 7 7 7 7 7 7 7 7
     84050x555556570e00 5 5 5 5 5
     84060x5555556571000 5 0x555556571004 5 0x555556571008 5
     8407\end{lstlisting}
     8408Examples 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
    80868412\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    80878413extern "C" {
    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 
    8102 void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap
    8103 
    8104 forall( 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 );
     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.
     8430void * resize( void * oaddr, size_t alignment, size_t size );
     8431void * realloc( void * oaddr, size_t alignment, size_t size );
     8432void * reallocarray( void * oaddr, size_t nalign, size_t dim, size_t elemSize );
     8433
     8434forall( 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}§
    81138452
    81148453        // §\CFA§ safe general allocation, fill, resize, alignment, array
    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 );
     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
     8462forall( T &, List ... ) void free( T * ptr, ... ) // deallocation list
     8463
     8464// §\CFA§ allocation/deallocation and constructor/destructor, non-array types
     8465forall( T &, Parms ... | { void ?{}( T &, Parms ); } ) T * new( Parms ... );§\indexc{new}§
     8466forall( T &, List ... | { void ^?{}( T & ); void delete( List ... ); } );§\indexc{delete}§
     8467// §\CFA§ allocation/deallocation and constructor/destructor, array types
     8468forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } ) T * anew( size_t dim, Parms ... );§\indexc{anew}§
     8469forall( 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
     8475Like safe memory allocation, \CFA provides safe block initialization and copy.
     8476While objects should be initialized/copied with constructors/assignment, block operations can be very performant.
     8477In 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]
     8480struct S { int i, j, k; };
     8481S 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]
     8487memset( s, '\0' );
     8488memset( sp, '\0' );
     8489
     8490memcpy( s, t );
     8491memcpy( sp, tp );
     8492
     8493amemset( sa, '\0', 10 );
     8494amemcpy( sa, ta, 10 );
     8495\end{cfa}
     8496&
     8497\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     8498memset( &s, '\0', sizeof(s) );
     8499memset( sp, '\0', sizeof(s) );
     8500
     8501memcpy( &s, &t, sizeof(s) );
     8502memcpy( sp, tp, sizeof(s) );
     8503
     8504memset( sa, '\0', sizeof(sa) );
     8505memcpy( sa, ta, sizeof(sa) );
     8506\end{cfa}
     8507\end{tabular}
     8508\end{cquote}
     8509These operations provide uniformity between reference and pointer, so object dereferencing, '©&©', is unnecessary.
     8510
     8511\begin{cfa}
     8512static 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}§
    81448524        T * amemcpy( T dest[], const T src[], size_t dim );
    81458525}
    8146 
    8147 // §\CFA§ allocation/deallocation and constructor/destructor, non-array types
    8148 forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p );§\indexc{new}§
    8149 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void delete( T * ptr );§\indexc{delete}§
    8150 forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } )
    8151   void delete( T * ptr, Params rest );
    8152 
    8153 // §\CFA§ allocation/deallocation and constructor/destructor, array types
    8154 forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p );§\indexc{anew}§
    8155 forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );§\indexc{adelete}§
    8156 forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } )
    8157   void adelete( size_t dim, T arr[], Params rest );
    81588526\end{cfa}
    81598527
     
    92909658Int sqrt( Int oper );
    92919659
    9292 forall( dtype istype | istream( istype ) ) istype * ?|?( istype * is, Int * mp );  §\C{// I/O}§
    9293 forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
     9660forall( istype & | istream( istype ) ) istype * ?|?( istype * is, Int * mp );  §\C{// I/O}§
     9661forall( ostype & | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
    92949662\end{cfa}
    92959663\VRef[Figure]{f:MultiPrecisionFactorials} shows \CFA and C factorial programs using the GMP interfaces.
     
    92999667\begin{cquote}
    93009668\begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}}
    9301 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{C}}    & \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{\CFA}}        \\
     9669\multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{C}}   \\
    93029670\hline
     9671\begin{cfa}
     9672#include <gmp.hfa>§\indexc{gmp}§
     9673int 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&
    93039685\begin{cfa}
    93049686#include <gmp.h>§\indexc{gmp.h}§
     
    93119693                ®mpz_mul_ui®( fact, fact, i );
    93129694                ®gmp_printf®( "%d %Zd\n", i, fact );
    9313         }
    9314 }
    9315 \end{cfa}
    9316 &
    9317 \begin{cfa}
    9318 #include <gmp.hfa>§\indexc{gmp}§
    9319 int 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;
    93279695        }
    93289696}
     
    94199787Rational narrow( double f, long int md );
    94209788
    9421 forall( dtype istype | istream( istype ) ) istype * ?|?( istype *, Rational * ); // I/O
    9422 forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype *, Rational );
     9789forall( istype & | istream( istype ) ) istype * ?|?( istype *, Rational * ); // I/O
     9790forall( ostype & | ostream( ostype ) ) ostype * ?|?( ostype *, Rational );
    94239791\end{cfa}
    94249792
     
    94409808\end{document}
    94419809
     9810From: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>
     9811To: 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>
     9816Subject: The White House on Memory-Safe programming
     9817Date: Mon, 4 Mar 2024 16:49:53 +0000
     9818
     9819I heard tell of this announcement last night.  Haven't read the actual report yet.
     9820
     9821Most mainstream article I can find:  https://me.pcmag.com/en/security/22413/white-house-to-developers-using-c-or-c-invites-cybersecurity-risks
     9822Less fluffy summary:  https://www.developer-tech.com/news/2024/feb/27/white-house-urges-adoption-memory-safe-programming-languages/
     9823Horse'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
     9826A contrary analysis:  https://hackaday.com/2024/02/29/the-white-house-memory-safety-appeal-is-a-security-red-herring/
     9827
    94429828% Local Variables: %
    94439829% tab-width: 4 %
  • libcfa/src/concurrency/actor.hfa

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

    rcf191ac r7042c60  
    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                                 __attribute__((unused)) struct oneshot * was = this.ptr;
     376                                struct oneshot * was __attribute__((unused)) = this.ptr; // used in option verify
    377377                                /* paranoid */ verifyf( was == future_FULFILLED, "Expected this.ptr to be 1p, was %p\n", was );
    378378
  • libcfa/src/device/cpu.cfa

    rcf191ac r7042c60  
    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)
    242 {
     241raw_cache_instance ** build_raw_cache_table(unsigned cpus_c, idx_range_t cpus, unsigned idxs, unsigned cache_levels) {
    243242        raw_cache_instance ** raw = alloc(cpus_c, '\0'`fill);
    244243
  • libcfa/src/iostream.hfa

    rcf191ac r7042c60  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  6 18:35:54 2024
    13 // Update Count     : 743
     12// Last Modified On : Sun Apr 21 07:32:19 2024
     13// Update Count     : 744
    1414//
    1515
     
    160160
    161161// tuples
    162 forall( 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 );
     162forall( 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 );
    165165} // distribution
    166166
  • libcfa/src/stdlib.cfa

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

    rcf191ac r7042c60  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 15 22:11:51 2024
    13 // Update Count     : 817
     12// Last Modified On : Tue Apr 23 14:05:21 2024
     13// Update Count     : 963
    1414//
    1515
     
    4747
    4848static inline forall( T & | sized(T) ) {
    49         // CFA safe equivalents, i.e., implicit size specification
     49        // CFA safe equivalents, i.e., implicit size specification, eliminate return-type cast
    5050
    5151        T * malloc( void ) {
     
    6464        } // calloc
    6565
    66         T * resize( T * ptr, size_t size ) {                            // CFA resize
    67                 if ( _Alignof(T) <= libAlign() ) return (T *)resize( (void *)ptr, size ); // CFA resize
     66        T * resize( T * ptr, size_t size ) {
     67                if ( _Alignof(T) <= libAlign() ) return (T *)resize( (void *)ptr, size ); // C 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
    6973        } // resize
    7074
     
    7478        } // realloc
    7579
     80        T * realloc( T * ptr, size_t alignment, size_t size ) {
     81                return (T *)realloc( (void *)ptr, alignment, size ); // CFA realloc
     82        } // realloc
     83
    7684        T * reallocarray( T * ptr, size_t dim ) {                       // CFA reallocarray
    7785                if ( _Alignof(T) <= libAlign() ) return (T *)reallocarray( (void *)ptr, dim, sizeof(T) ); // C reallocarray
     
    7987        } // realloc
    8088
     89        T * reallocarray( T * ptr, size_t alignment, size_t dim ) {
     90                return (T *)reallocarray( (void *)ptr, alignment, dim ); // CFA reallocarray
     91        } // realloc
     92
    8193        T * memalign( size_t align ) {
    8294                return (T *)memalign( align, sizeof(T) );               // C memalign
     
    8799        } // amemalign
    88100
    89         T * cmemalign( size_t align, size_t dim  ) {
     101        T * cmemalign( size_t align, size_t dim ) {
    90102                return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign
    91103        } // cmemalign
     
    109121
    110122/*
    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.
     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.
    112125        Or, just follow the instructions below for that.
    113126
     
    153166*/
    154167
    155 typedef struct S_align { inline size_t;  } T_align;
    156 typedef struct S_resize { inline void *;  }     T_resize;
    157 
    158 forall( T & ) {
    159         struct S_fill { char tag; char c; size_t size; T * at; char t[50]; };
    160         struct S_realloc { inline T *; };
     168#pragma GCC diagnostic push
     169#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
     170#pragma GCC diagnostic ignored "-Wuninitialized"
     171
     172struct T_align { size_t align; };
     173struct T_resize { void * addr; };
     174struct T_realloc { void * addr; };
     175forall( 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
     189static 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 }; }
    161193}
    162194
    163 static inline T_align ?`align( size_t a ) { return (T_align){a}; }
    164 static inline T_resize ?`resize( void * a )     { return (T_resize){a}; }
    165 
    166 extern "C" ssize_t write(int fd, const void *buf, size_t count);
    167195static inline forall( T & | sized(T) ) {
    168         S_fill(T) ?`fill ( T t ) {
    169                 S_fill(T) ret = { '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' };
    170199                size_t size = sizeof(T);
    171200                if ( size > sizeof(ret.t) ) {
     
    175204                return ret;
    176205        }
    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);
     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);
    187213                size_t copy_end = 0;
    188214
    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 );
     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 );
    194220                } else {
    195                         ptr = (T *)(void *) memalign( Align, Dim * size );
    196                 }
     221                        ptr = (T *)(void *)memalign( Align, Dim * tsize );
     222                } // if
    197223
    198224                if ( Fill.tag == 'c' ) {
    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                         }
     225                        memset( (char *)ptr + copy_end, (int)Fill.c, Dim * tsize - copy_end );
     226                } 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
    208231                } else if ( Fill.tag == 'a' ) {
    209                         memcpy( (char *)ptr + copy_end, Fill.at, min(Dim * size - copy_end, Fill.size) );
    210                 } else if ( Fill.tag == 'T' ) {
    211                         memcpy( (char *)ptr + copy_end, Fill.at, Dim * size );
    212                 }
    213 
     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
    214236                return ptr;
    215237        } // alloc_internal$
    216238
    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);
     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 );
    220245                }
    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);
     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 );
    224248                }
    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);
     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 );
    228251                }
    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 );
     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 );
    232254                }
    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 );
     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 );
    236258            }
    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 );
     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 );
    240261            }
    241         } // distribution TT
     262        } // distribution List
    242263} // distribution T
    243264
    244265static inline forall( T & | sized(T) ) {
    245266        // CFA safe initialization/copy, i.e., implicit size specification, non-array types
    246         T * memset( T * dest, char fill ) {
    247                 return (T *)memset( dest, fill, sizeof(T) );
     267        T * memset( T * dest, char fill ) {                                     // all combinations of pointer/reference
     268                return (T *)memset( dest, fill, sizeof(T) );    // C memset
    248269        } // memset
    249 
    250         T * memcpy( T * dest, const T * src ) {
    251                 return (T *)memcpy( dest, src, sizeof(T) );
     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
    252285        } // memcpy
    253286
     
    263296
    264297// CFA deallocation for multiple objects
    265 static inline forall( T & )                                                     // FIX ME, problems with 0p in list
     298static inline forall( T & )
    266299void free( T * ptr ) {
    267300        free( (void *)ptr );                                                            // C free
    268301} // free
    269 static inline forall( T &, TT ... | { void free( TT ); } )
    270 void free( T * ptr, TT rest ) {
     302static inline forall( T &, List ... | { void free( List ); } )
     303void free( T * ptr, List rest ) {
    271304        free( ptr );
    272305        free( rest );
     
    274307
    275308// CFA allocation/deallocation and constructor/destructor, non-array types
    276 static inline forall( T & | sized(T), TT ... | { void ?{}( T &, TT ); } )
    277 T * new( TT p ) {
     309static inline forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } )
     310T * new( Parms p ) {
    278311        return &(*(T *)malloc()){ p };                                          // run constructor
    279312} // new
     
    287320        free( ptr );                                                                            // always call free
    288321} // delete
    289 static inline forall( T &, TT ... | { void ^?{}( T & ); void delete( TT ); } )
    290 void delete( T * ptr, TT rest ) {
     322static inline forall( T &, List ... | { void ^?{}( T & ); void delete( List ); } )
     323void delete( T * ptr, List rest ) {
    291324        delete( ptr );
    292325        delete( rest );
     
    294327
    295328// CFA allocation/deallocation and constructor/destructor, array types
    296 forall( T & | sized(T), TT ... | { void ?{}( T &, TT ); } ) T * anew( size_t dim, TT p );
     329forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } ) T * anew( size_t dim, Parms p );
    297330forall( T & | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] );
    298 forall( T & | sized(T) | { void ^?{}( T & ); }, TT ... | { void adelete( TT ); } ) void adelete( T arr[], TT rest );
     331forall( T & | sized(T) | { void ^?{}( T & ); }, List ... | { void adelete( List ); } ) void adelete( T arr[], List rest );
     332
    299333//---------------------------------------
    300334
  • src/AST/Pass.hpp

    rcf191ac r7042c60  
    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;
    130115                auto const * temp = node->accept( visitor );
    131116                assert( temp == node );
  • src/AST/Print.cpp

    rcf191ac r7042c60  
    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

    rcf191ac r7042c60  
    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

    rcf191ac r7042c60  
    415415        code << "\t" << BYMK << endl;
    416416        code << "\t#define BT ast::BasicKind::" << endl;
    417         code << "\tstatic const BT Kind commonTypes[BT NUMBER_OF_BASIC_TYPES][BT NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor" << endl
     417        code << "\tstatic const ast::BasicKind 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

    rcf191ac r7042c60  
    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.
    170169        if ( !decl->type_params.empty() ) {
    171170                assertf( !options.genC, "FunctionDecl forall should not reach code generation." );
     
    174173                acc << ")" << std::endl;
    175174        }
     175        // The forall clause should be printed early as part of the preamble.
     176        output << acc.str();
     177        acc.str("");
    176178
    177179        acc << mangleName( decl );
  • src/Common/PersistentMap.h

    rcf191ac r7042c60  
    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

    rcf191ac r7042c60  
    3636        typedef const value_type* pointer;
    3737        typedef const const_value_type* const_pointer;
    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        
     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
    4745                value_type data;
    4846
     
    9997                        return data.first == o.data.first && &data.second == &o.data.second;
    10098                }
    101                
     99
    102100                bool operator!= (const iterator& that) const { return !(*this == that); }
    103101
     
    111109        };
    112110
    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;
     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;
    119115                const_value_type data;
    120116
     
    181177                        return data.first == o.data.first && &data.second == &o.data.second;
    182178                }
    183                
     179
    184180                bool operator!= (const const_iterator& that) const { return !(*this == that); }
    185181
     
    233229
    234230template<typename T>
    235 typename VectorMap<T>::iterator operator+ (typename VectorMap<T>::difference_type i,
    236                                            const typename VectorMap<T>::iterator& it) {
     231typename VectorMap<T>::iterator operator+(
     232                typename VectorMap<T>::difference_type i,
     233                const typename VectorMap<T>::iterator& it) {
    237234        return it + i;
    238235}
    239236
    240237template<typename T>
    241 typename VectorMap<T>::const_iterator operator+ (typename VectorMap<T>::difference_type i,
    242                                                  const typename VectorMap<T>::const_iterator& it) {
     238typename VectorMap<T>::const_iterator operator+(
     239                typename VectorMap<T>::difference_type i,
     240                const typename VectorMap<T>::const_iterator& it) {
    243241        return it + i;
    244242}
  • src/Concurrency/Actors.cpp

    rcf191ac r7042c60  
    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;
    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         }
    60         }
    61 
    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         }
     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                }
     60        }
     61
     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                }
    8787        }
    8888
    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" ),
    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,
     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,
    375375                                new UntypedExpr (
    376                     decl->location,
     376                                        decl->location,
    377377                                        new NameExpr( decl->location, "?{}" ),
    378378                                        {
    379379                                                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" )
     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" )
    383383                                        }
    384384                                )
    385385                        ));
    386386
    387             // Generates: send( receiver, new_req );
    388             sendBody->push_back( new ExprStmt(
    389                 decl->location,
     387                        // Generates: send( receiver, new_req );
     388                        sendBody->push_back( new ExprStmt(
     389                                decl->location,
    390390                                new UntypedExpr (
    391                     decl->location,
     391                                        decl->location,
    392392                                        new NameExpr( decl->location, "send" ),
    393393                                        {
    394394                                                {
    395                             new NameExpr( decl->location, "receiver" ),
    396                             new NameExpr( decl->location, "new_req" )
    397                         }
     395                                                        new NameExpr( decl->location, "receiver" ),
     396                                                        new NameExpr( decl->location, "new_req" )
     397                                                }
    398398                                        }
    399399                                )
    400400                        ));
    401401
    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 
    526525
    527526} // namespace Concurrency
  • src/Concurrency/Corun.cpp

    rcf191ac r7042c60  
    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

    rcf191ac r7042c60  
    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

    rcf191ac r7042c60  
    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) )
    952                 );
    953                
     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) )
     952                );
     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

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

    rcf191ac r7042c60  
    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

    rcf191ac r7042c60  
    3636namespace ResolvExpr {
    3737
     38namespace {
     39
    3840        // GENERATED START, DO NOT EDIT
    3941        // GENERATED BY BasicTypes-gen.cc
     
    397399                        }
    398400                } else if ( auto type2AsAttr = dynamic_cast< const ast::EnumAttrType * >( type2 ) ) {
    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             }
     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                        }
    410412                }
    411413        }
     
    519521                                                                // xxx - assume LHS is always the target type
    520522
    521                                                                 if ( ! ((widen.second && ref2->qualifiers.is_mutex) 
     523                                                                if ( ! ((widen.second && ref2->qualifiers.is_mutex)
    522524                                                                || (ref1->qualifiers.is_mutex == ref2->qualifiers.is_mutex ))) return;
    523525
     
    710712// size_t CommonType::traceId = Stats::Heap::new_stacktrace_id("CommonType");
    711713
    712 namespace {
    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;
     714ast::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;
     726                PRINT(
     727                        std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
     728                )
     729                if ( ( widen.first || q2 <= q1 ) && ( widen.second || q1 <= q2 ) ) {
    725730                        PRINT(
    726                                 std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
     731                                std::cerr << "widen okay" << std::endl;
    727732                        )
    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 
    737                 PRINT(
    738                         std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
    739                 )
    740                 return { nullptr };
    741         }
     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 };
    742742}
     743
     744} // namespace
    743745
    744746ast::ptr< ast::Type > commonType(
     
    781783        }
    782784        // otherwise both are reference types of the same depth and this is handled by the visitor
    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;
     785        return ast::Pass<CommonType>::read( type1.get(),
     786                type2, widen, env, open, need, have );
    788787}
    789788
  • src/ResolvExpr/ConversionCost.cc

    rcf191ac r7042c60  
    3131#define PRINT(x)
    3232#endif
     33
     34namespace {
    3335
    3436        // GENERATED START, DO NOT EDIT
     
    152154        );
    153155
    154 namespace {
    155156        int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
    156157                        const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
     
    379380
    380381void ConversionCost::postvisit( const ast::EnumAttrType * src ) {
    381     auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
     382        auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
    382383        assert( src->attr != ast::EnumAttribute::Label );
    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 );
     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 );
    389390                        if ( cost < Cost::infinity ) {
    390391                                cost.incUnsafe();
    391392                        }
    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     }
     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        }
    405406}
    406407
  • src/ResolvExpr/PolyCost.cc

    rcf191ac r7042c60  
    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 ) ) /* && */ if ( eqv->bound ) {
     35                if ( const ast::EqvClass * eqv = env_.lookup( *type ) ; eqv && 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         ast::Pass<PolyCost> costing( symtab, env );
    55         type->accept( costing );
    56         return (costing.core.result > 0) ? 1 : 0;
     54        return ast::Pass<PolyCost>::read( type, symtab, env );
    5755}
    5856
  • src/ResolvExpr/RenameVars.cc

    rcf191ac r7042c60  
    3030
    3131namespace {
    32         class RenamingData {
    33                 int level = 0;
    34                 int resetCount = 0;
    3532
    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;
     33class 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;
     41public:
     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;
    4488                }
    4589
    46                 void nextUsage() {
    47                         ++next_usage_id;
    48                 }
     90                return mutType;
     91        }
    4992
    50                 const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
    51                         auto it = idMap.find( type->name );
    52                         if ( it == idMap.end() ) return type;
     93        void closeLevel( const ast::FunctionType * type ) {
     94                if ( type->forall.empty() ) return;
     95                idMap.endScope();
     96        }
     97};
    5398
    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                 }
     99// Global State:
     100RenamingData renaming;
    62101
    63                 const ast::FunctionType * openLevel( const ast::FunctionType * type, RenameMode mode ) {
    64                         if ( type->forall.empty() ) return type;
    65                         idMap.beginScope();
     102struct RenameVars final : public ast::PureVisitor /*: public ast::WithForallSubstitutor*/ {
     103        RenameMode mode;
    66104
    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" );
     105        const ast::FunctionType * previsit( const ast::FunctionType * type ) {
     106                return renaming.openLevel( type, mode );
     107        }
    73108
    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 );
     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        */
    87120
    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         };
     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};
    130130
    131131} // namespace
  • src/ResolvExpr/Unify.cc

    rcf191ac r7042c60  
    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 {
    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                                         }
     49bool 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
     66bool 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
     90namespace {
     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;
    105104                                }
    106                                 return typeInst;
    107105                        }
    108                 };
    109         }
    110 
    111         std::vector< ast::ptr< ast::Type > > flattenList(
    112                 const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
     106                        return typeInst;
     107                }
     108        };
     109}
     110
     111std::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
     145static 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
     149class 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;
     156public:
     157        bool result;
     158
     159private:
     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
     174public:
     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
     250static 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
     257class 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;
     264public:
     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
     324private:
     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
    113330        ) {
    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
    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() );
    348                                 }
    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;
     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
    363340                                return unifyExact(
    364341                                        t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
    365342                                        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;
     343                        } else if ( !isTuple1 && isTuple2 ) {
     344                                // combine remainder of list1, then unify
    370345                                return unifyExact(
    371346                                        tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
     
    373348                        }
    374349
    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;
     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
     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 );
    392415                        }
    393416                }
    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 );
     417                return false;
     418        }
     419
     420public:
     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
     450private:
     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
     467        ) {
     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
    403512                        }
    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                                 }
     513
     514                        if ( !unifyExact(
     515                                        pty, pty2, tenv, need, have, open, noWiden() ) ) {
     516                                result = false;
     517                                return;
    416518                        }
    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;
     519
     520                        // ttype parameter should be last
     521                        if ( isTuple || isTuple2 ) break;
     522                }
     523                result = it == params.end() && jt == params2.end();
     524        }
     525
     526public:
     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;
    521547                        }
    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;
     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
     565private:
     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
     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() );
    560591                        }
    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
    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;
    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;
     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
     623public:
     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
     658bool 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
     667bool 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
     679bool 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
     706bool 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;
    738728                        return true;
    739729                } else {
    740730                        return false;
    741731                }
    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         }
     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
     743ast::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
    754754} // namespace ResolvExpr
    755755
  • src/ResolvExpr/typeops.h

    rcf191ac r7042c60  
    2121
    2222namespace ResolvExpr {
    23         class TypeEnvironment;
    2423
    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;
     24class TypeEnvironment;
    3125
    32                 if ( begin == end )     {
    33                         *out++ = ListType();
    34                         return;
    35                 } // if
     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
     28template< typename InputIterator, typename OutputIterator >
     29void combos( InputIterator begin, InputIterator end, OutputIterator out ) {
     30        typedef typename InputIterator::value_type SetType;
     31        typedef typename std::vector< typename SetType::value_type > ListType;
    3632
    37                 InputIterator current = begin;
    38                 begin++;
     33        if ( begin == end )     {
     34                *out++ = ListType();
     35                return;
     36        } // if
    3937
    40                 std::vector< ListType > recursiveResult;
    41                 combos( begin, end, back_inserter( recursiveResult ) );
     38        InputIterator current = begin;
     39        begin++;
    4240
    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;
     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.
     54inline 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 );
    4960                }
     61        } else {
     62                out.emplace_back( type );
     63        }
     64}
     65
     66/// Flatten tuple type into list of types.
     67inline 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
     74template< typename Iter >
     75const 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;
    5083        }
    5184
    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         }
     85        return new ast::TupleType( std::move(types) );
     86}
    6487
    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         }
     88inline const ast::Type * tupleFromTypes(
     89        const std::vector< ast::ptr< ast::Type > > & tys
     90) {
     91        return tupleFromTypes( tys.begin(), tys.end() );
     92}
    7293
    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         }
    9294} // namespace ResolvExpr
    9395
  • src/SymTab/Mangler.cc

    rcf191ac r7042c60  
    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

    rcf191ac r7042c60  
    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

    rcf191ac r7042c60  
    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

    rcf191ac r7042c60  
    88namespace {
    99class EnumAttrFuncGenerator {
    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);
     10        const ast::EnumDecl* decl;
     11        const ast::EnumInstType* instType;
     12        unsigned int functionNesting;
     13        ast::Linkage::Spec proto_linkage;
     14
     15public:
     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
     63private:
     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);
    204201};
    205202
    206203std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genLabelInit() const {
    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;
     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;
    217214}
    218215
    219216std::vector<ast::ptr<ast::Init>> EnumAttrFuncGenerator::genValueInit() const {
    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;
     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;
    238235}
    239236const ast::Init* EnumAttrFuncGenerator::getAutoInit(
    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     }
     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        }
    259256}
    260257
    261258ast::FunctionDecl* EnumAttrFuncGenerator::genProto(
    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;
     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;
    277274}
    278275
    279276void EnumAttrFuncGenerator::produceDecl(const ast::FunctionDecl* decl) {
    280     assert(nullptr != decl->stmts);
    281 
    282     definitions.push_back(decl);
     277        assert(nullptr != decl->stmts);
     278
     279        definitions.push_back(decl);
    283280}
    284281
    285282void EnumAttrFuncGenerator::produceForwardDecl(const ast::FunctionDecl* decl) {
    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);
     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);
    291288}
    292289
     
    300297
    301298ast::FunctionDecl* EnumAttrFuncGenerator::genLabelProto() const {
    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}))});
     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}))});
    308305}
    309306
    310307ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
    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))});
     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))});
    316313}
    317314
    318315ast::FunctionDecl* EnumAttrFuncGenerator::genSuccProto() const {
    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))});
     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))});
    324321}
    325322
    326323ast::FunctionDecl* EnumAttrFuncGenerator::genPredProto() const {
    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))});
     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))});
    332329}
    333330
    334331inline ast::EnumAttrType * getPosnType( const ast::EnumDecl * decl ) {
    335     return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
     332        return new ast::EnumAttrType(new ast::EnumInstType(decl), ast::EnumAttribute::Posn);
    336333}
    337334
    338335ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPosProto() const {
    339     return genProto(
    340         "_successor_",
    341         {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
    342         {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
    343     );
     336        return genProto(
     337                "_successor_",
     338                {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
     339                {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
     340        );
    344341}
    345342
    346343ast::FunctionDecl* EnumAttrFuncGenerator::genPredPosProto() const {
    347     return genProto(
    348         "_predessor_",
    349         {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
    350         {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
    351     );
     344        return genProto(
     345                "_predessor_",
     346                {new ast::ObjectDecl(getLocation(), "_i", getPosnType(decl))},
     347                {new ast::ObjectDecl(getLocation(), "_ret", getPosnType(decl))}
     348        );
    352349}
    353350
    354351ast::ObjectDecl* EnumAttrFuncGenerator::genAttrArrayProto(
    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;
     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;
    370368}
    371369
    372370void EnumAttrFuncGenerator::genValueOrLabelBody(
    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)});
     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)});
    384382}
    385383
    386384void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
    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)});
     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)});
    394392}
    395393
    396394void EnumAttrFuncGenerator::genAttributesDecls(const ast::EnumAttribute attr) {
    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     }
     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        }
    417415}
    418416
    419417ast::FunctionDecl* EnumAttrFuncGenerator::genSuccPredFunc(bool succ) {
    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;
     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;
    451449}
    452450
    453451void EnumAttrFuncGenerator::genAttrFunctions() {
    454     if (decl->base) {
    455         genAttributesDecls(ast::EnumAttribute::Value);
    456         genAttributesDecls(ast::EnumAttribute::Label);
    457         genAttributesDecls(ast::EnumAttribute::Posn);
    458     }
     452        if (decl->base) {
     453                genAttributesDecls(ast::EnumAttribute::Value);
     454                genAttributesDecls(ast::EnumAttribute::Label);
     455                genAttributesDecls(ast::EnumAttribute::Posn);
     456        }
    459457}
    460458
    461459void EnumAttrFuncGenerator::genSuccPredDecl() {
    462     if (decl->base) {
    463         auto succProto = genSuccProto();
    464         auto predProto = genPredProto();
    465 
    466         produceForwardDecl(succProto);
    467         produceForwardDecl(predProto);
    468     }
     460        if (decl->base) {
     461                auto succProto = genSuccProto();
     462                auto predProto = genPredProto();
     463
     464                produceForwardDecl(succProto);
     465                produceForwardDecl(predProto);
     466        }
    469467}
    470468
    471469void EnumAttrFuncGenerator::genSuccPredPosn() {
    472     if (decl->base) {
    473         ast::FunctionDecl* succ = genSuccPredFunc(true);
    474         ast::FunctionDecl* pred = genSuccPredFunc(false);
    475 
    476         produceDecl(succ);
    477         produceDecl(pred);
    478     }
     470        if (decl->base) {
     471                ast::FunctionDecl* succ = genSuccPredFunc(true);
     472                ast::FunctionDecl* pred = genSuccPredFunc(false);
     473
     474                produceDecl(succ);
     475                produceDecl(pred);
     476        }
    479477}
    480478
    481479void EnumAttrFuncGenerator::generateAndAppendFunctions(
    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);
     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);
    491489}
    492490
    493491// ---------------------------------------------------------
    494492
    495 struct 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;
     493struct 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
     499private:
     500        // Current level of nested functions.
     501        unsigned int functionNesting = 0;
    504502};
    505503
    506504void ImplementEnumFunc::previsit(const ast::EnumDecl* enumDecl) {
    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);
     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);
    515513}
    516514
    517515void ImplementEnumFunc::previsit(const ast::FunctionDecl*) {
    518     functionNesting += 1;
     516        functionNesting += 1;
    519517}
    520518
    521519void ImplementEnumFunc::postvisit(const ast::FunctionDecl*) {
    522     functionNesting -= 1;
    523 }
    524 
    525 }  // namespace
     520        functionNesting -= 1;
     521}
     522
     523} // namespace
    526524
    527525void implementEnumFunc(ast::TranslationUnit& translationUnit) {
    528     ast::Pass<ImplementEnumFunc>::run(translationUnit);
    529 }
    530 }  // namespace Validate
     526        ast::Pass<ImplementEnumFunc>::run(translationUnit);
     527}
     528
     529} // namespace Validate
  • src/Virtual/VirtualDtor.cpp

    rcf191ac r7042c60  
    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;
     38        unordered_map<const StructDecl *, CtorDtor> & structMap;
     39
     40public:
     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                }
     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        }
    39111
    40112  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 
    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 
    112   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
     379public:
     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 
    402401
    403402} // namespace Virtual
  • tests/alloc.cfa

    rcf191ac r7042c60  
    1010// Created On       : Wed Feb  3 07:56:22 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Oct 14 09:31:39 2022
    13 // Update Count     : 491
     12// Last Modified On : Tue Apr 23 14:04:11 2024
     13// Update Count     : 492
    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.