Changeset 15215f02


Ignore:
Timestamp:
Apr 22, 2024, 11:37:36 PM (5 weeks ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
master
Children:
13de4478
Parents:
0fe07be (diff), d7c0ad5 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

Files:
1 deleted
35 edited

Legend:

Unmodified
Added
Removed
  • doc/LaTeXmacros/common.sty

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    4848
    4949\section{C Enumeration}
     50\label{s:CEnumeration}
    5051
    51 The C enumeration has the following syntax and semantics.
     52The C enumeration has the following syntax~\cite[\S~6.7.2.2]{C11}.
     53\begin{clang}[identifierstyle=\linespread{0.9}\it]
     54$\it enum$-specifier:
     55        enum identifier$\(_{opt}\)$ { enumerator-list }
     56        enum identifier$\(_{opt}\)$ { enumerator-list , }
     57        enum identifier
     58enumerator-list:
     59        enumerator
     60        enumerator-list , enumerator
     61enumerator:
     62        enumeration-constant
     63        enumeration-constant = constant-expression
     64\end{clang}
     65The terms \emph{enumeration} and \emph{enumerator} used in this work \see{\VRef{s:Terminology}} come from the grammar.
     66The C enumeration semantics is discussed using examples.
     67
     68An unnamed enumeration is used to provide secondary renaming, like a @const@ declaration in other languages.
     69\begin{clang}
     70enum { Size = 20, Pi = 3.14159 };   // unnamed enumeration $\(\Rightarrow\)$ no ordering
     71\end{clang}
     72This declaration form is not an enumeration even though it is declared using an @enum@ because it has none of the following enumeration properties.
     73
     74A \emph{named} enumeration type is an actual enumeration.
    5275\begin{clang}
    5376enum Weekday { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun, };
  • doc/theses/jiada_liang_MMath/intro.tex

    r0fe07be r15215f02  
    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.
    67In theory, there are an infinite set of primary names per type.
    78
    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.
     9\Newterm{Secondary naming} is a common practice in mathematics, engineering and computer science, \eg $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MB (mega byte, 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 common purpose is to eliminate duplication of the primary constant throughout a program.
     12For example, the secondary name replaces its primary name, thereafter changing the binding of the secondary to primary name automatically distributes the rebinding throughout the program.
     13In 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@.
    1214Because 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{
    1315The term rvalue defines an expression that can only appear on the right-hand side of an assignment expression.}.
     
    1820enumerate (verb, transitive).
    1921To 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}
     22more usually, to mention (a number of things or persons) separately, as if for the purpose of counting;
     23to specify as in a list or catalogue.~\cite{OEDenumerate}
    2424\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.
     25Within 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.
    2626It is possible to enumerate among set names without having an ordering among the set elements.
    2727For example, the week, the weekdays, the weekend, and every second day of the week.
     
    2929for ( cursor in Mon, Tue, Wed, Thu, Fri, Sat, Sun } ... $\C[3.75in]{// week}$
    3030for ( cursor in Mon, Tue, Wed, Thu, Fri } ...   $\C{// weekday}$
    31 for ( cursor in Thu, Fri } ...                                  $\C{// weekend}$
     31for ( cursor in Sat, Sun } ...                                  $\C{// weekend}$
    3232for ( cursor in Mon, Wed, Fri, Sun } ...                $\C{// every second day of week}\CRT$
    3333\end{cfa}
    34 This independence from internal representation allows multiple names to have the same representation (eight note, quaver), giving synonyms.
     34This independence from internal representation allows multiple names to have the same representation (eighth note, quaver), giving synonyms.
    3535A set can have a partial or total ordering, making it possible to compare set elements, \eg Monday is before Friday and Friday is after.
    3636Ordering allows iterating among the enumeration set using relational operators and advancement, \eg
     
    3838for ( cursor = Monday; cursor @<=@ Friday; cursor = @succ@( cursor ) ) ...
    3939\end{cfa}
    40 Here the internal representations for the secondary names are \emph{generated} rather than listing a subset of names.
     40Here the internal representations for the secondary names are logically \emph{generated} rather than listing a subset of names.
     41
     42Hence, the fundamental aspects of an enumeration are:
     43\begin{enumerate}
     44\item
     45It defines a type from which instants can be generated.
     46\item
     47The type lists a finite set of secondary names, which become its primary constants.
     48This differentiates an enumeration from general types with an infinite number of primary constants.
     49\item
     50An enumeration's secondary names represent constants, which follows from their binding (aliasing) to primary names, which are constants.
     51\item
     52For safety, an enumeration instance is restricted to hold only its type's secondary names.
     53\item
     54There is a mechanism for \emph{enumerating} over the secondary names, where the ordering can be implicit from the type, explicitly listed, or generated arithmetically.
     55\end{enumerate}
    4156
    4257
    4358\section{Terminology}
    44 
    45 The term \Newterm{enumeration} defines the set of secondary names, and the term \Newterm{enumerator} represents an arbitrary secondary name.
     59\label{s:Terminology}
     60
     61The 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}}.
    4662As well, an enumerated type has three fundamental properties, \Newterm{label}, \Newterm{order}, and \Newterm{value}.
    4763\begin{cquote}
     
    7288\section{Motivation}
    7389
    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.
     90Some programming languages only provide direct secondary renaming.
     91\begin{cfa}
     92const Size = 20, Pi = 3.14159, Name = "Jane";
     93\end{cfa}
     94Here, it is possible to compare the secondary names, \eg @Size < Pi@, if that is meaningful.
     95
     96Secondary renaming can simulate an enumeration, but with extra effort.
    8397\begin{cfa}
    8498const Mon = 1, Tue = 2, Wed = 3, Thu = 4, Fri = 5, Sat = 6, Sun = 7;
    8599\end{cfa}
    86 Furthermore, reordering the enumerators requires manual renumbering.
     100Any reordering of the enumerators requires manual renumbering.
    87101\begin{cfa}
    88102const Sun = 1, Mon = 2, Tue = 3, Wed = 4, Thu = 5, Fri = 6, Sat = 7;
    89103\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}
     104Finally, there is no type to create a type-checked instance or iterator cursor.
     105Hence, there is only a weak equivalence between secondary naming and enumerations, justifying a seperate enumeration type in a programming language.
     106
     107A variant (algebraic) type is often promoted as a kind of enumeration, \ie a variant type can simulate an enumeration.
     108Fundamentally, a variant type is a tagged-union, where the tag is normally opaque and the types are usually heterogeneous.
     109\begin{cfa}[morekeywords={variant}]
    96110@variant@ Variant {
    97111        @int tag;@  // optional/implicit: 0 => int, 1 => double, 2 => S
     
    103117};
    104118\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:
     119Crucially, the union implies instance storage is shared by all the variant types, and therefore, before a variant type can be used in a statically-typed expression, it must be dynamically discriminated to its current contained type.
     120Hence, knowing which type is in a variant instance is crucial for correctness.
     121Occasionally, it is possible to statically determine all regions where each variant type is used, so a tag and runtime checking is unnecessary.
     122Otherwise, a tag is required to denote the particular type in the variant, and the tag is discriminated at runtime using some form of type pattern-matching, after which the value can be used in a statically-typed expression.
     123
     124A less frequent variant case is multiple variants with the same type, which normally requires explicit naming of the tag to disambiguate among the common types.
     125\begin{cquote}
     126\begin{tabular}{@{}l@{\hspace{30pt}}l@{}}
     127\begin{cfa}[morekeywords={variant}]
     128variant VariantCT {
     129        case @car@: int i;  // explicitly typed
     130        case @boat@: int i;
     131        case @bridge@: int i;
     132};
     133\end{cfa}
     134&
     135\begin{cfa}[morekeywords={variant}]
     136variant VariantCU {
     137        case @car@: ;  // empty or unit type
     138        case @boat@: ;
     139        case @bridge@: ;
     140};
     141\end{cfa}
     142\end{tabular}
     143\end{cquote}
     144Here, the explicit tag name is used to give different meaning to the values in the common @int@ type, \eg the value 3 has different interpretations depending on the tag name.
     145It is even possible to remove the type or use the empty @unit@ type (@struct unit {}@).
     146It is this tag naming that is used to simulate an enumeration.
     147
     148Normally, the variant tag is implicitly set by the compiler based on type, but with common types, a tag name is required to resolve type ambiguity.
     149\begin{cfa}
     150Variant v = 3;                                                  $\C{// implicitly set tag to 0 based on type of 3}$
     151VariantCT ve = boats.3;                                 $\C{// explicitly set tag to 1 using tag name}$
     152\end{cfa}
     153Type pattern-matching is then used to dynamically test the tag and branch to a section of statically-typed code to safely manipulate the value, \eg:
     154\begin{cquote}
     155\begin{tabular}{@{}l@{\hspace{30pt}}l@{}}
    113156\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 */ }
     157@match@( v ) { // know type implicitly or test tag
     158        case int { /* only access i field */ }
     159        case double { /* only access d field */ }
     160        case S { /* only access s field */ }
    119161}
    120162\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
     163&
     164\begin{cfa}[morekeywords={match}]
     165@match@( ve ) {
     166        case car: int { /* car interpretation */ }
     167        case boat: int { /* boat interpretation */ }
     168        case bridge: int { /* bridge interpretation */ }
     169}
     170\end{cfa}
     171\end{tabular}
     172\end{cquote}
     173For safety, some languages require all variant types to be listed or a @default@ case with no field accesses.
     174
     175To further strengthen the simulate for an enumeration with different values, each variant type can be a @const@ type or the tag becomes non-opaque, possibly taking advantage of the opaque auto-numbering.
     176\begin{cquote}
     177\begin{tabular}{@{}l@{\hspace{30pt}}l@{}}
     178\begin{cfa}
     179variant Week {
     180        case Mon: const int = 0;
    128181        ...
    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}
     182        case Sat: const int = 5;
     183        case Sun: const int = 10;
     184};
     185\end{cfa}
     186&
     187\begin{cfa}
     188variant Week {
     189        case Mon: ;  // tag auto-numbering
     190        ...
     191        case Sat: ;
     192        case @Sun = 10@: ; // directly set tag value
     193};
     194\end{cfa}
     195\end{tabular}
     196\end{cquote}
     197Directly setting the tag implies restrictions, like unique values.
     198In both cases, instances of @Week@ are @const@ (immutable).
     199However, usage between these two types becomes complex.
     200\begin{cfa}
     201Week day = Week.Mon;  // sets value or tag depending on type
     202if ( day == Week.Mon )   // dereference value or tag ?
     203\end{cfa}
     204Here, the dereference of @day@ should return the value of the type stored in the variant, never the tag.
     205If it does return the tag, some special meaning must be given to the empty/unit type, especially if a variant contains both regular and unit types.
     206
     207
     208In general, the enumeration simulation and the variant extensions to support it, are deviating from the normal use of a variant (union) type.
     209As well, the enumeration operations are limited to the available tag operations, \eg pattern matching.
    138210While enumerating among tag names is possible:
    139211\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.
     212for ( cursor in Week.Mon, Week.Wed, Week.Fri, Week.Sun ) ...
     213\end{cfa}
     214what is the type of @cursor@?
     215If it the tag type (@int@), how is this value used?
     216If it is the variant type, where is the instance variable, which only contains one value.
     217Hence, either enumerating with a variant enumeration is disallowed or some unusual typing rule must be invented to make it work but only in restricted contexts.
     218
     219While functional programming systems regularly re-purposing variant types into enumeration types, this process seems contrived and confusing.
     220A variant tag is not an enumeration, it is a discriminant among a restricted set of types stored in a storage block.
     221Hence, there is only a weak equivalence between an enumeration and variant type, justifying a seperate enumeration type in a programming language.
    161222
    162223
  • doc/theses/jiada_liang_MMath/relatedwork.tex

    r0fe07be r15215f02  
    5353\lstnewenvironment{ada}[1][]{\lstset{language=[2005]Ada,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},literate={'}{\ttfamily'\!}1}\lstset{#1}}{}
    5454
    55 An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
     55An Ada enumeration type is a set of ordered unscoped identifiers (enumerators) bound to \emph{unique} \Newterm{literals}.\footnote{%
     56Ada 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).}
    5657\begin{ada}
    57 type RGB is ( Red, Green, Blue ); -- 3 literals (enumerators)
     58type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun ); -- literals (enumerators)
    5859\end{ada}
    5960Object 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.
     61While Ada enumerators are unscoped, like C, Ada enumerators are overloadable.
    6262\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}
     63type RGB is ( @Red@, @Green@, Blue );
    7764type Traffic_Light is ( @Red@, Yellow, @Green@ );
    7865\end{ada}
    79 Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded names.
     66Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded identifiers.
    8067\VRef[Figure]{f:AdaEnumeration} shows how ambiguity is handled using a cast, \ie \lstinline[language=ada]{RGB'(Red)}.
    8168
     
    10289\end{figure}
    10390
    104 Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package names.
     91Enumerators without initialization are auto-initialized from left to right, starting at zero, incrementing by 1.
     92Enumerators with initialization must set \emph{all} enumerators in \emph{ascending} order, \ie there is no auto-initialization.
     93\begin{ada}
     94type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
     95for Week use ( Mon => 0, Tue => 1, Wed => 2, Thu => @10@, Fri => 11, Sat => 14, Sun => 15 );
     96\end{ada}
     97The enumeration operators are the equality and relational operators, @=@, @/=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of acsending enumerators.
     98
     99Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package identifiers.
    105100\begin{ada}
    106101OtherRed : RGB renames Red;
     
    113108There are three pairs of inverse enumeration pseudo-functions (attributes): @'Pos@ and @'Val@, @'Enum_Rep@ and @'Enum_Val@, and @'Image@ and @'Value@,
    114109\begin{cquote}
    115 \lstDeleteShortInline@
    116110\setlength{\tabcolsep}{15pt}
    117111\begin{tabular}{@{}ll@{}}
     
    128122\end{ada}
    129123\end{tabular}
    130 \lstMakeShortInline@
    131124\end{cquote}
    132125These attributes are important for IO.
     
    138131\end{ada}
    139132which 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.
     133The purpose is strictly readability using character literals rather than identifiers.
    141134\begin{ada}
    142135Op : Operator := '+';
     
    171164An enumeration type can be used in the Ada \lstinline[language=ada]{case} (all enumerators must appear or a default) or iterating constructs.
    172165\begin{cquote}
    173 \lstDeleteShortInline@
    174166\setlength{\tabcolsep}{15pt}
    175167\begin{tabular}{@{}ll@{}}
     
    211203\end{ada}
    212204\end{tabular}
    213 \lstMakeShortInline@
    214205\end{cquote}
    215206
     
    229220\CC has the equivalent of Pascal typed @const@ declarations \see{\VRef{s:Pascal}}, with static and dynamic initialization.
    230221\begin{c++}
    231 const auto one = 0 + 1;                                 $\C{// static intialization}$
     222const auto one = 0 + 1;                                 $\C{// static initialization}$
    232223const auto NULL = nullptr;
    233224const auto PI = 3.14159;
     
    237228                                Sat = Fri + 1, Sun = Sat + 1;
    238229int sa[Sun];
    239 const auto r = random();                                $\C{// dynamic intialization}$
     230const auto r = random();                                $\C{// dynamic initialization}$
    240231int da[r];                                                              $\C{// VLA}$
    241232\end{c++}
     
    362353\begin{figure}
    363354\centering
    364 \lstDeleteShortInline@
    365355\begin{tabular}{@{}l|l@{}}
    366356\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
     
    414404\end{csharp}
    415405\end{tabular}
    416 \lstMakeShortInline@
    417406\caption{\Csharp: Free Routine Versus Class Enumeration}
    418407\label{CsharpFreeVersusClass}
     
    429418const ( S = 0; T; USA = "USA"; U; V = 3.1; W ) $\C{// type change, implicit/explicit: 0 0 USA USA 3.1 3.1}$
    430419\end{Go}
    431 Constant names are unscoped and must be unique (no overloading).
     420Constant identifiers are unscoped and must be unique (no overloading).
    432421The first enumerator \emph{must} be explicitly initialized;
    433422subsequent enumerators can be implicitly or explicitly initialized.
     
    459448Basic switch and looping are possible.
    460449\begin{cquote}
    461 \lstDeleteShortInline@
    462450\setlength{\tabcolsep}{15pt}
    463451\begin{tabular}{@{}ll@{}}
     
    482470\end{Go}
    483471\end{tabular}
    484 \lstMakeShortInline@
    485472\end{cquote}
    486473However, the loop prints the values from 0 to 13 because there is no actual enumeration.
     
    513500\begin{figure}
    514501\centering
    515 \lstDeleteShortInline@
    516502\begin{tabular}{@{}l|l@{}}
    517503\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
     
    553539\end{Java}
    554540\end{tabular}
    555 \lstMakeShortInline@
    556541\caption{Java: Free Routine Versus Class Enumeration}
    557542\label{f:JavaFreeVersusClass}
     
    607592\section{Rust}
    608593\lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
     594% https://doc.rust-lang.org/reference/items/enumerations.html
    609595
    610596Rust provides a scoped enumeration based on variant types.
     
    1010996
    1011997
    1012 \section{Python}
     998\section{Python 3.13}
    1013999\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.
     1000% https://docs.python.org/3/howto/enum.html
     1001
     1002Python 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.
     1003As 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.
     1004Nevertheless, an attempt has been made to discuss core enumeration features that come with Python 3.13.
     1005
     1006A Python enumeration type is a set of ordered scoped identifiers (enumerators) bound to \emph{unique} values.
     1007An enumeration is not a basic type;
     1008it is a @class@ inheriting from the @Enum@ class, where the enumerators must be explicitly initialized, \eg:
     1009\begin{python}
     1010class Week(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
     1011\end{python}
     1012and/or explicitly auto initialized, \eg:
     1013\begin{python}
     1014class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @auto()@; Sat = 4; Sun = @auto()@
     1015\end{python}
     1016where @auto@ increments by 1 from the previous enumerator value.
     1017Object initialization and assignment are restricted to the enumerators of this type.
     1018An enumerator initialized with same value is an alias and invisible at the enumeration level, \ie the alias it substituted for its aliasee.
     1019\begin{python}
     1020class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @10@; Sat = @10@; Sun = @10@
     1021\end{python}
     1022Here, the enumeration has only 4 enumerators and 3 aliases.
     1023An alias is only visible by dropping down to the @class@ level and asking for class members.
     1024@Enum@ only supports equality comparison between enumerator values;
     1025the extended class @OrderedEnum@ adds relational operators @<@, @<=@, @>@, and @>=@.
     1026
     1027There are bidirectional enumeration pseudo-functions for label and value, but there is no concept of access using ordering (position).
     1028\begin{cquote}
     1029\setlength{\tabcolsep}{15pt}
     1030\begin{tabular}{@{}ll@{}}
     1031\begin{python}
     1032Week.Thu.value == 10;
     1033Week.Thu.name == 'Thu';
     1034\end{python}
     1035&
     1036\begin{python}
     1037Week( 10 ) == Thu
     1038Week['Thu'].value = 10
     1039\end{python}
     1040\end{tabular}
     1041\end{cquote}
     1042
     1043As an enumeration is a \lstinline[language=python]{class}, its own methods.
     1044\begin{python}
     1045class Week(Enum):
     1046        Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
     1047        $\\@$classmethod
     1048        def today(cls, date):
     1049                return cls(date.isoweekday())
     1050print( "today:", Week.today(date.today()))
     1051today: Week.Mon
     1052\end{python}
     1053The method @today@ retrieves the day of the week and uses it as an index to print out the corresponding label of @Week@.
    10761054
    10771055@Flag@ allows combining several members into a single variable:
    10781056\begin{python}
    1079 print( repr(WeekdayF.Sat | WeekdayF.Sun) )
    1080 <WeekdayF.Sun|Sat: 96>
     1057print( repr(WeekF.Sat | WeekF.Sun) )
     1058<WeekF.Sun|Sat: 96>
    10811059\end{python}
    10821060You can even iterate over a @Flag@ variable:
     
    10841062for day in weekend:
    10851063        print(day)
    1086 Weekday.SATURDAY
    1087 Weekday.SUNDAY
     1064WeekF.Sat
     1065WeekF.Sun
    10881066\end{python}
    10891067Okay, let's get some chores set up:
    10901068\begin{python}
    10911069>>> 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,
     1070...    'feed the cat': Week.MONDAY | Week.WEDNESDAY | Week.FRIDAY,
     1071...    'do the dishes': Week.TUESDAY | Week.THURSDAY,
     1072...    'answer SO questions': Week.SATURDAY,
    10951073...    }
    10961074\end{python}
     
    11011079...        if day in days:
    11021080...            print(chore)
    1103 >>> show_chores(chores_for_ethan, Weekday.SATURDAY)
     1081>>> show_chores(chores_for_ethan, Week.SATURDAY)
    11041082answer SO questions
    11051083\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
     1084Auto incrmenet for @Flag@ is by powers of 2.
     1085\begin{python}
     1086class WeekF(Flag): Mon = auto(); Tue = auto(); Wed = auto(); Thu = auto(); Fri = auto();  \
     1087                                                        Sat = auto(); Sun = auto(); Weekend = Sat | Sun
     1088for d in WeekF:
     1089        print( f"{d.name}: {d.value}", end=" ")
     1090Mon: 1 Tue: 2 Wed: 4 Thu: 8 Fri: 16 Sat: 32 Sun: 64 WeekA.Weekend
    11181091\end{python}
    11191092
     
    11231096@Enum@ allows such access:
    11241097\begin{python}
    1125 >>> Color(1)
    1126 <Color.RED: 1>
    1127 >>> Color(3)
    1128 <Color.BLUE: 3>
     1098print(RGB(1), RGB(3), )
     1099RGB.RED RGB.GREEN
    11291100\end{python}
    11301101If you want to access enum members by name, use item access:
    11311102\begin{python}
    1132 Color['RED']
    1133 <Color.RED: 1>
    1134 
    1135 Color['GREEN']
    1136 <Color.GREEN: 2>
     1103print( RGBa['RED'], RGBa['GREEN'] )
     1104RGB.RED RGB.GREEN
    11371105\end{python}
    11381106If you have an enum member and need its name or value:
    11391107\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.
     1108member = RGBa.RED
     1109print( f"{member.name} {member.value}" )
     1110RED 1
     1111\end{python}
     1112
    11651113
    11661114\subsection{Ensuring unique enumeration values}
     
    12071155>>> list(Shape)
    12081156[<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.
     1157>>> list(Week)
     1158[<Week.MONDAY: 1>, <Week.TUESDAY: 2>, <Week.WEDNESDAY: 4>, <Week.THURSDAY: 8>,
     1159<Week.FRIDAY: 16>, <Week.SATURDAY: 32>, <Week.SUNDAY: 64>]
     1160\end{python}
     1161Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Week.WEEKEND@ aren't shown.
    12141162
    12151163The special attribute @__members__@ is a read-only ordered mapping of names to members.
     
    22182166
    22192167OCaml 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)
     2168The simplest form of the variant type is a list of nullary datatype constructors, which is like an unscoped, opaque enumeration.
     2169
    22232170OCaml 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.
     2171A basic variant is a list of nullary datatype constructors, which is like an unscoped, opaque enumeration.
    22252172\begin{ocaml}
    22262173type weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun
     
    22462193type colour = Red | Green of @string@ | Blue of @int * float@
    22472194\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. 
     2195A variant with parameter is stored in a memory block, prefixed by an int tag and has its parameters stores as words in the block.
    22492196@colour@ is a summation of a nullary type, a unary product type of @string@, and a cross product of @int@ and @float@.
    22502197(Mathematically, a @Blue@ value is a Cartesian product of the types @int@ type and @float@.)
     
    22592206@Red, abc, 1 1.5@
    22602207\end{ocaml}
    2261 
    22622208
    22632209A variant type can have a recursive definition.
     
    22802226
    22812227In 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.
     2228Therefore it is not an enumeration, except for the simple opaque (nullary) case.
    22832229
    22842230\begin{comment}
     
    24662412With valediction,
    24672413  - Gregor Richards
     2414
     2415
     2416Date: Tue, 16 Apr 2024 11:04:51 -0400
     2417Subject: Re: C unnamed enumeration
     2418To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
     2419CC: <ajbeach@uwaterloo.ca>, <j82liang@uwaterloo.ca>, <mlbrooks@uwaterloo.ca>,
     2420        <f37yu@uwaterloo.ca>
     2421From: Gregor Richards <gregor.richards@uwaterloo.ca>
     2422
     2423On 4/16/24 09:55, Peter A. Buhr wrote:
     2424> So what is a variant? Is it a set of tag names, which might be a union or is it
     2425> a union, which might have tag names?
     2426
     2427Your tagless variant bears no resemblance to variants in any functional
     2428programming language. A variant is a tag AND a union. You might not need to put
     2429anything in the union, in which case it's a pointless union, but the named tag
     2430is absolutely mandatory. That's the thing that varies.
     2431
     2432I was unaware of std::variant. As far as functional languages are concerned,
     2433std::variant IS NOT A VARIANT. Perhaps it would be best to use the term ADT for
     2434the functional language concept, because that term has no other meanings.
     2435
     2436An ADT cannot not have a named tag. That's meaningless. The tag is the data
     2437constructor, which is the thing you actually define when you define an ADT. It
     2438is strictly the union that's optional.
     2439
     2440With valediction,
     2441  - Gregor Richards
    24682442\end{comment}
    24692443
     
    24872461\hline
    24882462\hline
    2489 pure                    &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
     2463opaque                  &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
    24902464\hline
    24912465typed                   &               &               &               &               &               &               &               &               &               &               & @int@ & integral      & @T@   \\
  • doc/theses/jiada_liang_MMath/uw-ethesis.bib

    r0fe07be r15215f02  
    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/uC++toCFA/Makefile

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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 : Thu Apr 18 21:53:45 2024
     14%% Update Count     : 6502
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    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
     2963{\color{red}
    29622964As well, \CFA-style declarations cannot be used to declare parameters for C-style routine-definitions because of the following ambiguity:
    29632965\begin{cfa}
     
    29672969The 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.
    29682970The 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.
    2969 The 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.
     2971The 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.}
    29702972
    29712973C-style declarations can be used to declare parameters for \CFA style routine definitions, \eg:
     
    30553057static [ int ] g ( int );
    30563058\end{cfa}
     3059
     3060
     3061\subsection{Postfix Function}
     3062\label{s:PostfixFunction}
     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}
     3102
     3103\VRef[Figure]{f:UnitsComparison} shows a common usage for postfix functions: converting basic literals into user literals.
     3104\see*{\VRef{s:DynamicStorageManagement} for other uses for postfix functions.}
     3105The \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).
     3106The three postfixing function names ©st©, ©lb©, and ©kg©, represent units stones, pounds, and kilograms, respectively.
     3107Each 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©.
     3108All arithmetic operations manipulate stones and the postfix operations convert to the different units.
     3109A 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.
     3110(Note, month is not a fixed period of time nor is year because of leap years.)
     3111
     3112\begin{figure}
     3113\centering
     3114\begin{tabular}{@{}l|l@{}}
     3115\multicolumn{1}{@{}c|}{\textbf{\CFA Postfix Routine}} & \multicolumn{1}{c@{}}{\textbf{\CC User Literals}} \\
     3116\hline
     3117\begin{cfa}
     3118struct Weight {
     3119        double stones;
     3120};
     3121
     3122
     3123Weight ?+?( Weight l, Weight r ) {
     3124        return l.stones + r.stones;
     3125}
     3126Weight ?`st( double w ) { return w; }
     3127double ?`st( Weight w ) { return w.stones; }
     3128Weight ?`lb( double w ) { return w / 14.0; }
     3129double ?`lb( Weight w ) { return w.stones * 14.0; }
     3130Weight ?`kg( double w ) { return w / 6.35; }
     3131double ?`kg( Weight w ) { return w.stones * 6.35; }
     3132int main() {
     3133        Weight w, heavy = { 20 }; // stones
     3134        w = 155`lb;
     3135        w = 0b_1111`st;
     3136        w = 0_233`lb;
     3137        w = 0x_9b`kg;
     3138        w = 5.5`st + 8`kg + 25.01`lb + heavy;
     3139}
     3140\end{cfa}
     3141&
     3142\begin{C++}
     3143struct Weight {
     3144        double stones;
     3145        Weight() {}
     3146        Weight( double w ) { stones = w; }
     3147};
     3148Weight operator+( Weight l, Weight r ) {
     3149        return l.stones + r.stones;
     3150}
     3151Weight operator""_st( long double w ) { return w; }
     3152Weight operator""_lb( long double w ) { return w / 14.0; }
     3153Weight operator""_kg( long double w ) { return w / 6.35; }
     3154Weight operator""_st( unsigned long long int w ) { return w; }
     3155Weight operator""_lb( unsigned long long int w ) { return w / 14.0; }
     3156Weight operator""_kg( unsigned long long int w ) { return w / 6.35; }
     3157int main() {
     3158        Weight w, heavy = { 20 }; // stones
     3159        w = 155_lb;
     3160        w = 0b1111_st;
     3161        w = 0'233_lb;           // quote separator
     3162        w = 0x9b_kg;
     3163        w = 5.5_st + 8_kg + 25.01_lb + heavy;
     3164}
     3165\end{C++}
     3166\end{tabular}
     3167
     3168\begin{comment}
     3169Time : comparison of time units. \\
     3170\begin{tabular}{@{}ll@{}}
     3171\CFA & \CC \\
     3172\begin{cfa}
     3173#include <fstream.hfa>
     3174#include <time.hfa>
     3175
     3176
     3177Duration s = 1`h + 2 * 10`m + 70`s / 10;
     3178sout | "1 hour + 2*10 min + 70/10 sec = " | s | "seconds";
     3179sout | "Dividing that by 2 minutes gives" | s / 2`m;
     3180sout | "Dividing that by 2 gives" | s / 2 | "seconds\n";
     3181sout | s | "seconds is"
     3182          | s`h | "hours,"
     3183          | (s % 1`h)`m | "minutes,"
     3184          | (s % 1`m)`s | "seconds";
     3185\end{cfa}
     3186&       
     3187\begin{C++}
     3188#include <iostream>
     3189#include <chrono>
     3190using namespace std;
     3191using namespace std::chrono;
     3192seconds s = hours(1) + 2 * minutes(10) + seconds(70) / 10;
     3193cout << "1 hour + 2*10 min + 70/10 sec = " << s.count() << " seconds\n";
     3194cout << "Dividing that by 2 minutes gives " << s / minutes(2) << '\n';
     3195cout << "Dividing that by 2 gives " << (s / 2).count() << " seconds\n";
     3196cout << s.count() << " seconds is "
     3197          << duration_cast<hours>( s ).count() << " hours, "
     3198          << duration_cast<minutes>( s % hours(1) ).count() << " minutes, "
     3199          << duration_cast<seconds>( s % minutes(1) ).count() << " seconds\n";
     3200\end{C++}
     3201\end{tabular}
     3202\end{comment}
     3203
     3204\caption{Units: Stone, Pound, Kilogram Comparison}
     3205\label{f:UnitsComparison}
     3206\end{figure}
     3207
     3208The \CC example (right) provides a \emph{restricted} capability via user literals.
     3209The \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.
     3210As 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©.
     3211Finally, there is no mechanism to use this syntax for a bidirectional conversion because \lstinline[language=C++]{operator ""} does not accept variable arguments.
    30573212
    30583213
     
    38093964\subsection{Polymorphism}
    38103965
    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.
     3966Due to the implicit flattening and structuring conversions involved in argument passing, object and opaque parameters are restricted to matching only with non-tuple types.
    38123967The integration of polymorphism, type assertions, and monomorphic specialization of tuple-assertions are a primary contribution of this thesis to the design of tuples.
    38133968\begin{cfa}
    3814 forall(T, dtype U)
     3969forall(T, U &)
    38153970void f(T x, U * y);
    38163971
     
    49255080        sout | '1' | '2' | '3';
    49265081        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;
     5082        sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x £" | 6 | "x ¥"
     5083                | 7 | "x ¡" | 8 | "x ¿" | 9 | "x «" | 10;
    49295084        sout | 1 | ", x" | 2 | ". x" | 3 | "; x" | 4 | "! x" | 5 | "? x" | 6 | "% x"
    4930                 | 7 | "¢ x" | 8 | "» x" | 9 | ") x" | 10 | "] x" | 11 | "} x";
     5085                | 7 | "¢ x" | 8 | "» x" | 9 | ") x" | 10 | "] x" | 11 | "} x";
    49315086        sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x:" | 4 | ":x " | 5 | " x\t" | 6 | "\tx";
    49325087        sout | "x ( " | 1 | " ) x" | 2 | " , x" | 3 | " :x: " | 4;
     
    77757930\item[Rationale:] increase type safety
    77767931\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}:
     7932\item[Difficulty of converting:] requires adding a cast \see{\VRef{s:DynamicStorageManagement} for better alternatives}:
    77787933\begin{cfa}
    77797934        int * b = (int *)malloc( sizeof(int) );
     
    79888143\label{s:StandardLibrary}
    79898144
    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.
     8145The \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.
     8146
     8147
     8148\subsection{Dynamic Storage-Management}
     8149\label{s:DynamicStorageManagement}
     8150
     8151Dynamic storage-management in C is based on explicit allocation and deallocation (©malloc©/©free©).
     8152Programmer's must manage all allocated storage via its address (pointer) and subsequently deallocate the storage via this address.
     8153Storage that is not deallocated becomes inaccessible, called a \newterm{memory leak}, which can only be detected at program termination.
     8154Storage freed twice is an error, called a \newterm{duplicate free}, which can sometimes be detected.
     8155Storage used after it is deallocated is an error, called using a \newterm{dangling pointer}, which can sometimes be detected.
     8156
     8157
     8158\subsubsection{C Interface}
     8159
     8160C dynamic storage-management provides the following properties.
     8161\begin{description}[leftmargin=*]
     8162\item[fill]
     8163storage after an allocation with a specified character or value.
     8164\item[align]
     8165an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
     8166\item[scale]
     8167an allocation size to the specified number of array elements.
     8168An array may be filled, resized, or aligned.
    80028169\item[resize]
    80038170an 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.
     8171In 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.
     8172When new storage is allocated, it may be aligned and storage after copied data may be filled.
    80118173\end{description}
    8012 \VRef[Table]{t:AllocationVersusCapabilities} shows allocation routines supporting different combinations of storage-management capabilities.
     8174\VRef[Table]{t:AllocationVersusProperties} shows different combinations of storage-management properties provided by the C and \CFA allocation routines.
     8175
    80138176\begin{table}
     8177\caption{Allocation Routines versus Storage-Management Properties}
     8178\label{t:AllocationVersusProperties}
    80148179\centering
    80158180\begin{minipage}{0.75\textwidth}
    80168181\begin{tabular}{@{}r|l|l|l|l|l@{}}
    8017 \multicolumn{1}{c}{}&           & \multicolumn{1}{c|}{fill}     & resize        & alignment     & array \\
     8182                & \multicolumn{1}{c|}{routine} & \multicolumn{1}{c|}{\textbf{fill}} & \textbf{alignment}        & \textbf{scale}        & \textbf{resize} \\
    80188183\hline
    80198184C               & ©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   \\
     8185                & ©calloc©                      & yes (0 only)  & no            & yes           & no    \\
     8186                & ©realloc©                     & copy                  & no            & no            & yes   \\
     8187                & ©reallocarray©        & copy                  & no            & yes           & yes   \\
     8188                & ©memalign©            & no                    & yes           & no            & no    \\
     8189                & ©aligned_alloc©\footnote{Same as ©memalign© but size is an integral multiple of alignment.}
     8190                                                        & no                    & yes           & no            & no    \\
     8191                & ©posix_memalign©      & no                    & yes           & no            & no    \\
     8192                & ©valloc©                      & no                    & yes (page size)& no   & no    \\
    80278193                & ©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   \\
     8194                                                        & no                    & yes (page size)& no   & no    \\
     8195\hline                                                                                                                                 
     8196\CFA    & ©cmemalign©           & yes (0 only)  & yes           & yes           & no    \\
     8197                & ©resize©                      & no copy               & yes           & no            & yes   \\
     8198                & ©realloc©                     & copy                  & yes           & no            & yes   \\
     8199                & ©alloc©\footnote{Multiple overloads with different parameters.}
     8200                                                        & yes                   & yes           & yes           & yes
    80368201\end{tabular}
    80378202\end{minipage}
    8038 \caption{Allocation Routines versus Storage-Management Capabilities}
    8039 \label{t:AllocationVersusCapabilities}
     8203\vspace*{-10pt}
    80408204\end{table}
    80418205
    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 );
     8206
     8207\subsubsection{\CFA Interface}
     8208
     8209\CFA dynamic memory management:
     8210\begin{enumerate}[leftmargin=\parindent]
     8211\item
     8212Extend 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.
     8213\begin{cfa}
     8214int * ip = (int *)malloc( sizeof(int) ); §\C[2.3in]{// C}§
     8215int * ip = malloc();                                    §\C{// \CFA type-safe call of C malloc}§
     8216int * ip = alloc();                                             §\C{// \CFA type-safe call of \CFA alloc}§
     8217struct __attribute__(( aligned(128) )) spinlock { ... };
     8218spinlock * slp = malloc();                              §\C{// correct size, alignment, and return type}\CRT§
     8219\end{cfa}
     8220Here, the alignment of the ©ip© storage is 16 (default) and 128 for ©slp©.
     8221
     8222\item
     8223Introduce the notion of \newterm{sticky properties} used in resizing.
     8224All initial allocation properties are remembered and maintained for use should resize require new storage.
     8225For example, the initial alignment and fill properties in the initial allocation
     8226\begin{cfa}
     8227struct __attribute__(( aligned(4096) )) S { ... };
     8228S * sp = calloc( 10 );                                  §\C{// align 4K and zero fill}§
     8229sp = reallocarray( sp, 100 );                   §\C{// preserve 4K alignment and zero fill new storage}§
     8230\end{cfa}
     8231are preserved in the resize so the new storage has the same alignment and extra storage after the data copy is zero filled.
     8232Without sticky properties it is dangerous to resize, resulting in the C idiom of manually performing the reallocation to maintain correctness, which is error prone.
     8233
     8234\item
     8235Provide resizing without data copying, which is useful to repurpose an existing block of storage for another purpose, rather than freeing the old storage and performing a new allocation.
     8236The resize might be able to take advantage of unused storage after the data to preventing the free/reallocation step altogether.
     8237
     8238\item
     8239Provide ©free©/©delete© functions that delete a variable number of pointers.
     8240\begin{cfa}
     8241int * ip = malloc(), * jp = malloc(), * kp = malloc();
     8242double * xp = malloc(), * yp = malloc(), * zp = malloc();
     8243free( ®ip, jp, kp, xp, yp, zp® );
     8244\end{cfa}
     8245
     8246\item
     8247Support constructors for initialization of allocated storage (like \CC) and destructors for deallocation.
     8248\begin{cfa}
     8249struct S { int v; };                                    §\C{// default constructors}§
     8250void ^?{}( S & ) { ... }                                §\C{// destructor}§
     8251S & sp = *®new®( 3 );                                   §\C{// allocate and call constructor}§
     8252sout | sp.v;
     8253®delete®( &sp );                                                §\C{// call destructor}§
     8254S * spa1 = ®anew®( 10, 5 ), * spa2 = ®anew®( 10, 8 ); §\C{// allocate array and call constructor for each array element}§
     8255for ( i; 10 ) sout | spa1[i].v | spa2[i].v | nonl; sout | nl;
     8256®adelete®( spa1, spa2 );                                §\C{// call destructors on all array objects}§
     8257
     82583
     82595 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8
    80818260\end{cfa}
    80828261Allocation routines ©new©/©anew© allocate a variable/array and initialize storage using the allocated type's constructor.
    80838262Note, the matching deallocation routines ©delete©/©adelete©.
    8084 
    8085 \leavevmode
     8263\end{enumerate}
     8264
     8265In addition, \CFA provides a new allocator interface to further increase orthogonality and usability of dynamic-memory allocation.
     8266This interface helps programmers in three ways.
     8267\begin{enumerate}
     8268\item
     8269naming: \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.
     8270\item
     8271named 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.
     8272\item
     8273safe usage: like the \CFA's C-interface, programmers do not have to specify object size or cast allocation results.
     8274\end{enumerate}
     8275
     8276The polymorphic functions ©T * alloc( ... )© and ©T * alloc( size_t dim, ... )© are overloaded with a variable number of specific allocation properties, or an integer dimension parameter followed by a variable number of specific allocation properties.
     8277These allocation properties can be passed as named arguments when calling the \lstinline{alloc} routine.
     8278A call without parameters returns an uninitialized dynamically allocated object of type ©T© (©malloc©).
     8279A call with only the dimension (dim) parameter returns an uninitialized dynamically allocated array of objects with type ©T© (©aalloc©).
     8280The variable number of arguments consist of allocation properties, which can be combined to produce different kinds of allocations.
     8281The properties ©resize© and ©realloc© are associated with the allocation variable indicating how the existing allocation is modified, without or with data copying.
     8282Function ©alloc© is used extensively in the \CFA runtime.
     8283
     8284The following allocation property functions may be combined and appear in any order as arguments to ©alloc©,
     8285\begin{itemize}
     8286\item
     8287©T_align ?`align( size_t alignment )© to align an allocation.
     8288The alignment parameter must be $\ge$ the default alignment (©libAlign()© in \CFA) and a power of two, \eg:
     8289\begin{cfa}
     8290int * i0 = alloc( ®4096`align® );  sout | i0 | nl;
     8291int * i1 = alloc( 3, ®4096`align® );  sout | i1; for (i; 3 ) sout | &i1[i] | nonl; sout | nl;
     8292
     82930x555555572000
     82940x555555574000 0x555555574000 0x555555574004 0x555555574008
     8295\end{cfa}
     8296returns a dynamic object and object array aligned on a 4096-byte boundary.
     8297
     8298\item
     8299©S_fill(T) ?`fill ( /* various types */ )© to initialize storage.
     8300There are three ways to fill storage:
     8301\begin{enumerate}
     8302\item
     8303A ©char© fills every byte of each object.
     8304\item
     8305An object of the returned type fills each object.
     8306\item
     8307An object array pointer fills some or all of the corresponding object array.
     8308\end{enumerate}
     8309For example:
     8310\begin{cfa}[numbers=left]
     8311int * i0 = alloc( ®0n`fill® );  sout | *i0 | nl;  // 0n disambiguates 0
     8312int * i1 = alloc( ®5`fill® );  sout | *i1 | nl;
     8313int * i2 = alloc( ®'\xfe'`fill® ); sout | hex( *i2 ) | nl;
     8314int * i3 = alloc( 5, ®5`fill® );  for ( i; 5 ) sout | i3[i] | nonl; sout | nl;
     8315int * i4 = alloc( 5, ®0xdeadbeefN`fill® );  for ( i; 5 ) sout | hex( i4[i] ) | nonl; sout | nl;
     8316int * i5 = alloc( 5, ®i3`fill® );  for ( i; 5 ) sout | i5[i] | nonl; sout | nl; // completely fill from i3
     8317int * i6 = alloc( 5, ®[i3, 3]`fill® );  for ( i; 5 ) sout | i6[i] | nonl; sout | nl; // partial fill from i3
     8318\end{cfa}
     8319\begin{lstlisting}[numbers=left]
     83200
     83215
     83220xfefefefe
     83235 5 5 5 5
     83240xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
     83255 5 5 5 5
     83265 5 5 -555819298 -555819298  // two undefined values
     8327\end{lstlisting}
     8328Examples 1 to 3 fill an object with a value or characters.
     8329Examples 4 to 7 fill an array of objects with values, another array, or part of an array.
     8330
     8331\item
     8332©S_resize(T) ?`resize( void * oaddr )© used to resize, realign, and fill, where the old object data is not copied to the new object.
     8333The old object type may be different from the new object type, since the values are not used.
     8334For example:
     8335\begin{cfa}[numbers=left]
     8336int * i = alloc( ®5`fill® );  sout | i | *i;
     8337i = alloc( ®i`resize®, ®256`align®, ®7`fill® );  sout | i | *i;
     8338double * d = alloc( ®i`resize®, ®4096`align®, ®13.5`fill® );  sout | d | *d;
     8339\end{cfa}
     8340\begin{lstlisting}[numbers=left]
     83410x55555556d5c0 5
     83420x555555570000 7
     83430x555555571000 13.5
     8344\end{lstlisting}
     8345Examples 2 to 3 change the alignment, fill, and size for the initial storage of ©i©.
     8346
     8347\begin{cfa}[numbers=left]
     8348int * ia = alloc( 5, ®5`fill® );  for ( i; 5 ) sout | ia[i] | nonl; sout | nl;
     8349ia = alloc( 10, ®ia`resize®, ®7`fill® ); for ( i; 10 ) sout | ia[i] | nonl; sout | nl;
     8350sout | ia; ia = alloc( 5, ®ia`resize®, ®512`align®, ®13`fill® ); sout | ia; for ( i; 5 ) sout | ia[i] | nonl; sout | nl;;
     8351ia = alloc( 3, ®ia`resize®, ®4096`align®, ®2`fill® );  sout | ia; for ( i; 3 ) sout | &ia[i] | ia[i] | nonl; sout | nl;
     8352\end{cfa}
     8353\begin{lstlisting}[numbers=left]
     83545 5 5 5 5
     83557 7 7 7 7 7 7 7 7 7
     83560x55555556d560 0x555555571a00 13 13 13 13 13
     83570x555555572000 0x555555572000 2 0x555555572004 2 0x555555572008 2
     8358\end{lstlisting}
     8359Examples 2 to 4 change the array size, alignment and fill for the initial storage of ©ia©.
     8360
     8361\item
     8362©S_realloc(T) ?`realloc( T * a ))©
     8363used to resize, realign, and fill, where the old object data is copied to the new object.
     8364The old object type must be the same as the new object type, since the value is used.
     8365Note, for ©fill©, only the extra space after copying the data from the old object is filled with the given parameter.
     8366For example:
     8367\begin{cfa}[numbers=left]
     8368int * i = alloc( ®5`fill® );  sout | i | *i;
     8369i = alloc( ®i`realloc®, ®256`align® );  sout | i | *i;
     8370i = alloc( ®i`realloc®, ®4096`align®, ®13`fill® );  sout | i | *i;
     8371\end{cfa}
     8372\begin{lstlisting}[numbers=left]
     83730x55555556d5c0 5
     83740x555555570000 5
     83750x555555571000 5
     8376\end{lstlisting}
     8377Examples 2 to 3 change the alignment for the initial storage of ©i©.
     8378The ©13`fill© in example 3 does nothing because no extra space is added.
     8379
     8380\begin{cfa}[numbers=left]
     8381int * ia = alloc( 5, ®5`fill® );  for ( i; 5 ) sout | ia[i]; sout | nl;
     8382ia = alloc( 10, ®ia`realloc®, ®7`fill® ); for ( i; 10 ) sout | ia[i]; sout | nl;
     8383sout | ia; ia = alloc( 1, ®ia`realloc®, ®512`align®, ®13`fill® ); sout | ia; for ( i; 1 ) sout | ia[i]; sout | nl;;
     8384ia = alloc( 3, ®ia`realloc®, ®4096`align®, ®2`fill® );  sout | ia; for ( i; 3 ) sout | &ia[i] | ia[i]; sout | nl;
     8385\end{cfa}
     8386\begin{lstlisting}[numbers=left]
     83875 5 5 5 5
     83885 5 5 5 5 7 7 7 7 7
     83890x55555556c560 0x555555570a00 5
     83900x555555571000 0x555555571000 5 0x555555571004 2 0x555555571008 2
     8391\end{lstlisting}
     8392Examples 2 to 4 change the array size, alignment and fill for the initial storage of ©ia©.
     8393The ©13`fill© in example 3 does nothing because no extra space is added.
     8394\end{itemize}
     8395
     8396\medskip
    80868397\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    80878398extern "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 );
     8399        // New allocation operations.
     8400        void * aalloc( size_t dim, size_t elemSize );§\indexc{aalloc}§
     8401        void * resize( void * oaddr, size_t size );§\indexc{resize}§
     8402        void * amemalign( size_t align, size_t dim, size_t elemSize );§\indexc{amemalign}§
     8403        void * cmemalign( size_t align, size_t dim, size_t elemSize );§\indexc{cmemalign}§
     8404        size_t malloc_alignment( void * addr );§\indexc{malloc_alignment}§
     8405        bool malloc_zero_fill( void * addr );§\indexc{malloc_zero_fill}§
     8406        size_t malloc_size( void * addr );§\indexc{malloc_size}§
     8407        int malloc_stats_fd( int fd );§\indexc{malloc_stats_fd}§
     8408        size_t malloc_expansion();§\indexc{malloc_expansion}§ $\C{// heap expansion size (bytes)}$
     8409        size_t malloc_mmap_start();§\indexc{malloc_mmap_start}§ $\C{// crossover allocation size from sbrk to mmap}$
     8410        size_t malloc_unfreed();§\indexc{malloc_unfreed()}§     $\C{// heap unfreed size (bytes)}$
     8411        void malloc_stats_clear();§\indexc{malloc_stats_clear}§ $\C{// clear heap statistics}$
     8412}
     8413
     8414// New allocation operations.
     8415void * resize( void * oaddr, size_t alignment, size_t size );
     8416void * realloc( void * oaddr, size_t alignment, size_t size );
     8417void * reallocarray( void * oaddr, size_t nalign, size_t dim, size_t elemSize );
     8418
     8419forall( T & | sized(T) ) {
     8420        // §\CFA§ safe equivalents, i.e., implicit size specification, eliminate return-type cast
     8421        T * malloc( void );§\indexc{malloc}§
     8422        T * aalloc( size_t dim );§\indexc{aalloc}§
     8423        T * calloc( size_t dim );§\indexc{calloc}§
     8424        T * resize( T * ptr, size_t size );§\indexc{resize}§
     8425        T * realloc( T * ptr, size_t size );§\indexc{realloc}§
     8426        T * reallocarray( T * ptr, size_t dim );§\indexc{reallocarray}§
     8427        T * memalign( size_t align );§\indexc{memalign}§
     8428        T * amemalign( size_t align, size_t dim );§\indexc{amemalign}§
     8429        T * cmemalign( size_t align, size_t dim );§\indexc{aalloc}§
     8430        T * aligned_alloc( size_t align );§\indexc{aligned_alloc}§
     8431        int posix_memalign( T ** ptr, size_t align );§\indexc{posix_memalign}§
     8432        T * valloc( void );§\indexc{valloc}§
     8433        T * pvalloc( void );§\indexc{pvalloc}§
    81138434
    81148435        // §\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}§
     8436        T * alloc( ... );§\indexc{alloc}§                                       §\C{// variable, T size}§
     8437        T * alloc( size_t dim, ... );
     8438        T_align ?`align( size_t alignment );§\indexc{align}§
     8439        S_fill(T) ?`fill( /* various types */ );§\indexc{fill}§
     8440        S_resize(T) ?`resize( void * oaddr );§\indexc{resize}§
     8441        S_realloc(T) ?`realloc( T * a ));§\indexc{realloc}§
    81378442
    81388443        // §\CFA§ safe initialization/copy, i.e., implicit size specification
     
    81468451
    81478452// §\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 );
     8453forall( T &, TT ... ) void free( T * ptr, ... );
     8454
     8455forall( T & | sized(T), Params ... | { void ?{}( T &, Params ); } )
     8456T * new( Params p );§\indexc{new}§
     8457forall( T & | { void ^?{}( T & ); } )
     8458void delete( T * ptr );§\indexc{delete}§
     8459forall( T &, Params ... | { void ^?{}( T & ); void delete( Params ); } )
     8460void delete( T * ptr, Params rest );
    81528461
    81538462// §\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 );
     8463forall( T & | sized(T), Params ... | { void ?{}( T &, Params ); } )
     8464T * anew( size_t dim, Params p );§\indexc{anew}§
     8465forall( T & | sized(T) | { void ^?{}( T & ); } )
     8466void adelete( T arr[] );§\indexc{adelete}§
     8467forall( T & | sized(T) | { void ^?{}( T & ); }, Params ... | { void adelete( Params ); } )
     8468void adelete( T arr[], Params rest );
    81588469\end{cfa}
    81598470
     
    92909601Int sqrt( Int oper );
    92919602
    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 );
     9603forall( istype & | istream( istype ) ) istype * ?|?( istype * is, Int * mp );  §\C{// I/O}§
     9604forall( ostype & | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
    92949605\end{cfa}
    92959606\VRef[Figure]{f:MultiPrecisionFactorials} shows \CFA and C factorial programs using the GMP interfaces.
     
    92999610\begin{cquote}
    93009611\begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}}
    9301 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{C}}    & \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{\CFA}}        \\
     9612\multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{C}}   \\
    93029613\hline
     9614\begin{cfa}
     9615#include <gmp.hfa>§\indexc{gmp}§
     9616int main( void ) {
     9617        sout | "Factorial Numbers";
     9618        ®Int® fact = 1;
     9619
     9620        sout | 0 | fact;
     9621        for ( i; 40 ) {
     9622                fact *= i;
     9623                sout | i | fact;
     9624        }
     9625}
     9626\end{cfa}
     9627&
    93039628\begin{cfa}
    93049629#include <gmp.h>§\indexc{gmp.h}§
     
    93119636                ®mpz_mul_ui®( fact, fact, i );
    93129637                ®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;
    93279638        }
    93289639}
     
    94199730Rational narrow( double f, long int md );
    94209731
    9421 forall( dtype istype | istream( istype ) ) istype * ?|?( istype *, Rational * ); // I/O
    9422 forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype *, Rational );
     9732forall( istype & | istream( istype ) ) istype * ?|?( istype *, Rational * ); // I/O
     9733forall( ostype & | ostream( ostype ) ) ostype * ?|?( ostype *, Rational );
    94239734\end{cfa}
    94249735
     
    94409751\end{document}
    94419752
     9753From: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>
     9754To: Peter Buhr <pabuhr@uwaterloo.ca>,
     9755        Andrew James Beach
     9756        <ajbeach@uwaterloo.ca>,
     9757        Fangren Yu <f37yu@uwaterloo.ca>, Jiada Liang
     9758        <j82liang@uwaterloo.ca>
     9759Subject: The White House on Memory-Safe programming
     9760Date: Mon, 4 Mar 2024 16:49:53 +0000
     9761
     9762I heard tell of this announcement last night.  Haven't read the actual report yet.
     9763
     9764Most mainstream article I can find:  https://me.pcmag.com/en/security/22413/white-house-to-developers-using-c-or-c-invites-cybersecurity-risks
     9765Less fluffy summary:  https://www.developer-tech.com/news/2024/feb/27/white-house-urges-adoption-memory-safe-programming-languages/
     9766Horse's Mouth:  https://www.whitehouse.gov/wp-content/uploads/2024/02/Final-ONCD-Technical-Report.pdf
     9767"This report focuses on the programming language as a primary building block, and explores hardware architecture and formal methods as complementary approaches"
     9768
     9769A contrary analysis:  https://hackaday.com/2024/02/29/the-white-house-memory-safety-appeal-is-a-security-red-herring/
     9770
    94429771% Local Variables: %
    94439772% tab-width: 4 %
  • libcfa/src/concurrency/actor.hfa

    r0fe07be r15215f02  
    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
  • src/AST/Pass.hpp

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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/Common/PersistentMap.h

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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

    r0fe07be r15215f02  
    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 * Gen