Changes in / [15215f02:0fe07be]


Ignore:
Files:
1 added
35 edited

Legend:

Unmodified
Added
Removed
  • doc/LaTeXmacros/common.sty

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

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

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

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

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

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

    r15215f02 r0fe07be  
    4848
    4949\section{C Enumeration}
    50 \label{s:CEnumeration}
    5150
    52 The 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
    58 enumerator-list:
    59         enumerator
    60         enumerator-list , enumerator
    61 enumerator:
    62         enumeration-constant
    63         enumeration-constant = constant-expression
    64 \end{clang}
    65 The terms \emph{enumeration} and \emph{enumerator} used in this work \see{\VRef{s:Terminology}} come from the grammar.
    66 The C enumeration semantics is discussed using examples.
    67 
    68 An unnamed enumeration is used to provide secondary renaming, like a @const@ declaration in other languages.
    69 \begin{clang}
    70 enum { Size = 20, Pi = 3.14159 };   // unnamed enumeration $\(\Rightarrow\)$ no ordering
    71 \end{clang}
    72 This declaration form is not an enumeration even though it is declared using an @enum@ because it has none of the following enumeration properties.
    73 
    74 A \emph{named} enumeration type is an actual enumeration.
     51The C enumeration has the following syntax and semantics.
    7552\begin{clang}
    7653enum Weekday { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun, };
  • doc/theses/jiada_liang_MMath/intro.tex

    r15215f02 r0fe07be  
    11\chapter{Introduction}
    22
    3 All types in a programming language must have a set of constants, and these constants have \Newterm{primary names}, \eg integral types have constants @-1@, @17@, @0xff@, floating-point types have constants @5.3@, @2.3E-5@, @0xff.ffp0@, character types have constants @'a'@, @"abc\n"@, \mbox{\lstinline{u8"}\texttt{\guillemotleft{na\"{i}ve}\guillemotright}\lstinline{"}}, \etc.
    4 Con\-stants can be overloaded among types, \eg @0@ is a null pointer for all pointer types, and the value zero for integral and floating-point types.
    5 (In \CFA, the primary constants @0@ and @1@ can be overloaded for any type.)
     3All types in a programming language must have a set of constants, and these constants have \Newterm{primary names}, \eg integral types have constants @-1@, @17@, @12345@, \etc.
     4Constants can be overloaded among types, \eg @0@ is a null pointer for all pointer types, and the value zero for integral and floating-point types.
    65Hence, each primary constant has a symbolic name referring to its internal representation, and these names are dictated by language syntax related to types.
    76In theory, there are an infinite set of primary names per type.
    87
    9 \Newterm{Secondary naming} is a common practice in mathematics, engineering and computer science, \eg $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MB (mega byte, 1E6), and in general situations, \eg specific times (noon, New Years), cities (Big Apple), flowers (Lily), \etc.
     8\Newterm{Secondary naming} is a common practice in mathematics and engineering, \eg $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MHz (1E6), and in general situations, \eg specific times (noon, New Years), cities (Big Apple), flowers (Lily), \etc.
    109Many programming languages capture this important software-engineering capability through a mechanism called \Newterm{constant} or \Newterm{literal} naming, where a secondary name is aliased to a primary name.
    11 Its common purpose is to eliminate duplication of the primary constant throughout a program.
    12 For 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.
    13 In some cases, secondary naming is \Newterm{opaque}, where the matching internal representation can be chosen arbitrarily, and only equality operations are available, \eg @O_RDONLY@, @O_WRONLY@, @O_CREAT@, @O_TRUNC@, @O_APPEND@.
     10In some cases, secondary naming is \Newterm{pure}, where the matching internal representation can be chosen arbitrarily, and only equality operations are available, \eg @O_RDONLY@, @O_WRONLY@, @O_CREAT@, @O_TRUNC@, @O_APPEND@.
     11(The names the thing.)
    1412Because 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{
    1513The term rvalue defines an expression that can only appear on the right-hand side of an assignment expression.}.
     
    2018enumerate (verb, transitive).
    2119To count, ascertain the number of;
    22 more usually, to mention (a number of things or persons) separately, as if for the purpose of counting;
    23 to specify as in a list or catalogue.~\cite{OEDenumerate}
     20\emph{more
     21usually, to mention (a number of things or persons) separately, as if for the
     22purpose of counting};
     23to specify as in a list or catalogue.~\cite{OED}
    2424\end{quote}
    25 Within an enumeration set, the enumeration names must be unique, and instances of an enumerated type are \emph{often} restricted to hold only the secondary names.
     25Within an enumeration set, the enumeration names must be unique, and instances of an enumerated type are restricted to hold only the secondary names.
    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 Sat, Sun } ...                                  $\C{// weekend}$
     31for ( cursor in Thu, Fri } ...                                  $\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 (eighth note, quaver), giving synonyms.
     34This independence from internal representation allows multiple names to have the same representation (eight 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 logically \emph{generated} rather than listing a subset of names.
    41 
    42 Hence, the fundamental aspects of an enumeration are:
    43 \begin{enumerate}
    44 \item
    45 It defines a type from which instants can be generated.
    46 \item
    47 The type lists a finite set of secondary names, which become its primary constants.
    48 This differentiates an enumeration from general types with an infinite number of primary constants.
    49 \item
    50 An enumeration's secondary names represent constants, which follows from their binding (aliasing) to primary names, which are constants.
    51 \item
    52 For safety, an enumeration instance is restricted to hold only its type's secondary names.
    53 \item
    54 There is a mechanism for \emph{enumerating} over the secondary names, where the ordering can be implicit from the type, explicitly listed, or generated arithmetically.
    55 \end{enumerate}
     40Here the internal representations for the secondary names are \emph{generated} rather than listing a subset of names.
    5641
    5742
    5843\section{Terminology}
    59 \label{s:Terminology}
    6044
    61 The term \Newterm{enumeration} defines a type with a set of secondary names, and the term \Newterm{enumerator} represents an arbitrary secondary name \see{\VRef{s:CEnumeration}}.
     45The term \Newterm{enumeration} defines the set of secondary names, and the term \Newterm{enumerator} represents an arbitrary secondary name.
    6246As well, an enumerated type has three fundamental properties, \Newterm{label}, \Newterm{order}, and \Newterm{value}.
    6347\begin{cquote}
     
    8872\section{Motivation}
    8973
    90 Some programming languages only provide direct secondary renaming.
     74Some programming languages only provide secondary renaming, which can be simulated by an enumeration without ordering.
    9175\begin{cfa}
    92 const Size = 20, Pi = 3.14159, Name = "Jane";
     76const Size = 20, Pi = 3.14159;
     77enum { Size = 20, Pi = 3.14159 };   // unnamed enumeration $\(\Rightarrow\)$ no ordering
    9378\end{cfa}
    94 Here, it is possible to compare the secondary names, \eg @Size < Pi@, if that is meaningful.
     79In both cases, it is possible to compare the secondary names, \eg @Size < Pi@, if that is meaningful;
     80however, without an enumeration type-name, it is impossible to create an iterator cursor.
    9581
    96 Secondary renaming can simulate an enumeration, but with extra effort.
     82Secondary renaming can similate an enumeration, but with extra effort.
    9783\begin{cfa}
    9884const Mon = 1, Tue = 2, Wed = 3, Thu = 4, Fri = 5, Sat = 6, Sun = 7;
    9985\end{cfa}
    100 Any reordering of the enumerators requires manual renumbering.
     86Furthermore, reordering the enumerators requires manual renumbering.
    10187\begin{cfa}
    10288const Sun = 1, Mon = 2, Tue = 3, Wed = 4, Thu = 5, Fri = 6, Sat = 7;
    10389\end{cfa}
    104 Finally, there is no type to create a type-checked instance or iterator cursor.
    105 Hence, there is only a weak equivalence between secondary naming and enumerations, justifying a seperate enumeration type in a programming language.
     90Finally, there is no common type to create a type-checked instance or iterator cursor.
     91Hence, there is only a weak equivalence between secondary naming and enumerations, justifying the enumeration type in a programming language.
    10692
    107 A variant (algebraic) type is often promoted as a kind of enumeration, \ie a variant type can simulate an enumeration.
    108 Fundamentally, a variant type is a tagged-union, where the tag is normally opaque and the types are usually heterogeneous.
    109 \begin{cfa}[morekeywords={variant}]
     93A variant (algebraic) type is often promoted as a kind of enumeration, \ie a varient type can simulate an enumeration.
     94A variant type is a tagged-union, where the possible types may be heterogeneous.
     95\begin{cfa}
    11096@variant@ Variant {
    11197        @int tag;@  // optional/implicit: 0 => int, 1 => double, 2 => S
     
    117103};
    118104\end{cfa}
    119 Crucially, 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.
    120 Hence, knowing which type is in a variant instance is crucial for correctness.
    121 Occasionally, it is possible to statically determine all regions where each variant type is used, so a tag and runtime checking is unnecessary.
    122 Otherwise, 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.
     105Crucially, the union implies instance storage is shared by all of the variant types.
     106Hence, a variant is dynamically typed, as in a dynamic-typed programming-language, but the set of types is statically bound, similar to some aspects of dynamic gradual-typing~\cite{Gradual Typing}.
     107Knowing which type is in a variant instance is crucial for correctness.
     108Occasionally, it is possible to statically determine all regions where each variant type is used, so a tag and runtime checking is unnecessary;
     109otherwise, a tag is required to denote the particular type in the variant and the tag checked at runtime using some form of type pattern-matching.
    123110
    124 A 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}]
    128 variant VariantCT {
    129         case @car@: int i;  // explicitly typed
    130         case @boat@: int i;
    131         case @bridge@: int i;
     111The tag can be implicitly set by the compiler on assignment, or explicitly set by the program\-mer.
     112Type pattern-matching is then used to dynamically test the tag and branch to a section of code to safely manipulate the value, \eg:
     113\begin{cfa}[morekeywords={match}]
     114Variant v = 3;  // implicitly set tag to 0
     115@match@( v ) {    // know the type or test the tag
     116        case int { /* only access i field in v */ }
     117        case double { /* only access d field in v */ }
     118        case S { /* only access s field in v */ }
     119}
     120\end{cfa}
     121For safety, either all variant types must be listed or a @default@ case must exist with no field accesses.
     122
     123To simulate an enumeration with a variant, the tag is \emph{re-purposed} for either ordering or value and the variant types are omitted.
     124\begin{cfa}
     125variant Weekday {
     126        int tag; // implicit 0 => Mon, ..., 6 => Sun
     127        @case Mon;@ // no type
     128        ...
     129        @case Sun;@
    132130};
    133131\end{cfa}
    134 &
    135 \begin{cfa}[morekeywords={variant}]
    136 variant VariantCU {
    137         case @car@: ;  // empty or unit type
    138         case @boat@: ;
    139         case @bridge@: ;
    140 };
     132The type system ensures tag setting and testing are correctly done.
     133However, the enumeration operations are limited to the available tag operations, \eg pattern matching.
     134\begin{cfa}
     135Week week = Mon;
     136if ( @dynamic_cast(Mon)@week ) ... // test tag == Mon
    141137\end{cfa}
    142 \end{tabular}
    143 \end{cquote}
    144 Here, 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.
    145 It is even possible to remove the type or use the empty @unit@ type (@struct unit {}@).
    146 It is this tag naming that is used to simulate an enumeration.
     138While enumerating among tag names is possible:
     139\begin{cfa}[morekeywords={in}]
     140for ( cursor in Mon, Wed, Fri, Sun ) ...
     141\end{cfa}
     142ordering for iteration would require a \emph{magic} extension, such as a special @enum@ variant, because it has no meaning for a regular variant, \ie @int@ < @double@.
    147143
    148 Normally, 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}
    150 Variant v = 3;                                                  $\C{// implicitly set tag to 0 based on type of 3}$
    151 VariantCT ve = boats.3;                                 $\C{// explicitly set tag to 1 using tag name}$
    152 \end{cfa}
    153 Type 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@{}}
     144However, if a special @enum@ variant allows the tags to be heterogeneously typed, ordering must fall back on case positioning, as many types have incomparable values.
     145Iterating using tag ordering and heterogeneous types, also requires pattern matching.
    156146\begin{cfa}[morekeywords={match}]
    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 */ }
     147for ( cursor = Mon; cursor <= Fri; cursor = succ( cursor) ) {
     148        match( cursor ) {
     149                case Mon { /* access special type for Mon */ }
     150                ...
     151                case Fri { /* access special type for Fri */ }
     152                default
     153        }
    161154}
    162155\end{cfa}
    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}
    173 For safety, some languages require all variant types to be listed or a @default@ case with no field accesses.
     156If the variant type is changed by adding/removing types or the loop range changes, the pattern matching must be adjusted.
     157As well, if the start/stop values are dynamic, it may be impossible to statically determine if all variant types are listed.
    174158
    175 To 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}
    179 variant Week {
    180         case Mon: const int = 0;
    181         ...
    182         case Sat: const int = 5;
    183         case Sun: const int = 10;
    184 };
    185 \end{cfa}
    186 &
    187 \begin{cfa}
    188 variant 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}
    197 Directly setting the tag implies restrictions, like unique values.
    198 In both cases, instances of @Week@ are @const@ (immutable).
    199 However, usage between these two types becomes complex.
    200 \begin{cfa}
    201 Week day = Week.Mon;  // sets value or tag depending on type
    202 if ( day == Week.Mon )   // dereference value or tag ?
    203 \end{cfa}
    204 Here, the dereference of @day@ should return the value of the type stored in the variant, never the tag.
    205 If 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 
    208 In general, the enumeration simulation and the variant extensions to support it, are deviating from the normal use of a variant (union) type.
    209 As well, the enumeration operations are limited to the available tag operations, \eg pattern matching.
    210 While enumerating among tag names is possible:
    211 \begin{cfa}[morekeywords={in}]
    212 for ( cursor in Week.Mon, Week.Wed, Week.Fri, Week.Sun ) ...
    213 \end{cfa}
    214 what is the type of @cursor@?
    215 If it the tag type (@int@), how is this value used?
    216 If it is the variant type, where is the instance variable, which only contains one value.
    217 Hence, 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 
    219 While functional programming systems regularly re-purposing variant types into enumeration types, this process seems contrived and confusing.
    220 A variant tag is not an enumeration, it is a discriminant among a restricted set of types stored in a storage block.
    221 Hence, there is only a weak equivalence between an enumeration and variant type, justifying a seperate enumeration type in a programming language.
     159Re-purposing the notion of enumerating into variant types is ill formed and confusing.
     160Hence, there is only a weak equivalence between an enumeration and variant type, justifying the enumeration type in a programming language.
    222161
    223162
  • doc/theses/jiada_liang_MMath/relatedwork.tex

    r15215f02 r0fe07be  
    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 a set of ordered unscoped identifiers (enumerators) bound to \emph{unique} \Newterm{literals}.\footnote{%
    56 Ada is \emph{case-insensitive} so identifiers may appear in multiple forms and still be the same, \eg \lstinline{Mon}, \lstinline{moN}, and \lstinline{MON} (a questionable design decision).}
     55An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
    5756\begin{ada}
    58 type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun ); -- literals (enumerators)
     57type RGB is ( Red, Green, Blue ); -- 3 literals (enumerators)
    5958\end{ada}
    6059Object initialization and assignment are restricted to the enumerators of this type.
    61 While Ada enumerators are unscoped, like C, Ada enumerators are overloadable.
     60Enumerators without an explicitly designated constant value are auto-initialized: from left to right, starting at zero or the next explicitly initialized constant, incrementing by 1.
     61To explicitly set enumerator values, \emph{all} enumerators must be set in \emph{ascending} order, \ie there is no auto-initialization.
    6262\begin{ada}
    63 type RGB is ( @Red@, @Green@, Blue );
     63type RGB is ( Red, Green, Blue );
     64@for RGB use ( Red => 10, Green => 20, Blue => 30 );@ -- ascending order
     65\end{ada}
     66Hence, the position, value, label tuples are:
     67\begin{ada}
     68(0, 10, RED)  (1, 20, GREEN)  (2, 30, BLUE)
     69\end{ada}
     70Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same, \eg @Red@ and @RED@ (a questionable design decision).
     71
     72Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope.
     73The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of enumerators, which is always ascending.
     74
     75Ada enumerators are overloadable.
     76\begin{ada}
    6477type Traffic_Light is ( @Red@, Yellow, @Green@ );
    6578\end{ada}
    66 Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded identifiers.
     79Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded names.
    6780\VRef[Figure]{f:AdaEnumeration} shows how ambiguity is handled using a cast, \ie \lstinline[language=ada]{RGB'(Red)}.
    6881
     
    89102\end{figure}
    90103
    91 Enumerators without initialization are auto-initialized from left to right, starting at zero, incrementing by 1.
    92 Enumerators with initialization must set \emph{all} enumerators in \emph{ascending} order, \ie there is no auto-initialization.
    93 \begin{ada}
    94 type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
    95 for Week use ( Mon => 0, Tue => 1, Wed => 2, Thu => @10@, Fri => 11, Sat => 14, Sun => 15 );
    96 \end{ada}
    97 The enumeration operators are the equality and relational operators, @=@, @/=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of acsending enumerators.
    98 
    99 Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package identifiers.
     104Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package names.
    100105\begin{ada}
    101106OtherRed : RGB renames Red;
     
    108113There are three pairs of inverse enumeration pseudo-functions (attributes): @'Pos@ and @'Val@, @'Enum_Rep@ and @'Enum_Val@, and @'Image@ and @'Value@,
    109114\begin{cquote}
     115\lstDeleteShortInline@
    110116\setlength{\tabcolsep}{15pt}
    111117\begin{tabular}{@{}ll@{}}
     
    122128\end{ada}
    123129\end{tabular}
     130\lstMakeShortInline@
    124131\end{cquote}
    125132These attributes are important for IO.
     
    131138\end{ada}
    132139which is syntactic sugar for the label and not character literals from the predefined type @Character@.
    133 The purpose is strictly readability using character literals rather than identifiers.
     140The purpose is strictly readability using character literals rather than names.
    134141\begin{ada}
    135142Op : Operator := '+';
     
    164171An enumeration type can be used in the Ada \lstinline[language=ada]{case} (all enumerators must appear or a default) or iterating constructs.
    165172\begin{cquote}
     173\lstDeleteShortInline@
    166174\setlength{\tabcolsep}{15pt}
    167175\begin{tabular}{@{}ll@{}}
     
    203211\end{ada}
    204212\end{tabular}
     213\lstMakeShortInline@
    205214\end{cquote}
    206215
     
    220229\CC has the equivalent of Pascal typed @const@ declarations \see{\VRef{s:Pascal}}, with static and dynamic initialization.
    221230\begin{c++}
    222 const auto one = 0 + 1;                                 $\C{// static initialization}$
     231const auto one = 0 + 1;                                 $\C{// static intialization}$
    223232const auto NULL = nullptr;
    224233const auto PI = 3.14159;
     
    228237                                Sat = Fri + 1, Sun = Sat + 1;
    229238int sa[Sun];
    230 const auto r = random();                                $\C{// dynamic initialization}$
     239const auto r = random();                                $\C{// dynamic intialization}$
    231240int da[r];                                                              $\C{// VLA}$
    232241\end{c++}
     
    353362\begin{figure}
    354363\centering
     364\lstDeleteShortInline@
    355365\begin{tabular}{@{}l|l@{}}
    356366\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
     
    404414\end{csharp}
    405415\end{tabular}
     416\lstMakeShortInline@
    406417\caption{\Csharp: Free Routine Versus Class Enumeration}
    407418\label{CsharpFreeVersusClass}
     
    418429const ( S = 0; T; USA = "USA"; U; V = 3.1; W ) $\C{// type change, implicit/explicit: 0 0 USA USA 3.1 3.1}$
    419430\end{Go}
    420 Constant identifiers are unscoped and must be unique (no overloading).
     431Constant names are unscoped and must be unique (no overloading).
    421432The first enumerator \emph{must} be explicitly initialized;
    422433subsequent enumerators can be implicitly or explicitly initialized.
     
    448459Basic switch and looping are possible.
    449460\begin{cquote}
     461\lstDeleteShortInline@
    450462\setlength{\tabcolsep}{15pt}
    451463\begin{tabular}{@{}ll@{}}
     
    470482\end{Go}
    471483\end{tabular}
     484\lstMakeShortInline@
    472485\end{cquote}
    473486However, the loop prints the values from 0 to 13 because there is no actual enumeration.
     
    500513\begin{figure}
    501514\centering
     515\lstDeleteShortInline@
    502516\begin{tabular}{@{}l|l@{}}
    503517\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
     
    539553\end{Java}
    540554\end{tabular}
     555\lstMakeShortInline@
    541556\caption{Java: Free Routine Versus Class Enumeration}
    542557\label{f:JavaFreeVersusClass}
     
    592607\section{Rust}
    593608\lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    594 % https://doc.rust-lang.org/reference/items/enumerations.html
    595609
    596610Rust provides a scoped enumeration based on variant types.
     
    9961010
    9971011
    998 \section{Python 3.13}
     1012\section{Python}
    9991013\lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    1000 % https://docs.python.org/3/howto/enum.html
    1001 
    1002 Python is a dynamically-typed reflexive programming language with multiple versions, and hence, it is possible to extend existing or build new language features within the language.
    1003 As a result, discussing Python enumerations is a moving target, because if a features does not exist, if can often be created with varying levels of complexity.
    1004 Nevertheless, an attempt has been made to discuss core enumeration features that come with Python 3.13.
    1005 
    1006 A Python enumeration type is a set of ordered scoped identifiers (enumerators) bound to \emph{unique} values.
    1007 An enumeration is not a basic type;
    1008 it is a @class@ inheriting from the @Enum@ class, where the enumerators must be explicitly initialized, \eg:
    1009 \begin{python}
    1010 class Week(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
    1011 \end{python}
    1012 and/or explicitly auto initialized, \eg:
    1013 \begin{python}
    1014 class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @auto()@; Sat = 4; Sun = @auto()@
    1015 \end{python}
    1016 where @auto@ increments by 1 from the previous enumerator value.
    1017 Object initialization and assignment are restricted to the enumerators of this type.
    1018 An 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}
    1020 class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @10@; Sat = @10@; Sun = @10@
    1021 \end{python}
    1022 Here, the enumeration has only 4 enumerators and 3 aliases.
    1023 An 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;
    1025 the extended class @OrderedEnum@ adds relational operators @<@, @<=@, @>@, and @>=@.
    1026 
    1027 There 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}
    1032 Week.Thu.value == 10;
    1033 Week.Thu.name == 'Thu';
    1034 \end{python}
    1035 &
    1036 \begin{python}
    1037 Week( 10 ) == Thu
    1038 Week['Thu'].value = 10
    1039 \end{python}
    1040 \end{tabular}
    1041 \end{cquote}
    1042 
    1043 As an enumeration is a \lstinline[language=python]{class}, its own methods.
    1044 \begin{python}
    1045 class 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())
    1050 print( "today:", Week.today(date.today()))
    1051 today: Week.Mon
    1052 \end{python}
    1053 The method @today@ retrieves the day of the week and uses it as an index to print out the corresponding label of @Week@.
     1014
     1015A Python enumeration is a set of symbolic names bound to \emph{unique} values.
     1016They are similar to global variables, but offer a more useful @repr()@, grouping, type-safety, and additional features.
     1017Enumerations inherits from the @Enum@ class, \eg:
     1018\begin{python}
     1019class Weekday(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
     1020class RGB(@Enum@): Red = 1; Green = 2; Blue = 3
     1021\end{python}
     1022
     1023Depending on the nature of the enum a member's value may or may not be important, but either way that value can be used to get the corresponding member:
     1024\begin{python}
     1025print( repr( Weekday( 3 ) ) )
     1026<Weekday.Wed: 3>
     1027\end{python}
     1028As you can see, the @repr()@ of a member shows the enum name, the member name, and the value.
     1029The @str()@ of a member shows only the enum name and member name:
     1030\begin{python}
     1031print( str( Weekday.Thu ), Weekday.Thu )
     1032Weekday.Thu Weekday.Thu
     1033\end{python}
     1034The type of an enumeration member is the enum it belongs to:
     1035\begin{python}
     1036print( type( Weekday.Thu ) )
     1037<enum 'Weekday'>
     1038print( isinstance(Weekday.Fri, Weekday) )
     1039True
     1040\end{python}
     1041Enum members have an attribute that contains just their name:
     1042\begin{python}
     1043print(Weekday.TUESDAY.name)
     1044TUESDAY
     1045\end{python}
     1046Likewise, they have an attribute for their value:
     1047\begin{python}
     1048Weekday.WEDNESDAY.value
     10493
     1050\end{python}
     1051
     1052Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added.
     1053For example, @datetime.date@ has two methods for returning the weekday: @weekday()@ and @isoweekday()@.
     1054The difference is that one of them counts from 0-6 and the other from 1-7.
     1055Rather than keep track of that ourselves we can add a method to the @Weekday@ enum to extract the day from the date instance and return the matching enum member:
     1056\begin{python}
     1057class Weekday(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = 15; Sat = 16; Sun = 17
     1058$@$classmethod
     1059def from_date(cls, date):
     1060        return cls(date.isoweekday())
     1061\end{python}
     1062Now we can find out what today is! Observe:
     1063\begin{python}
     1064>>> from datetime import date
     1065>>> Weekday.from_date(date.today())     
     1066<Weekday.TUESDAY: 2>
     1067\end{python}
     1068Of course, if you're reading this on some other day, you'll see that day instead.
     1069
     1070This Weekday enum is great if our variable only needs one day, but what if we need several? Maybe we're writing a function to plot chores during a week, and don't want to use a @list@ -- we could use a different type of @Enum@:
     1071\begin{python}
     1072from enum import Flag
     1073class WeekdayF(@Flag@): Mon = @1@; Tue = @2@; Wed = @4@; Thu = @8@; Fri = @16@; Sat = @32@; Sun = @64@
     1074\end{python}
     1075We've changed two things: we're inherited from @Flag@, and the values are all powers of 2.
    10541076
    10551077@Flag@ allows combining several members into a single variable:
    10561078\begin{python}
    1057 print( repr(WeekF.Sat | WeekF.Sun) )
    1058 <WeekF.Sun|Sat: 96>
     1079print( repr(WeekdayF.Sat | WeekdayF.Sun) )
     1080<WeekdayF.Sun|Sat: 96>
    10591081\end{python}
    10601082You can even iterate over a @Flag@ variable:
     
    10621084for day in weekend:
    10631085        print(day)
    1064 WeekF.Sat
    1065 WeekF.Sun
     1086Weekday.SATURDAY
     1087Weekday.SUNDAY
    10661088\end{python}
    10671089Okay, let's get some chores set up:
    10681090\begin{python}
    10691091>>> chores_for_ethan = {
    1070 ...    'feed the cat': Week.MONDAY | Week.WEDNESDAY | Week.FRIDAY,
    1071 ...    'do the dishes': Week.TUESDAY | Week.THURSDAY,
    1072 ...    'answer SO questions': Week.SATURDAY,
     1092...    'feed the cat': Weekday.MONDAY | Weekday.WEDNESDAY | Weekday.FRIDAY,
     1093...    'do the dishes': Weekday.TUESDAY | Weekday.THURSDAY,
     1094...    'answer SO questions': Weekday.SATURDAY,
    10731095...    }
    10741096\end{python}
     
    10791101...        if day in days:
    10801102...            print(chore)
    1081 >>> show_chores(chores_for_ethan, Week.SATURDAY)
     1103>>> show_chores(chores_for_ethan, Weekday.SATURDAY)
    10821104answer SO questions
    10831105\end{python}
    1084 Auto incrmenet for @Flag@ is by powers of 2.
    1085 \begin{python}
    1086 class WeekF(Flag): Mon = auto(); Tue = auto(); Wed = auto(); Thu = auto(); Fri = auto();  \
    1087                                                         Sat = auto(); Sun = auto(); Weekend = Sat | Sun
    1088 for d in WeekF:
    1089         print( f"{d.name}: {d.value}", end=" ")
    1090 Mon: 1 Tue: 2 Wed: 4 Thu: 8 Fri: 16 Sat: 32 Sun: 64 WeekA.Weekend
     1106In cases where the actual values of the members do not matter, you can save yourself some work and use @auto()@ for the values:
     1107\begin{python}
     1108>>> from enum import auto
     1109>>> class Weekday(Flag):
     1110...    MONDAY = auto()
     1111...    TUESDAY = auto()
     1112...    WEDNESDAY = auto()
     1113...    THURSDAY = auto()
     1114...    FRIDAY = auto()
     1115...    SATURDAY = auto()
     1116...    SUNDAY = auto()
     1117...    WEEKEND = SATURDAY | SUNDAY
    10911118\end{python}
    10921119
     
    10961123@Enum@ allows such access:
    10971124\begin{python}
    1098 print(RGB(1), RGB(3), )
    1099 RGB.RED RGB.GREEN
     1125>>> Color(1)
     1126<Color.RED: 1>
     1127>>> Color(3)
     1128<Color.BLUE: 3>
    11001129\end{python}
    11011130If you want to access enum members by name, use item access:
    11021131\begin{python}
    1103 print( RGBa['RED'], RGBa['GREEN'] )
    1104 RGB.RED RGB.GREEN
     1132Color['RED']
     1133<Color.RED: 1>
     1134
     1135Color['GREEN']
     1136<Color.GREEN: 2>
    11051137\end{python}
    11061138If you have an enum member and need its name or value:
    11071139\begin{python}
    1108 member = RGBa.RED
    1109 print( f"{member.name} {member.value}" )
    1110 RED 1
    1111 \end{python}
    1112 
     1140>>> member = Color.RED
     1141>>> member.name
     1142'RED'
     1143>>> member.value
     11441
     1145\end{python}
     1146
     1147\subsection{Duplicating enum members and values}
     1148
     1149An enum member can have other names associated with it.
     1150Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@.
     1151By-value lookup of the value of @A@ will return the member @A@.
     1152By-name lookup of @A@ will return the member @A@.
     1153By-name lookup of @B@ will also return the member @A@:
     1154\begin{python}
     1155class Shape(Enum): SQUARE = 2; DIAMOND = 1; CIRCLE = 3; ALIAS_FOR_SQUARE = 2
     1156>>> Shape.SQUARE
     1157<Shape.SQUARE: 2>
     1158>>> Shape.ALIAS_FOR_SQUARE
     1159<Shape.SQUARE: 2>
     1160>>> Shape(2)
     1161<Shape.SQUARE: 2>
     1162\end{python}
     1163
     1164Note: Attempting to create a member with the same name as an already defined attribute (another member, a method, etc.) or attempting to create an attribute with the same name as a member is not allowed.
    11131165
    11141166\subsection{Ensuring unique enumeration values}
     
    11551207>>> list(Shape)
    11561208[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
    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}
    1161 Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Week.WEEKEND@ aren't shown.
     1209>>> list(Weekday)
     1210[<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>,
     1211<Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]
     1212\end{python}
     1213Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Weekday.WEEKEND@ aren't shown.
    11621214
    11631215The special attribute @__members__@ is a read-only ordered mapping of names to members.
     
    21662218
    21672219OCaml provides a variant (union) type, where multiple heterogeneously-typed objects share the same storage.
    2168 The simplest form of the variant type is a list of nullary datatype constructors, which is like an unscoped, opaque enumeration.
    2169 
     2220The simplest form of the variant type is a list of nullary datatype constructors, which is like an unscoped, pure enumeration.
     2221
     2222(I think the value of a ocaml variants are types not object, so I am not sure about this line)
    21702223OCaml provides a variant (union) type, which is an aggregation of heterogeneous types.
    2171 A basic variant is a list of nullary datatype constructors, which is like an unscoped, opaque enumeration.
     2224A basic variant is a list of nullary datatype constructors, which is like an unscoped, pure enumeration.
    21722225\begin{ocaml}
    21732226type weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun
     
    21932246type colour = Red | Green of @string@ | Blue of @int * float@
    21942247\end{ocaml}
    2195 A variant with parameter is stored in a memory block, prefixed by an int tag and has its parameters stores as words in the block.
     2248A variant with parameter is stored in a memory block, prefixed by an int tag and has its parameters stores as words in the block. 
    21962249@colour@ is a summation of a nullary type, a unary product type of @string@, and a cross product of @int@ and @float@.
    21972250(Mathematically, a @Blue@ value is a Cartesian product of the types @int@ type and @float@.)
     
    22062259@Red, abc, 1 1.5@
    22072260\end{ocaml}
     2261
    22082262
    22092263A variant type can have a recursive definition.
     
    22262280
    22272281In summary, an OCaml variant is a singleton value rather than a set of possibly ordered values, and hence, has no notion of enumerabilty.
    2228 Therefore it is not an enumeration, except for the simple opaque (nullary) case.
     2282Therefore it is not an enumeration, except for the simple pure (nullary) case.
    22292283
    22302284\begin{comment}
     
    24122466With valediction,
    24132467  - Gregor Richards
    2414 
    2415 
    2416 Date: Tue, 16 Apr 2024 11:04:51 -0400
    2417 Subject: Re: C unnamed enumeration
    2418 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
    2419 CC: <ajbeach@uwaterloo.ca>, <j82liang@uwaterloo.ca>, <mlbrooks@uwaterloo.ca>,
    2420         <f37yu@uwaterloo.ca>
    2421 From: Gregor Richards <gregor.richards@uwaterloo.ca>
    2422 
    2423 On 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 
    2427 Your tagless variant bears no resemblance to variants in any functional
    2428 programming language. A variant is a tag AND a union. You might not need to put
    2429 anything in the union, in which case it's a pointless union, but the named tag
    2430 is absolutely mandatory. That's the thing that varies.
    2431 
    2432 I was unaware of std::variant. As far as functional languages are concerned,
    2433 std::variant IS NOT A VARIANT. Perhaps it would be best to use the term ADT for
    2434 the functional language concept, because that term has no other meanings.
    2435 
    2436 An ADT cannot not have a named tag. That's meaningless. The tag is the data
    2437 constructor, which is the thing you actually define when you define an ADT. It
    2438 is strictly the union that's optional.
    2439 
    2440 With valediction,
    2441   - Gregor Richards
    24422468\end{comment}
    24432469
     
    24612487\hline
    24622488\hline
    2463 opaque                  &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
     2489pure                    &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
    24642490\hline
    24652491typed                   &               &               &               &               &               &               &               &               &               &               & @int@ & integral      & @T@   \\
  • doc/theses/jiada_liang_MMath/uw-ethesis.bib

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

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

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

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

    r15215f02 r0fe07be  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Thu Apr 18 21:53:45 2024
    14 %% Update Count     : 6502
     13%% Last Modified On : Mon Feb 12 11:50:26 2024
     14%% Update Count     : 6199
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    130130\vspace*{\fill}
    131131\noindent
    132 \copyright\,2016, 2018, 2021, 2024 \CFA Project \\ \\
     132\copyright\,2016, 2018, 2021 \CFA Project \\ \\
    133133\noindent
    134134This work is licensed under the Creative Commons Attribution 4.0 International License.
     
    312312For example, it is possible to write a type-safe \CFA wrapper ©malloc© based on the C ©malloc©:
    313313\begin{cfa}
    314 forall( T & | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); }
     314forall( dtype T | sized(T) ) T * malloc( void ) { return (T *)malloc( sizeof(T) ); }
    315315int * ip = malloc(); §\C{// select type and size from left-hand side}§
    316316double * dp = malloc();
     
    10231023while () { sout | "empty"; break; }
    10241024do { sout | "empty"; break; } while ();
    1025 for () { sout | "empty"; break; }                               §\C[3in]{sout | nl | nlOff;}§
    1026 
    1027 for ( 0 ) { sout | "A"; } sout | "zero";                §\C{sout | nl;}§
    1028 for ( 1 ) { sout | "A"; }                                               §\C{sout | nl;}§
    1029 for ( 10 ) { sout | "A"; }                                              §\C{sout | nl;}§
    1030 for ( ~= 10 ) { sout | "A"; }                                   §\C{sout | nl;}§
    1031 for ( 1 ~= 10 ~ 2 ) { sout | "B"; }                             §\C{sout | nl;}§
    1032 for ( 1 -~= 10 ~ 2 ) { sout | "C"; }                    §\C{sout | nl;}§
    1033 for ( 0.5 ~ 5.5 ) { sout | "D"; }                               §\C{sout | nl;}§
    1034 for ( 0.5 -~ 5.5 ) { sout | "E"; }                              §\C{sout | nl;}§
    1035 for ( i; 10 ) { sout | i; }                                             §\C{sout | nl;}§
    1036 for ( i; ~= 10 ) { sout | i; }                                  §\C{sout | nl;}§
    1037 for ( i; 1 ~= 10 ~ 2 ) { sout | i; }                    §\C{sout | nl;}§
    1038 for ( i; 1 -~= 10 ~ 2 ) { sout | i; }                   §\C{sout | nl;}§
    1039 for ( i; 0.5 ~ 5.5 ) { sout | i; }                              §\C{sout | nl;}§
    1040 for ( i; 0.5 -~ 5.5 ) { sout | i; }                             §\C{sout | nl;}§
    1041 for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; }               §\C{sout | nl;}§
    1042 for ( ui; 2u -~= 10u ~ 2u ) { sout | ui; }              §\C{sout | nl | nl | nl;}§
     1025for () { sout | "empty"; break; }                                                       §\C{sout | nl | nlOff;}§
     1026
     1027for ( 0 ) { sout | "A"; } sout | "zero";                                        §\C{sout | nl;}§
     1028for ( 1 ) { sout | "A"; }                                                                       §\C{sout | nl;}§
     1029for ( 10 ) { sout | "A"; }                                                                      §\C{sout | nl;}§
     1030for ( ~= 10 ) { sout | "A"; }                                                           §\C{sout | nl;}§
     1031for ( 1 ~= 10 ~ 2 ) { sout | "B"; }                                                     §\C{sout | nl;}§
     1032for ( 1 -~= 10 ~ 2 ) { sout | "C"; }                                            §\C{sout | nl;}§
     1033for ( 0.5 ~ 5.5 ) { sout | "D"; }                                                       §\C{sout | nl;}§
     1034for ( 0.5 -~ 5.5 ) { sout | "E"; }                                                      §\C{sout | nl;}§
     1035for ( i; 10 ) { sout | i; }                                                                     §\C{sout | nl;}§
     1036for ( i; ~= 10 ) { sout | i; }                                                          §\C{sout | nl;}§
     1037for ( i; 1 ~= 10 ~ 2 ) { sout | i; }                                            §\C{sout | nl;}§
     1038for ( i; 1 -~= 10 ~ 2 ) { sout | i; }                                           §\C{sout | nl;}§
     1039for ( i; 0.5 ~ 5.5 ) { sout | i; }                                                      §\C{sout | nl;}§
     1040for ( i; 0.5 -~ 5.5 ) { sout | i; }                                                     §\C{sout | nl;}§
     1041for ( ui; 2u ~= 10u ~ 2u ) { sout | ui; }                                       §\C{sout | nl;}§
     1042for ( ui; 2u -~= 10u ~ 2u ) { sout | ui; }                                      §\C{sout | nl | nl | nl;}§
    10431043
    10441044enum { N = 10 };
    1045 for ( N ) { sout | "N"; }                                               §\C{sout | nl;}§
    1046 for ( i; N ) { sout | i; }                                              §\C{sout | nl;}§
    1047 for ( i; -~ N ) { sout | i; }                                   §\C{sout | nl | nl | nl;}§
     1045for ( N ) { sout | "N"; }                                                                       §\C{sout | nl;}§
     1046for ( i; N ) { sout | i; }                                                                      §\C{sout | nl;}§
     1047for ( i; -~ N ) { sout | i; }                                                           §\C{sout | nl | nl | nl;}§
    10481048
    10491049const int low = 3, high = 10, inc = 2;
    1050 for ( i; low ~ high ~ inc + 1 ) { sout | i; }   §\C{sout | nl;}§
    1051 for ( i; 1 ~ @ ) { if ( i > 10 ) break; sout | i; } §\C{sout | nl;}§
    1052 for ( i; @ -~ 10 ) { if ( i < 0 ) break; sout | i; } §\C{sout | nl;}§
    1053 for ( i; 2 ~ @ ~ 2 ) { if ( i > 10 ) break; sout | i; } §\C{sout | nl;}§
     1050for ( i; low ~ high ~ inc + 1 ) { sout | i; }                           §\C{sout | nl;}§
     1051for ( i; 1 ~ @ ) { if ( i > 10 ) break; sout | i; }                     §\C{sout | nl;}§
     1052for ( i; @ -~ 10 ) { if ( i < 0 ) break; sout | i; }            §\C{sout | nl;}§
     1053for ( i; 2 ~ @ ~ 2 ) { if ( i > 10 ) break; sout | i; }         §\C{sout | nl;}§
    10541054for ( i; 2.1 ~ @ ~ @ ) { if ( i > 10.5 ) break; sout | i; i += 1.7; } §\C{sout | nl;}§
    10551055for ( i; @ -~ 10 ~ 2 ) { if ( i < 0 ) break; sout | i; }        §\C{sout | nl;}§
    10561056for ( i; 12.1 ~ @ ~ @ ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; } §\C{sout | nl;}§
    1057 for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }              §\C{sout | nl;}§
    1058 for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }             §\C{sout | nl;}§
    1059 for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }  §\C{sout | nl;}§
    1060 for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; } §\C{sout | nl;}§
    1061 for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }              §\C{sout | nl;}§
    1062 for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }             §\C{sout | nl;}§
    1063 for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }  §\C{sout | nl;}§
    1064 for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; } §\C{sout | nl;}§
     1057for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }                                      §\C{sout | nl;}§
     1058for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }                                     §\C{sout | nl;}§
     1059for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }                          §\C{sout | nl;}§
     1060for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }                         §\C{sout | nl;}§
     1061for ( i; 5 : j; -5 ~ @ ) { sout | i | j; }                                      §\C{sout | nl;}§
     1062for ( i; 5 : j; @ -~ -5 ) { sout | i | j; }                                     §\C{sout | nl;}§
     1063for ( i; 5 : j; -5 ~ @ ~ 2 ) { sout | i | j; }                          §\C{sout | nl;}§
     1064for ( i; 5 : j; @ -~ -5 ~ 2 ) { sout | i | j; }                         §\C{sout | nl;}§
    10651065for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } §\C{sout | nl;}§
    10661066for ( i; 5 : j; @ -~ -5 ~ 2 : k; 1.5 ~ @ ) { sout | i | j | k; } §\C{sout | nl;}§
    1067 for ( i; 5 : k; 1.5 ~ @ : j; @ -~ -5 ~ 2 ) { sout | i | j | k; } §\C{sout | nl;}\CRT§
     1067for ( i; 5 : k; 1.5 ~ @ : j; @ -~ -5 ~ 2 ) { sout | i | j | k; } §\C{sout | nl;}§
    10681068\end{cfa}
    10691069&
     
    29602960The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter ©x© of type array of 5 integers.
    29612961Since the strings overlap starting with the open bracket, ©[©, there is an ambiguous interpretation for the string.
    2962 
    2963 {\color{red}
    29642962As well, \CFA-style declarations cannot be used to declare parameters for C-style routine-definitions because of the following ambiguity:
    29652963\begin{cfa}
     
    29692967The 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.
    29702968The 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.
    2971 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.}
     2969The 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.
    29722970
    29732971C-style declarations can be used to declare parameters for \CFA style routine definitions, \eg:
     
    30573055static [ int ] g ( int );
    30583056\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.
    3065 The syntax uses the backquote ©`© to separate the parameters/arguments and function name: ©?`© denotes a postfix-function name, \eg ©int ?`h( int s )© and ©`© denotes a postfix-function call, \eg ©0`h© meaning ©h( 0 )©.
    3066 \begin{cquote}
    3067 \begin{tabular}{@{}l|l|l|l@{}}
    3068 postfix function & constant argument call & variable argument call & postfix function pointer \\
    3069 \hline
    3070 \begin{cfa}
    3071 int ?`h( int s );
    3072 int ?`h( double s );
    3073 int ?`m( char c );
    3074 int ?`m( const char * s );
    3075 int ?`t( int a, int b, int c );
    3076 \end{cfa}
    3077 &       
    3078 \begin{cfa}
    3079 0`h;
    3080 3.5`h;
    3081 '1'`m;
    3082 "123" "456"`m;
    3083 [1,2,3]`t;
    3084 \end{cfa}
    3085 &       
    3086 \begin{cfa}
    3087 int i = 7;
    3088 i`h;
    3089 (i + 3)`h;
    3090 (i + 3.5)`h;
    3091 \end{cfa}
    3092 &       
    3093 \begin{cfa}
    3094 int (* ?`p)( int i );
    3095 ?`p = ?`h;
    3096 3`p;
    3097 i`p;
    3098 (i + 3)`p;
    3099 \end{cfa}
    3100 \end{tabular}
    3101 \end{cquote}
    3102 
    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.}
    3105 The \CFA example (left) stores a mass in units of stones (1 stone = 14 lb or 6.35 kg) and provides an addition operator (imagine a full set of arithmetic operators).
    3106 The three postfixing function names ©st©, ©lb©, and ©kg©, represent units stones, pounds, and kilograms, respectively.
    3107 Each name has two forms that bidirectional convert: a value of a specified unit to stones, \eg ©w = 14`lb© $\Rightarrow$ ©w == 1© stone or a ©Weight© from stones back to specific units, \eg ©w`lb© (1 stone) to ©14©.
    3108 All arithmetic operations manipulate stones and the postfix operations convert to the different units.
    3109 A similar group of postfix functions provide user constants for converting time units into nanoseconds, which is the basic time unit, \eg ©ns©, ©us©, ©ms©, ©s©, ©m©, ©h©, ©d©, and ©w©, for nanosecond, microsecond, millisecond, second, minute, hour, day, and week, respectively.
    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}
    3118 struct Weight {
    3119         double stones;
    3120 };
    3121 
    3122 
    3123 Weight ?+?( Weight l, Weight r ) {
    3124         return l.stones + r.stones;
    3125 }
    3126 Weight ?`st( double w ) { return w; }
    3127 double ?`st( Weight w ) { return w.stones; }
    3128 Weight ?`lb( double w ) { return w / 14.0; }
    3129 double ?`lb( Weight w ) { return w.stones * 14.0; }
    3130 Weight ?`kg( double w ) { return w / 6.35; }
    3131 double ?`kg( Weight w ) { return w.stones * 6.35; }
    3132 int 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++}
    3143 struct Weight {
    3144         double stones;
    3145         Weight() {}
    3146         Weight( double w ) { stones = w; }
    3147 };
    3148 Weight operator+( Weight l, Weight r ) {
    3149         return l.stones + r.stones;
    3150 }
    3151 Weight operator""_st( long double w ) { return w; }
    3152 Weight operator""_lb( long double w ) { return w / 14.0; }
    3153 Weight operator""_kg( long double w ) { return w / 6.35; }
    3154 Weight operator""_st( unsigned long long int w ) { return w; }
    3155 Weight operator""_lb( unsigned long long int w ) { return w / 14.0; }
    3156 Weight operator""_kg( unsigned long long int w ) { return w / 6.35; }
    3157 int 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}
    3169 Time : comparison of time units. \\
    3170 \begin{tabular}{@{}ll@{}}
    3171 \CFA & \CC \\
    3172 \begin{cfa}
    3173 #include <fstream.hfa>
    3174 #include <time.hfa>
    3175 
    3176 
    3177 Duration s = 1`h + 2 * 10`m + 70`s / 10;
    3178 sout | "1 hour + 2*10 min + 70/10 sec = " | s | "seconds";
    3179 sout | "Dividing that by 2 minutes gives" | s / 2`m;
    3180 sout | "Dividing that by 2 gives" | s / 2 | "seconds\n";
    3181 sout | 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>
    3190 using namespace std;
    3191 using namespace std::chrono;
    3192 seconds s = hours(1) + 2 * minutes(10) + seconds(70) / 10;
    3193 cout << "1 hour + 2*10 min + 70/10 sec = " << s.count() << " seconds\n";
    3194 cout << "Dividing that by 2 minutes gives " << s / minutes(2) << '\n';
    3195 cout << "Dividing that by 2 gives " << (s / 2).count() << " seconds\n";
    3196 cout << 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 
    3208 The \CC example (right) provides a \emph{restricted} capability via user literals.
    3209 The \lstinline[language=C++]{operator ""} only takes a constant argument (\ie no variable argument), and the constant type must be the highest-level constant-type, \eg ©long double© for all floating-point constants.
    3210 As well, there is no constant conversion, \ie ©int© to ©double© constants, so integral constants are handled by a separate set of routines, with maximal integral type ©unsigned long long int©.
    3211 Finally, there is no mechanism to use this syntax for a bidirectional conversion because \lstinline[language=C++]{operator ""} does not accept variable arguments.
    32123057
    32133058
     
    39643809\subsection{Polymorphism}
    39653810
    3966 Due to the implicit flattening and structuring conversions involved in argument passing, object and opaque parameters are restricted to matching only with non-tuple types.
     3811Due to the implicit flattening and structuring conversions involved in argument passing, ©otype© and ©dtype© parameters are restricted to matching only with non-tuple types.
    39673812The integration of polymorphism, type assertions, and monomorphic specialization of tuple-assertions are a primary contribution of this thesis to the design of tuples.
    39683813\begin{cfa}
    3969 forall(T, U &)
     3814forall(T, dtype U)
    39703815void f(T x, U * y);
    39713816
     
    50804925        sout | '1' | '2' | '3';
    50814926        sout | 1 | "" | 2 | "" | 3;
    5082         sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x £" | 6 | "x ¥"
    5083                 | 7 | "x ¡" | 8 | "x ¿" | 9 | "x «" | 10;
     4927        sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x £" | 6 | "x Â¥"
     4928                | 7 | "x ¡" | 8 | "x ¿" | 9 | "x «" | 10;
    50844929        sout | 1 | ", x" | 2 | ". x" | 3 | "; x" | 4 | "! x" | 5 | "? x" | 6 | "% x"
    5085                 | 7 | "¢ x" | 8 | "» x" | 9 | ") x" | 10 | "] x" | 11 | "} x";
     4930                | 7 | "¢ x" | 8 | "» x" | 9 | ") x" | 10 | "] x" | 11 | "} x";
    50864931        sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x:" | 4 | ":x " | 5 | " x\t" | 6 | "\tx";
    50874932        sout | "x ( " | 1 | " ) x" | 2 | " , x" | 3 | " :x: " | 4;
     
    79307775\item[Rationale:] increase type safety
    79317776\item[Effect on original feature:] deletion of semantically well-defined feature.
    7932 \item[Difficulty of converting:] requires adding a cast \see{\VRef{s:DynamicStorageManagement} for better alternatives}:
     7777\item[Difficulty of converting:] requires adding a cast \see{\VRef{s:StorageManagement} for better alternatives}:
    79337778\begin{cfa}
    79347779        int * b = (int *)malloc( sizeof(int) );
     
    81437988\label{s:StandardLibrary}
    81447989
    8145 The \CFA standard-library extends existing C library routines by adding new function, wrapping existing explicitly-polymorphic C routines into implicitly-polymorphic versions, and adding new \CFA extensions.
    8146 
    8147 
    8148 \subsection{Dynamic Storage-Management}
    8149 \label{s:DynamicStorageManagement}
    8150 
    8151 Dynamic storage-management in C is based on explicit allocation and deallocation (©malloc©/©free©).
    8152 Programmer's must manage all allocated storage via its address (pointer) and subsequently deallocate the storage via this address.
    8153 Storage that is not deallocated becomes inaccessible, called a \newterm{memory leak}, which can only be detected at program termination.
    8154 Storage freed twice is an error, called a \newterm{duplicate free}, which can sometimes be detected.
    8155 Storage 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 
    8160 C dynamic storage-management provides the following properties.
    8161 \begin{description}[leftmargin=*]
    8162 \item[fill]
    8163 storage after an allocation with a specified character or value.
     7990The \CFA standard-library wraps explicitly-polymorphic C routines into implicitly-polymorphic versions.
     7991
     7992
     7993\subsection{Storage Management}
     7994\label{s:StorageManagement}
     7995
     7996The storage-management routines extend their C equivalents by overloading, alternate names, providing shallow type-safety, and removing the need to specify the allocation size for non-array types.
     7997
     7998C storage management provides the following capabilities:
     7999\begin{description}
     8000\item[filled]
     8001after allocation with a specified character or value.
     8002\item[resize]
     8003an existing allocation to decreased or increased its size.
     8004In either case, new storage may or may not be allocated and, if there is a new allocation, as much data from the existing allocation is copied into the new allocation.
     8005For an increase in storage size, new storage after the copied data may be filled.
    81648006\item[align]
    81658007an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
    8166 \item[scale]
    8167 an allocation size to the specified number of array elements.
     8008\item[array]
     8009the allocation size is scaled to the specified number of array elements.
    81688010An array may be filled, resized, or aligned.
    8169 \item[resize]
    8170 an existing allocation to decreased or increased its size.
    8171 In either direction, new storage may or may not be allocated, but if there is a new allocation, as much data from the existing allocation is copied into the new allocation.
    8172 When new storage is allocated, it may be aligned and storage after copied data may be filled.
    81738011\end{description}
    8174 \VRef[Table]{t:AllocationVersusProperties} shows different combinations of storage-management properties provided by the C and \CFA allocation routines.
    8175 
     8012\VRef[Table]{t:AllocationVersusCapabilities} shows allocation routines supporting different combinations of storage-management capabilities.
    81768013\begin{table}
    8177 \caption{Allocation Routines versus Storage-Management Properties}
    8178 \label{t:AllocationVersusProperties}
    81798014\centering
    81808015\begin{minipage}{0.75\textwidth}
    81818016\begin{tabular}{@{}r|l|l|l|l|l@{}}
    8182                 & \multicolumn{1}{c|}{routine} & \multicolumn{1}{c|}{\textbf{fill}} & \textbf{alignment}        & \textbf{scale}        & \textbf{resize} \\
     8017\multicolumn{1}{c}{}&           & \multicolumn{1}{c|}{fill}     & resize        & alignment     & array \\
    81838018\hline
    81848019C               & ©malloc©                      & no                    & no            & no            & 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    \\
     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   \\
    81938027                & ©pvalloc©\footnote{Same as ©valloc© but rounds size to multiple of page size.}
    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
     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   \\
    82018036\end{tabular}
    82028037\end{minipage}
    8203 \vspace*{-10pt}
     8038\caption{Allocation Routines versus Storage-Management Capabilities}
     8039\label{t:AllocationVersusCapabilities}
    82048040\end{table}
    82058041
    8206 
    8207 \subsubsection{\CFA Interface}
    8208 
    8209 \CFA dynamic memory management:
    8210 \begin{enumerate}[leftmargin=\parindent]
    8211 \item
    8212 Extend 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}
    8214 int * ip = (int *)malloc( sizeof(int) ); §\C[2.3in]{// C}§
    8215 int * ip = malloc();                                    §\C{// \CFA type-safe call of C malloc}§
    8216 int * ip = alloc();                                             §\C{// \CFA type-safe call of \CFA alloc}§
    8217 struct __attribute__(( aligned(128) )) spinlock { ... };
    8218 spinlock * slp = malloc();                              §\C{// correct size, alignment, and return type}\CRT§
    8219 \end{cfa}
    8220 Here, the alignment of the ©ip© storage is 16 (default) and 128 for ©slp©.
    8221 
    8222 \item
    8223 Introduce the notion of \newterm{sticky properties} used in resizing.
    8224 All initial allocation properties are remembered and maintained for use should resize require new storage.
    8225 For example, the initial alignment and fill properties in the initial allocation
    8226 \begin{cfa}
    8227 struct __attribute__(( aligned(4096) )) S { ... };
    8228 S * sp = calloc( 10 );                                  §\C{// align 4K and zero fill}§
    8229 sp = reallocarray( sp, 100 );                   §\C{// preserve 4K alignment and zero fill new storage}§
    8230 \end{cfa}
    8231 are preserved in the resize so the new storage has the same alignment and extra storage after the data copy is zero filled.
    8232 Without sticky properties it is dangerous to resize, resulting in the C idiom of manually performing the reallocation to maintain correctness, which is error prone.
    8233 
    8234 \item
    8235 Provide 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.
    8236 The resize might be able to take advantage of unused storage after the data to preventing the free/reallocation step altogether.
    8237 
    8238 \item
    8239 Provide ©free©/©delete© functions that delete a variable number of pointers.
    8240 \begin{cfa}
    8241 int * ip = malloc(), * jp = malloc(), * kp = malloc();
    8242 double * xp = malloc(), * yp = malloc(), * zp = malloc();
    8243 free( ®ip, jp, kp, xp, yp, zp® );
    8244 \end{cfa}
    8245 
    8246 \item
    8247 Support constructors for initialization of allocated storage (like \CC) and destructors for deallocation.
    8248 \begin{cfa}
    8249 struct S { int v; };                                    §\C{// default constructors}§
    8250 void ^?{}( S & ) { ... }                                §\C{// destructor}§
    8251 S & sp = *®new®( 3 );                                   §\C{// allocate and call constructor}§
    8252 sout | sp.v;
    8253 ®delete®( &sp );                                                §\C{// call destructor}§
    8254 S * spa1 = ®anew®( 10, 5 ), * spa2 = ®anew®( 10, 8 ); §\C{// allocate array and call constructor for each array element}§
    8255 for ( i; 10 ) sout | spa1[i].v | spa2[i].v | nonl; sout | nl;
    8256 ®adelete®( spa1, spa2 );                                §\C{// call destructors on all array objects}§
    8257 
    8258 3
    8259 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8 5 8
     8042\CFA memory management extends the type safety of all allocations by using the type of the left-hand-side type to determine the allocation size and return a matching type for the new storage.
     8043Type-safe allocation is provided for all C allocation routines and new \CFA allocation routines, \eg in
     8044\begin{cfa}
     8045int * ip = (int *)malloc( sizeof(int) ); §\C{// C}§
     8046int * ip = malloc();                                    §\C{// \CFA type-safe version of C malloc}§
     8047int * ip = alloc();                                             §\C{// \CFA type-safe uniform alloc}§
     8048\end{cfa}
     8049the latter two allocations determine the allocation size from the type of ©p© (©int©) and cast the pointer to the allocated storage to ©int *©.
     8050
     8051\CFA memory management extends allocation safety by implicitly honouring all alignment requirements, \eg in
     8052\begin{cfa}
     8053struct S { int i; } __attribute__(( aligned( 128 ) )); // cache-line alignment
     8054S * sp = malloc();                                              §\C{// honour type alignment}§
     8055\end{cfa}
     8056the storage allocation is implicitly aligned to 128 rather than the default 16.
     8057The alignment check is performed at compile time so there is no runtime cost.
     8058
     8059\CFA memory management extends the resize capability with the notion of \newterm{sticky properties}.
     8060Hence, initial allocation capabilities are remembered and maintained when resize requires copying.
     8061For example, an initial alignment and fill capability are preserved during a resize copy so the copy has the same alignment and extended storage is filled.
     8062Without sticky properties it is dangerous to use ©realloc©, resulting in an idiom of manually performing the reallocation to maintain correctness.
     8063\begin{cfa}
     8064
     8065\end{cfa}
     8066
     8067\CFA memory management extends allocation to support constructors for initialization of allocated storage, \eg in
     8068\begin{cfa}
     8069struct S { int i; };                                    §\C{// cache-line alignment}§
     8070void ?{}( S & s, int i ) { s.i = i; }
     8071// assume ?|? operator for printing an S
     8072
     8073S & sp = *®new®( 3 );                                   §\C{// call constructor after allocation}§
     8074sout | sp.i;
     8075®delete®( &sp );
     8076
     8077S * spa = ®anew®( 10, 5 );                              §\C{// allocate array and initialize each array element}§
     8078for ( i; 10 ) sout | spa[i] | nonl;
     8079sout | nl;
     8080®adelete®( 10, spa );
    82608081\end{cfa}
    82618082Allocation routines ©new©/©anew© allocate a variable/array and initialize storage using the allocated type's constructor.
    82628083Note, the matching deallocation routines ©delete©/©adelete©.
    8263 \end{enumerate}
    8264 
    8265 In addition, \CFA provides a new allocator interface to further increase orthogonality and usability of dynamic-memory allocation.
    8266 This interface helps programmers in three ways.
    8267 \begin{enumerate}
    8268 \item
    8269 naming: \CFA regular and ©ttype© polymorphism (similar to \CC variadic templates) is used to encapsulate a wide range of allocation functionality into a single routine name, so programmers do not have to remember multiple routine names for different kinds of dynamic allocations.
    8270 \item
    8271 named arguments: individual allocation properties are specified using postfix function call \see{\VRef{s:PostfixFunction}}, so programmers do not have to remember parameter positions in allocation calls.
    8272 \item
    8273 safe usage: like the \CFA's C-interface, programmers do not have to specify object size or cast allocation results.
    8274 \end{enumerate}
    8275 
    8276 The 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.
    8277 These allocation properties can be passed as named arguments when calling the \lstinline{alloc} routine.
    8278 A call without parameters returns an uninitialized dynamically allocated object of type ©T© (©malloc©).
    8279 A call with only the dimension (dim) parameter returns an uninitialized dynamically allocated array of objects with type ©T© (©aalloc©).
    8280 The variable number of arguments consist of allocation properties, which can be combined to produce different kinds of allocations.
    8281 The properties ©resize© and ©realloc© are associated with the allocation variable indicating how the existing allocation is modified, without or with data copying.
    8282 Function ©alloc© is used extensively in the \CFA runtime.
    8283 
    8284 The 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.
    8288 The alignment parameter must be $\ge$ the default alignment (©libAlign()© in \CFA) and a power of two, \eg:
    8289 \begin{cfa}
    8290 int * i0 = alloc( ®4096`align® );  sout | i0 | nl;
    8291 int * i1 = alloc( 3, ®4096`align® );  sout | i1; for (i; 3 ) sout | &i1[i] | nonl; sout | nl;
    8292 
    8293 0x555555572000
    8294 0x555555574000 0x555555574000 0x555555574004 0x555555574008
    8295 \end{cfa}
    8296 returns 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.
    8300 There are three ways to fill storage:
    8301 \begin{enumerate}
    8302 \item
    8303 A ©char© fills every byte of each object.
    8304 \item
    8305 An object of the returned type fills each object.
    8306 \item
    8307 An object array pointer fills some or all of the corresponding object array.
    8308 \end{enumerate}
    8309 For example:
    8310 \begin{cfa}[numbers=left]
    8311 int * i0 = alloc( ®0n`fill® );  sout | *i0 | nl;  // 0n disambiguates 0
    8312 int * i1 = alloc( ®5`fill® );  sout | *i1 | nl;
    8313 int * i2 = alloc( ®'\xfe'`fill® ); sout | hex( *i2 ) | nl;
    8314 int * i3 = alloc( 5, ®5`fill® );  for ( i; 5 ) sout | i3[i] | nonl; sout | nl;
    8315 int * i4 = alloc( 5, ®0xdeadbeefN`fill® );  for ( i; 5 ) sout | hex( i4[i] ) | nonl; sout | nl;
    8316 int * i5 = alloc( 5, ®i3`fill® );  for ( i; 5 ) sout | i5[i] | nonl; sout | nl; // completely fill from i3
    8317 int * 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]
    8320 0
    8321 5
    8322 0xfefefefe
    8323 5 5 5 5 5
    8324 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef 0xdeadbeef
    8325 5 5 5 5 5
    8326 5 5 5 -555819298 -555819298  // two undefined values
    8327 \end{lstlisting}
    8328 Examples 1 to 3 fill an object with a value or characters.
    8329 Examples 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.
    8333 The old object type may be different from the new object type, since the values are not used.
    8334 For example:
    8335 \begin{cfa}[numbers=left]
    8336 int * i = alloc( ®5`fill® );  sout | i | *i;
    8337 i = alloc( ®i`resize®, ®256`align®, ®7`fill® );  sout | i | *i;
    8338 double * d = alloc( ®i`resize®, ®4096`align®, ®13.5`fill® );  sout | d | *d;
    8339 \end{cfa}
    8340 \begin{lstlisting}[numbers=left]
    8341 0x55555556d5c0 5
    8342 0x555555570000 7
    8343 0x555555571000 13.5
    8344 \end{lstlisting}
    8345 Examples 2 to 3 change the alignment, fill, and size for the initial storage of ©i©.
    8346 
    8347 \begin{cfa}[numbers=left]
    8348 int * ia = alloc( 5, ®5`fill® );  for ( i; 5 ) sout | ia[i] | nonl; sout | nl;
    8349 ia = alloc( 10, ®ia`resize®, ®7`fill® ); for ( i; 10 ) sout | ia[i] | nonl; sout | nl;
    8350 sout | ia; ia = alloc( 5, ®ia`resize®, ®512`align®, ®13`fill® ); sout | ia; for ( i; 5 ) sout | ia[i] | nonl; sout | nl;;
    8351 ia = 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]
    8354 5 5 5 5 5
    8355 7 7 7 7 7 7 7 7 7 7
    8356 0x55555556d560 0x555555571a00 13 13 13 13 13
    8357 0x555555572000 0x555555572000 2 0x555555572004 2 0x555555572008 2
    8358 \end{lstlisting}
    8359 Examples 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 ))©
    8363 used to resize, realign, and fill, where the old object data is copied to the new object.
    8364 The old object type must be the same as the new object type, since the value is used.
    8365 Note, for ©fill©, only the extra space after copying the data from the old object is filled with the given parameter.
    8366 For example:
    8367 \begin{cfa}[numbers=left]
    8368 int * i = alloc( ®5`fill® );  sout | i | *i;
    8369 i = alloc( ®i`realloc®, ®256`align® );  sout | i | *i;
    8370 i = alloc( ®i`realloc®, ®4096`align®, ®13`fill® );  sout | i | *i;
    8371 \end{cfa}
    8372 \begin{lstlisting}[numbers=left]
    8373 0x55555556d5c0 5
    8374 0x555555570000 5
    8375 0x555555571000 5
    8376 \end{lstlisting}
    8377 Examples 2 to 3 change the alignment for the initial storage of ©i©.
    8378 The ©13`fill© in example 3 does nothing because no extra space is added.
    8379 
    8380 \begin{cfa}[numbers=left]
    8381 int * ia = alloc( 5, ®5`fill® );  for ( i; 5 ) sout | ia[i]; sout | nl;
    8382 ia = alloc( 10, ®ia`realloc®, ®7`fill® ); for ( i; 10 ) sout | ia[i]; sout | nl;
    8383 sout | ia; ia = alloc( 1, ®ia`realloc®, ®512`align®, ®13`fill® ); sout | ia; for ( i; 1 ) sout | ia[i]; sout | nl;;
    8384 ia = 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]
    8387 5 5 5 5 5
    8388 5 5 5 5 5 7 7 7 7 7
    8389 0x55555556c560 0x555555570a00 5
    8390 0x555555571000 0x555555571000 5 0x555555571004 2 0x555555571008 2
    8391 \end{lstlisting}
    8392 Examples 2 to 4 change the array size, alignment and fill for the initial storage of ©ia©.
    8393 The ©13`fill© in example 3 does nothing because no extra space is added.
    8394 \end{itemize}
    8395 
    8396 \medskip
     8084
     8085\leavevmode
    83978086\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    83988087extern "C" {
    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.
    8415 void * resize( void * oaddr, size_t alignment, size_t size );
    8416 void * realloc( void * oaddr, size_t alignment, size_t size );
    8417 void * reallocarray( void * oaddr, size_t nalign, size_t dim, size_t elemSize );
    8418 
    8419 forall( 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}§
     8088        // C unsafe allocation
     8089        void * malloc( size_t size );§\indexc{malloc}§
     8090        void * calloc( size_t dim, size_t size );§\indexc{calloc}§
     8091        void * realloc( void * ptr, size_t size );§\indexc{realloc}§
     8092        void * memalign( size_t align, size_t size );§\indexc{memalign}§
     8093        void * aligned_alloc( size_t align, size_t size );§\indexc{aligned_alloc}§
     8094        int posix_memalign( void ** ptr, size_t align, size_t size );§\indexc{posix_memalign}§
     8095        void * cmemalign( size_t alignment, size_t noOfElems, size_t elemSize );§\indexc{cmemalign}§ // CFA
     8096
     8097        // C unsafe initialization/copy
     8098        void * memset( void * dest, int c, size_t size );§\indexc{memset}§
     8099        void * memcpy( void * dest, const void * src, size_t size );§\indexc{memcpy}§
     8100}
     8101
     8102void * realloc( void * oaddr, size_t nalign, size_t size ); // CFA heap
     8103
     8104forall( dtype T | sized(T) ) {
     8105        // §\CFA§ safe equivalents, i.e., implicit size specification
     8106        T * malloc( void );
     8107        T * calloc( size_t dim );
     8108        T * realloc( T * ptr, size_t size );
     8109        T * memalign( size_t align );
     8110        T * cmemalign( size_t align, size_t dim  );
     8111        T * aligned_alloc( size_t align );
     8112        int posix_memalign( T ** ptr, size_t align );
    84348113
    84358114        // §\CFA§ safe general allocation, fill, resize, alignment, array
    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}§
     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}§
    84428137
    84438138        // §\CFA§ safe initialization/copy, i.e., implicit size specification
     
    84518146
    84528147// §\CFA§ allocation/deallocation and constructor/destructor, non-array types
    8453 forall( T &, TT ... ) void free( T * ptr, ... );
    8454 
    8455 forall( T & | sized(T), Params ... | { void ?{}( T &, Params ); } )
    8456 T * new( Params p );§\indexc{new}§
    8457 forall( T & | { void ^?{}( T & ); } )
    8458 void delete( T * ptr );§\indexc{delete}§
    8459 forall( T &, Params ... | { void ^?{}( T & ); void delete( Params ); } )
    8460 void delete( T * ptr, Params rest );
     8148forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * new( Params p );§\indexc{new}§
     8149forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void delete( T * ptr );§\indexc{delete}§
     8150forall( dtype T, ttype Params | sized(T) | { void ^?{}( T & ); void delete( Params ); } )
     8151  void delete( T * ptr, Params rest );
    84618152
    84628153// §\CFA§ allocation/deallocation and constructor/destructor, array types
    8463 forall( T & | sized(T), Params ... | { void ?{}( T &, Params ); } )
    8464 T * anew( size_t dim, Params p );§\indexc{anew}§
    8465 forall( T & | sized(T) | { void ^?{}( T & ); } )
    8466 void adelete( T arr[] );§\indexc{adelete}§
    8467 forall( T & | sized(T) | { void ^?{}( T & ); }, Params ... | { void adelete( Params ); } )
    8468 void adelete( T arr[], Params rest );
     8154forall( dtype T | sized(T), ttype Params | { void ?{}( T &, Params ); } ) T * anew( size_t dim, Params p );§\indexc{anew}§
     8155forall( dtype T | sized(T) | { void ^?{}( T & ); } ) void adelete( size_t dim, T arr[] );§\indexc{adelete}§
     8156forall( dtype T | sized(T) | { void ^?{}( T & ); }, ttype Params | { void adelete( Params ); } )
     8157  void adelete( size_t dim, T arr[], Params rest );
    84698158\end{cfa}
    84708159
     
    96019290Int sqrt( Int oper );
    96029291
    9603 forall( istype & | istream( istype ) ) istype * ?|?( istype * is, Int * mp );  §\C{// I/O}§
    9604 forall( ostype & | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
     9292forall( dtype istype | istream( istype ) ) istype * ?|?( istype * is, Int * mp );  §\C{// I/O}§
     9293forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
    96059294\end{cfa}
    96069295\VRef[Figure]{f:MultiPrecisionFactorials} shows \CFA and C factorial programs using the GMP interfaces.
     
    96109299\begin{cquote}
    96119300\begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}}
    9612 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{C}}   \\
     9301\multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{C}}    & \multicolumn{1}{@{\hspace{\parindentlnth}}c@{}}{\textbf{\CFA}}        \\
    96139302\hline
    9614 \begin{cfa}
    9615 #include <gmp.hfa>§\indexc{gmp}§
    9616 int 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 &
    96289303\begin{cfa}
    96299304#include <gmp.h>§\indexc{gmp.h}§
     
    96369311                ®mpz_mul_ui®( fact, fact, i );
    96379312                ®gmp_printf®( "%d %Zd\n", i, fact );
     9313        }
     9314}
     9315\end{cfa}
     9316&
     9317\begin{cfa}
     9318#include <gmp.hfa>§\indexc{gmp}§
     9319int main( void ) {
     9320        sout | "Factorial Numbers";
     9321        Int fact = 1;
     9322
     9323        sout | 0 | fact;
     9324        for ( i; 40 ) {
     9325                fact *= i;
     9326                sout | i | fact;
    96389327        }
    96399328}
     
    97309419Rational narrow( double f, long int md );
    97319420
    9732 forall( istype & | istream( istype ) ) istype * ?|?( istype *, Rational * ); // I/O
    9733 forall( ostype & | ostream( ostype ) ) ostype * ?|?( ostype *, Rational );
     9421forall( dtype istype | istream( istype ) ) istype * ?|?( istype *, Rational * ); // I/O
     9422forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype *, Rational );
    97349423\end{cfa}
    97359424
     
    97519440\end{document}
    97529441
    9753 From: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>
    9754 To: 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>
    9759 Subject: The White House on Memory-Safe programming
    9760 Date: Mon, 4 Mar 2024 16:49:53 +0000
    9761 
    9762 I heard tell of this announcement last night.  Haven't read the actual report yet.
    9763 
    9764 Most mainstream article I can find:  https://me.pcmag.com/en/security/22413/white-house-to-developers-using-c-or-c-invites-cybersecurity-risks
    9765 Less fluffy summary:  https://www.developer-tech.com/news/2024/feb/27/white-house-urges-adoption-memory-safe-programming-languages/
    9766 Horse'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 
    9769 A contrary analysis:  https://hackaday.com/2024/02/29/the-white-house-memory-safety-appeal-is-a-security-red-herring/
    9770 
    97719442% Local Variables: %
    97729443% tab-width: 4 %
  • libcfa/src/concurrency/actor.hfa

    r15215f02 r0fe07be  
    299299
    300300        if ( seperate_clus ) {
    301                 this.cluster = alloc();
     301                cluster = alloc();
    302302                (*cluster){};
    303303        } else cluster = active_cluster();
     
    360360        adelete( worker_req_queues );
    361361        adelete( processors );
    362         if ( seperate_clus ) delete( this.cluster );
     362        if ( seperate_clus ) delete( cluster );
    363363
    364364        #ifdef ACTOR_STATS // print formatted stats
  • src/AST/Pass.hpp

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

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

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

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

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

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

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

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

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

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

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

    r15215f02 r0fe07be  
    397397                        }
    398398                } else if ( auto type2AsAttr = dynamic_cast< const ast::EnumAttrType * >( type2 ) ) {
    399                         if ( type2AsAttr->attr == ast::EnumAttribute::Posn ) {
    400                                 ast::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::SignedInt ];
    401                                 if (
    402                                         ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
    403                                                 || widen.first )
    404                                         && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
    405                                                 || widen.second )
    406                                 ) {
    407                                         result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
    408                                 }
    409                         }
     399            if ( type2AsAttr->attr == ast::EnumAttribute::Posn ) {
     400                            ast::BasicKind kind = commonTypes[ basic->kind ][ ast::BasicKind::SignedInt ];
     401                            if (
     402                                    ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
     403                                            || widen.first )
     404                                    && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
     405                                            || widen.second )
     406                            ) {
     407                                    result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
     408                            }
     409            }
    410410                }
    411411        }
     
    519519                                                                // xxx - assume LHS is always the target type
    520520
    521                                                                 if ( ! ((widen.second && ref2->qualifiers.is_mutex)
     521                                                                if ( ! ((widen.second && ref2->qualifiers.is_mutex) 
    522522                                                                || (ref1->qualifiers.is_mutex == ref2->qualifiers.is_mutex ))) return;
    523523
  • src/ResolvExpr/ConversionCost.cc

    r15215f02 r0fe07be  
    379379
    380380void ConversionCost::postvisit( const ast::EnumAttrType * src ) {
    381         auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
     381    auto dstAsEnumAttrType = dynamic_cast<const ast::EnumAttrType *>(dst);
    382382        assert( src->attr != ast::EnumAttribute::Label );
    383         if ( src->attr == ast::EnumAttribute::Value ) {
    384                 if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Value) {
    385                         cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
    386                 } else {
    387                         auto baseType = src->instance->base->base;
    388                         cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );
     383    if ( src->attr == ast::EnumAttribute::Value ) {
     384        if ( dstAsEnumAttrType && dstAsEnumAttrType->attr == ast::EnumAttribute::Value) {
     385            cost = costCalc( src->instance, dstAsEnumAttrType->instance, srcIsLvalue, symtab, env );
     386        } else {
     387            auto baseType = src->instance->base->base;
     388            cost = costCalc( baseType, dst, srcIsLvalue, symtab, env );
    389389                        if ( cost < Cost::infinity ) {
    390390                                cost.incUnsafe();
    391391                        }
    392                 }
    393         } else { // ast::EnumAttribute::Posn
    394                 if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
    395                         cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
    396                         if ( cost < Cost::unsafe ) cost.incSafe();
    397                 } else {
    398                         static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::SignedInt ) };
    399                         cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
    400                         if ( cost < Cost::unsafe ) {
    401                                 cost.incSafe();
    402                         }
    403                 }
    404         }
     392        }
     393    } else { // ast::EnumAttribute::Posn
     394        if ( auto dstBase = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
     395                    cost = costCalc( src->instance, dstBase, srcIsLvalue, symtab, env );
     396                    if ( cost < Cost::unsafe ) cost.incSafe();
     397            } else {
     398                    static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicKind::SignedInt ) };
     399                    cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
     400                    if ( cost < Cost::unsafe ) {
     401                            cost.incSafe();
     402                    }
     403            }
     404    }
    405405}
    406406
  • src/ResolvExpr/PolyCost.cc

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

    r15215f02 r0fe07be  
    307307                                // type unification calls expression unification (mutual recursion)
    308308                                if ( ! unify(array->dimension, array2->dimension,
    309                                         tenv, need, have, open, widen) ) return;
     309                                    tenv, need, have, open, widen) ) return;
    310310                        }
    311311
     
    455455                        // check that the other type is compatible and named the same
    456456                        auto otherInst = dynamic_cast< const XInstType * >( other );
    457                         if (otherInst && inst->name == otherInst->name)
     457                        if (otherInst && inst->name == otherInst->name) 
    458458                                this->result = otherInst;
    459459                        return otherInst;
     
    542542                        // Lazy approach for now
    543543                        if ( auto otherPos = dynamic_cast< const ast::EnumAttrType *>(type2) ) {
    544                                 if ( enumAttr->match(otherPos) ) {
    545                                         result = otherPos;
    546                                 }
    547                         }
     544                            if ( enumAttr->match(otherPos) ) {
     545                                    result = otherPos;
     546                            }
     547            } 
    548548                }
    549549
  • src/SymTab/Mangler.cc

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

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

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

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

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