Changes in / [486caad:df78cce]


Ignore:
Files:
1 deleted
22 edited

Legend:

Unmodified
Added
Removed
  • doc/bibliography/pl.bib

    r486caad rdf78cce  
    12631263    school      = {School of Computer Science, University of Waterloo},
    12641264    year        = 2019,
    1265     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     1265    optaddress  = {Waterloo, Ontario, Canada, N2L 3G1},
    12661266    note        = {\url{https://uwspace.uwaterloo.ca/handle/10012/14584}},
    12671267}
     
    19551955    school      = {School of Computer Sc., University of Waterloo},
    19561956    year        = 2015,
    1957     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     1957    optaddress  = {Waterloo, Ontario, Canada, N2L 3G1},
    19581958    note        = {\url{https://uwspace.uwaterloo.ca/handle/10012/10013}},
    19591959}
     
    41304130    school      = {School of Computer Sc., University of Waterloo},
    41314131    year        = 2019,
    4132     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     4132    optaddress  = {Waterloo, Ontario, Canada, N2L 3G1},
    41334133    note        = {\url{https://uwspace.uwaterloo.ca/handle/10012/14706}},
    41344134}
     
    43234323    school      = {School of Computer Science, University of Waterloo},
    43244324    year        = 2003,
    4325     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     4325    optaddress  = {Waterloo, Ontario, Canada, N2L 3G1},
    43264326    note        = {\url{http://plg.uwaterloo.ca/theses/BilsonThesis.pdf}},
    43274327}
     
    43644364    year        = 2018,
    43654365    month       = sep,
    4366     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     4366    optaddress  = {Waterloo, Ontario, Canada, N2L 3G1},
    43674367    note        = {\url{https://uwspace.uwaterloo.ca/handle/10012/13935}},
    43684368}
     
    59905990    key         = {OCaml},
    59915991    title       = {The {OC}aml system, release 5.1},
    5992     address     = {Rust Project Developers},
     5992    optaddress  = {Rust Project Developers},
    59935993    year        = 2023,
    59945994    note        = {\url{https://v2.ocaml.org/manual/}},
     
    70077007    organization= {United States Department of Defense},
    70087008    edition     = {{ANSI/MIL-STD-1815A-1983}},
    7009     address     = {Springer, New York},
    70107009    month       = feb,
    70117010    year        = 1983,
     7011    note        = {Springer, New York},
    70127012}
    70137013
     
    74217421    school      = {School of Computer Science, University of Waterloo},
    74227422    year        = 2017,
    7423     address     = {Waterloo, Ontario, Canada, N2L 3G1},
     7423    optaddress  = {Waterloo, Ontario, Canada, N2L 3G1},
    74247424    note        = {\url{https://uwspace.uwaterloo.ca/handle/10012/11830}},
    74257425}
     
    75087508    key         = {Rust},
    75097509    title       = {{R}ust Programming Language},
    7510     address     = {Rust Project Developers},
     7510    optaddress  = {Rust Project Developers},
    75117511    year        = 2015,
    75127512    note        = {\url{https://doc.rust-lang.org/reference.html}},
     
    77297729    publisher   = {Morgan \& Claypool},
    77307730    year        = 2013,
     7731}
     7732
     7733@inproceedings{Leissa14,
     7734    title       = {{S}ierra: a {SIMD} extension for {C}++},
     7735    author      = {Lei{\ss}a, Roland and Haffner, Immanuel and Hack, Sebastian},
     7736    booktitle   = {Proceedings of the 2014 Workshop on Workshop on programming models for SIMD/Vector processing},
     7737    pages       = {17-24},
     7738    year        = {2014},
     7739    organization= {ACM}
     7740}
     7741
     7742@article{Nickolls08,
     7743    author      = {Nickolls, John and Buck, Ian and Garland, Michael and Skadron, Kevin},
     7744    title       = {Scalable Parallel Programming with CUDA},
     7745    journal     = {Queue},
     7746    volume      = {6},
     7747    number      = {2},
     7748    month       = mar,
     7749    year        = 2008,
     7750    pages       = {40-53},
     7751    publisher   = {ACM},
     7752    address     = {New York, NY, USA},
    77317753}
    77327754
  • doc/theses/jiada_liang_MMath/CFAenum.tex

    r486caad rdf78cce  
    1 \chapter{\CFA Enumeration}
    2 
    3 
    4 \CFA supports C enumeration using the same syntax and semantics for backwards compatibility.
     1\chapter{\CFA-Style Enum}
     2
     3
     4\CFA supports C-Style enumeration using the same syntax and semantics for backwards compatibility.
    55\CFA also extends C-Style enumeration by adding a number of new features that bring enumerations inline with other modern programming languages.
    66
     
    1616Finally, qualification is provided to disambiguate any ambiguous situations.
    1717\begin{cfa}
    18 enum E1 { First, Second, Third, Fourth };
    19 enum E2 { @Fourth@, @Third@, @Second@, @First@ };
    20 E1 p() { return Third; }                                $\C{// correctly resolved duplicate names}$
    21 E2 p() { return Fourth; }
     18enum C1 { First, Second, Third, Fourth };
     19enum C2 { @Fourth@, @Third@, @Second@, @First@ };
     20C1 p() { return Third; }                                $\C{// correctly resolved duplicate names}$
     21C2 p() { return Fourth; }
    2222void foo() {
    23         E1 e1 = First;   E2 e2 = First;
     23        C1 e1 = First;   C2 e2 = First;
    2424        e1 = Second;   e2 = Second;
    2525        e1 = p();   e2 = p();                           $\C{// correctly resolved function call}$
    26         int i = @E1.@First + @E2.@First;        $\C{// disambiguate with qualification}$
    27         int j = @(E1)@First + @(E2)@First;      $\C{// disambiguate with cast}$
    28 }
    29 \end{cfa}
    30 \CFA overloading allows programmers to use the most meaningful names without fear of name clashes from include files.
    31 Either the type system implicitly disambiguates or the programmer explicitly disambiguates using qualification or casting.
     26        int i = @C1.@First + @C2.@First;        $\C{// ambiguous without qualification}$
     27}
     28\end{cfa}
     29\CFA overloading allows programmers to use the most meaningful names without fear of unresolvable clashes from included files, which are correctable with qualification.
    3230
    3331
     
    3634An enumeration can be scoped, so the enumerator constants are not projected into the enclosing scope, using @'!'@.
    3735\begin{cfa}
    38 enum Weekday @!@ { Mon, Tue, Wed, Thu = 10, Fri, Sat, Sun };
    39 enum RGB @!@ { Red, Green, Blue };
     36enum Weekday @!@ { /* as above */ };
     37enum( char * ) Names @!@ { /* as above */ };
    4038\end{cfa}
    4139Now the enumerators \emph{must} be qualified with the associated enumeration.
    4240\begin{cfa}
    43 Weekday weekday = @Weekday@.Mon;
    44 weekday = @Weekday@.Sat;
    45 RGB rgb = RGB.Red;
    46 rgb = RGB.Blue;
     41Weekday weekday = @Weekday@.Monday;
     42Names names = @Names.@Fred;
     43names = @Names.@Jane;
    4744\end{cfa}
    4845It is possible to toggle back to unscoping using the \CFA @with@ clause/statement (see also \CC \lstinline[language=c++]{using enum} in Section~\ref{s:C++RelatedWork}).
    4946\begin{cfa}
    50 with ( @Weekday@, @RGB@ ) {                     $\C{// type names}$
    51          weekday = @Sun@;                               $\C{// no qualification}$
    52          rgb = @Green@;
    53 }
    54 \end{cfa}
    55 As in Section~\ref{s:EnumeratorNameResolution}, opening multiple unscoped enumerations can result in duplicate enumeration names, but \CFA implicit type resolution and explicit qualification/casting handles name resolution.
     47Weekday weekday;
     48with ( @Weekday@, @Names@ ) {                   $\C{// type names}$
     49         Names names = @Fred@;
     50         names = @Jane@;
     51         weekday = Saturday;
     52}
     53\end{cfa}
     54As in Section~\ref{s:EnumeratorNameResolution}, opening multiple unscoped enumerations can result in duplicate enumeration names, but \CFA type resolution and falling back to explicit qualification handles name resolution.
    5655
    5756\section{Enumerator Typing}
     
    8180\begin{cfa}
    8281// integral
    83         enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' };
     82        enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$' };
    8483        enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 };
    8584        enum( @long long int@ ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 };
     
    8887        enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i };
    8988// pointer
    90         enum( @const char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
     89        enum( @char *@ ) Names { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
    9190        int i, j, k;
    9291        enum( @int *@ ) ptr { I = &i,  J = &j,  K = &k };
     
    9998// aggregate
    10099        struct Person { char * name; int age, height; };
    101 @***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz,
    102                                                                                         Jon = { "JONATHAN", 35, 190 } };
     100@***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz, Jon = { "JONATHAN", 35, 190 } };
    103101\end{cfa}
    104102\caption{Enumerator Typing}
     
    142140\begin{cfa}
    143141enum() Mode { O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC, O_APPEND };
    144 Mode iomode = O_RDONLY;
    145 bool b = iomode == O_RDONLY || iomode < O_APPEND; $\C{// ordering}$
    146 @***@@int i = iomode;@                                                  $\C{// disallow conversion to int}$
     142@***@Mode iomode = O_RDONLY;
     143bool b = iomode == O_RDONLY || iomode < O_APPEND;
     144int i = iomode;                                                 $\C{\color{red}// disallowed}$
    147145\end{cfa}
    148146
     
    151149If follows from enumerator typing that the enumerator type can be another enumerator.
    152150\begin{cfa}
    153 enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' };
    154 enum( Currency ) Europe { Euro = Currency.Euro, Pound = Currency.Pound };
     151enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$' };
     152enum( @Currency@ ) Europe { Euro = Currency.Euro, Pound = Currency.Pound }; // intersection
    155153enum( char ) Letter { A = 'A',  B = 'B', C = 'C', ..., Z = 'Z' };
    156154enum( @Letter@ ) Greek { Alph = A, Beta = B, ..., Zeta = Z }; // intersection
     
    160158\begin{cfa}
    161159Letter letter = A;
    162 Greak greek = Beta;
    163 letter = Beta;                                                  $\C{// allowed, greek == B}$
    164 @greek = A;@                                                    $\C{// disallowed}$
     160@***@Greak greek = Beta;
     161letter = Beta;                                                  $\C{// allowed, letter == B}$
     162greek = A;                                                              $\C{\color{red}// disallowed}$
    165163\end{cfa}
    166164
     
    279277p(variable_d); // 3
    280278\end{cfa}
    281 
    282 
    283 \section{Planet Example}
    284 
    285 \VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating all of the \CFA enumeration features.
    286 Enumeration @Planet@ is a typed enumeration of type @MR@.
    287 Each of the planet enumerators is initialized to a specific mass/radius, @MR@, value.
    288 The unnamed enumeration projects the gravitational-constant enumerator @G@.
    289 The program main iterates through the planets computing the weight on each planet for a given earth weight.
    290 
    291 \begin{figure}
    292 \begin{cfa}
    293 struct MR { double mass, radius; };
    294 enum( MR ) Planet {
    295         //                           mass          radius
    296         MERCURY = { 3.303_E23, 2.4397_E6 },
    297         VENUS       = { 4.869_E24, 6.0518_E6 },
    298         EARTH       = { 5.976_E24, 6.3781_E6 },
    299         MARS         = { 6.421_E23, 3.3972_E6 },
    300         JUPITER    = { 1.898_E27, 7.1492_E7 },
    301         SATURN     = { 5.688_E26, 6.0268_E7 },
    302         URANUS    = { 8.686_E25, 2.5559_E7 },
    303         NEPTUNE  = { 1.024_E26, 2.4746_E7 },
    304 };
    305 enum( double ) { G = 6.6743E-11 }; // universal gravitational constant (m3 kg-1 s-2)
    306 
    307 static double surfaceGravity( Planet p ) with( p ) {
    308         return G * mass / ( radius * radius );
    309 }
    310 static double surfaceWeight( Planet p, double otherMass ) {
    311         return otherMass * surfaceGravity( p );
    312 }
    313 int main( int argc, char * argv[] ) {
    314         if ( argc != 2 ) exit | "Usage: " | argv[0] | "earth-weight";
    315         double earthWeight = convert( argv[1] );
    316         double mass = earthWeight / surfaceGravity( EARTH );
    317         for ( p; Planet ) {
    318                 sout | "Your weight on" | labelE(p) | "is" | surfaceWeight( p, mass );
    319         }
    320 }
    321 \end{cfa}
    322 \caption{Planet Example}
    323 \label{f:PlanetExample}
    324 \end{figure}
  • doc/theses/jiada_liang_MMath/background.tex

    r486caad rdf78cce  
    11\chapter{Background}
    2 \lstnewenvironment{clang}[1][]{\lstset{language=[ANSI]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    3 
    4 \CFA is a backwards-compatible extension of the C programming language.
    5 Therefore, it must support C-style enumerations and any enumeration extensions must be intuitive to C programmers both in syntax and semantics.
    6 
    7 It is common for C programmers to ``believe'' there are three equivalent forms of named constants.
    8 \begin{clang}
    9 #define Mon 0
    10 static const int Mon = 0;
    11 enum { Mon };
    12 \end{clang}
    13 \begin{enumerate}[leftmargin=*]
    14 \item
    15 For @#define@, the programmer has to explicitly manage the constant name and value.
    16 Furthermore, these C preprocessor macro names are outside of the C type-system, and hence cannot be overloaded, and can incorrectly change random text in a program.
    17 \item
    18 The same explicit management is true for the @const@ declaration, and the @const@ variable cannot appear in constant-expression locations, like @case@ labels, array dimensions,\footnote{
    19 C allows variable-length array-declarations (VLA), so this case does work, but it fails in \CC, which does not support VLAs, unless it is \lstinline{g++}.} immediate operands of assembler instructions, and occupy storage.
    20 \begin{clang}
    21 $\$$ nm test.o
    22 0000000000000018 r Mon
    23 \end{clang}
    24 \item
    25 Only the @enum@ form is managed by the compiler, is part of the language type-system, and works in all C constant-expression locations.
    26 \end{enumerate}
    272
    283
    29 \section{C \lstinline{const}}
     4\section{C-Style Enum}
    305
    31 As noted, C has the equivalent of Pascal typed @const@ declarations \see{\VRef{s:Pascal}}, with static and dynamic initialization.
    32 \begin{clang}
    33 static const int one = 0 + 1;                   $\C{// static intialization}$
    34 static const void * NIL = NULL;
    35 static const double PI = 3.14159;
    36 static const char Plus = '+';
    37 static const char * Fred = "Fred";
    38 static const int Mon = 0, Tue = Mon + 1, Wed = Tue + 1, Thu = Wed + 1, Fri = Thu + 1,
    39                                         Sat = Fri + 1, Sun = Sat + 1;
    40 void foo() {
    41         const int r = random();                         $\C{// dynamic intialization}$
    42         int sa[Sun];                                            $\C{// VLA, local scope only}$
    43 }
    44 \end{clang}
    45 Statically initialized identifiers may appear in any constant-expression context, \eg @case@.
    46 Dynamically initialized identifiers may appear as array dimensions in @g++@, which allows variable-sized arrays.
    47 
    48 
    49 \section{C Enumeration}
    50 
    51 The C enumeration has the following syntax and semantics.
    52 \begin{clang}
    53 enum Weekday { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun, };
    54 \end{clang}
     6The C-Style enumeration has the following syntax and semantics.
     7\begin{cfa}
     8enum Weekday { Monday, Tuesday, Wednesday, Thursday@ = 10@, Friday, Saturday, Sunday };
     9\end{cfa}
    5510Enumerators without an explicitly designated constant value are \Newterm{auto-initialized} by the compiler: from left to right, starting at zero or the next explicitly initialized constant, incrementing by @1@.
    56 For example, @Mon@ to @Wed@ are implicitly assigned with constants @0@--@2@, @Thu@ is explicitly set to constant @10@, and @Fri@ to @Sun@ are implicitly assigned with constants @11@--@13@.
     11For example, @Monday@ to @Wednesday@ are implicitly assigned with constants @0@--@2@, @Thursday@ is explicitly set to constant @10@, and @Friday@ to @Sunday@ are implicitly assigned with constants @11@--@13@.
    5712Initialization may occur in any order.
    58 \begin{clang}
    59 enum Weekday { Thu@ = 10@, Fri, Sat, Sun, Mon@ = 0@, Tue, Wed };
    60 \end{clang}
     13\begin{cfa}
     14enum Weekday { Thursday@ = 10@, Friday, Saturday, Sunday, Monday@ = 0@, Tuesday, Wednesday };
     15\end{cfa}
    6116Note, the comma in the enumerator list can be a terminator or a separator, allowing the list to end with a dangling comma.
    62 \begin{clang}
     17\begin{cfa}
    6318enum Weekday {
    64         Thu = 10, Fri, Sat, Sun,
    65         Mon = 0, Tue, Wed@,@ // terminating comma
     19        Thursday = 10, Friday, Saturday, Sunday,
     20        Monday = 0, Tuesday, Wednesday@,@ // terminating comma
    6621};
    67 \end{clang}
     22\end{cfa}
    6823This feature allow enumerator lines to be interchanged without moving a comma.\footnote{
    6924A terminating comma appears in other C syntax, \eg the initializer list.}
     
    7328In practice, since integral constants are used, which have type @int@ (unless qualified with a size suffix), C uses @int@ as the underlying type for enumeration variables.
    7429Finally, there is an implicit bidirectional conversion between an enumeration and its integral type.
    75 \begin{clang}
     30\begin{cfa}
    7631{
    7732        enum Weekday { /* as above */ };        $\C{// enumerators implicitly projected into local scope}$
    78         Weekday weekday = Mon                        $\C{// weekday == 0}$
    79         weekday = Fri                                        $\C{// weekday == 11}$
    80         int i = Sun;                                            $\C{// implicit conversion to int, i == 13}$
     33        Weekday weekday = Monday;                       $\C{// weekday == 0}$
     34        weekday = Friday;                                       $\C{// weekday == 11}$
     35        int i = Sunday;                                         $\C{// implicit conversion to int, i == 13}$
    8136        weekday = 10000;                                        $\C{// UNDEFINED! implicit conversion to Weekday}$
    8237}
    83 int j = Wed;                                                    $\C{// ERROR! Wed is not declared in this scope}$
    84 \end{clang}
     38int j = Wednesday;                                              $\C{// ERROR! Wednesday is not declared in this scope}$
     39\end{cfa}
    8540The implicit conversion from @int@ to an enumeration type is an unnecessary source of error.
     41
     42It is common for C programmers to ``believe'' there are 3 equivalent forms of constant enumeration.
     43\begin{cfa}
     44#define Monday 0
     45static const int Monday = 0;
     46enum { Monday };
     47\end{cfa}
     48For @#define@, the programmer has to play compiler and explicitly manage the enumeration values;
     49furthermore, these are independent constants outside of any language type mechanism.
     50The same explicit management is true for @const@ declarations, and the @const@ variable cannot appear in constant-expression locations, like @case@ labels, array dimensions,\footnote{
     51C allows variable-length array-declarations (VLA), so this case does work, but it fails in \CC, which does not support VLAs, unless it is \lstinline{g++}.} and immediate operands of assembler instructions.
     52Only the @enum@ form is managed by the compiler, is part of the language type-system, and works in all C constant-expression locations.
  • doc/theses/jiada_liang_MMath/implementation.tex

    r486caad rdf78cce  
    548548\begin{cfa}
    549549enum(int) Weekday {
    550         Mon = 10, Tue, ...
     550        Monday=10, Tuesday, ...
    551551};
    552552
  • doc/theses/jiada_liang_MMath/intro.tex

    r486caad rdf78cce  
    11\chapter{Introduction}
    22
    3 All types in a programming language must have a set of constants, and these constants have \Newterm{primary names}, \eg integral types have constants @-1@, @17@, @12345@, \etc.
    4 Constants can be overloaded among types, \eg @0@ is a null pointer for all pointer types, and the value zero for integral and floating-point types.
    5 Hence, each primary constant has a symbolic name referring to its internal representation, and these names are dictated by language syntax related to types.
    6 In theory, there are an infinite set of primary names per type.
     3Naming values is a common practice in mathematics and engineering, \eg $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MHz (1E6), etc.
     4Naming is also commonly used to represent many other numerical phenomenon, such as days of the week, months of a year, floors of a building (basement), specific times (noon, New Years).
     5Many programming languages capture this important software engineering capability through a mechanism called an \Newterm{enumeration}.
     6An enumeration is similar to other programming-language types by providing a set of constrained values, but adds the ability to name \emph{all} the values in its set.
     7Note, all enumeration names must be unique but different names can represent the same value (eight note, quaver), which are synonyms.
    78
    8 \Newterm{Secondary naming} is a common practice in mathematics and engineering, \eg $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MHz (1E6), and in general situations, \eg specific times (noon, New Years), cities (Big Apple), flowers (Lily), \etc.
    9 Many programming languages capture this important software-engineering capability through a mechanism called \Newterm{constant} or \Newterm{literal} naming, where a secondary name is aliased to a primary name.
    10 In some cases, secondary naming is \Newterm{pure}, where the matching internal representation can be chosen arbitrarily, and only equality operations are available, \eg @O_RDONLY@, @O_WRONLY@, @O_CREAT@, @O_TRUNC@, @O_APPEND@.
    11 (The names the thing.)
    12 Because 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{
    13 The term rvalue defines an expression that can only appear on the right-hand side of an assignment expression.}.
     9Specifically, an enumerated type restricts its values to a fixed set of named constants.
     10While all types are restricted to a fixed set of values because of the underlying von Neumann architecture, and hence, to a corresponding set of constants, \eg @3@, @3.5@, @3.5+2.1i@, @'c'@, @"abc"@, etc., these values are not named, other than the programming-language supplied constant names.
    1411
    15 Secondary names can form an (ordered) set, \eg days of the week, months of a year, floors of a building (basement, ground, 1st), colours in a rainbow, \etc.
    16 Many programming languages capture these groupings through a mechanism called an \Newterm{enumeration}.
    17 \begin{quote}
    18 enumerate (verb, transitive).
    19 To count, ascertain the number of;
    20 \emph{more
    21 usually, to mention (a number of things or persons) separately, as if for the
    22 purpose of counting};
    23 to specify as in a list or catalogue.~\cite{OED}
    24 \end{quote}
    25 Within an enumeration set, the enumeration names must be unique, and instances of an enumerated type are restricted to hold only the secondary names.
    26 It is possible to enumerate among set names without having an ordering among the set elements.
    27 For example, the week, the weekdays, the weekend, and every second day of the week.
    28 \begin{cfa}[morekeywords={in}]
    29 for ( cursor in Mon, Tue, Wed, Thu, Fri, Sat, Sun } ... $\C[3.75in]{// week}$
    30 for ( cursor in Mon, Tue, Wed, Thu, Fri } ...   $\C{// weekday}$
    31 for ( cursor in Thu, Fri } ...                                  $\C{// weekend}$
    32 for ( cursor in Mon, Wed, Fri, Sun } ...                $\C{// every second day of week}\CRT$
    33 \end{cfa}
    34 This independence from internal representation allows multiple names to have the same representation (eight note, quaver), giving synonyms.
    35 A set can have a partial or total ordering, making it possible to compare set elements, \eg Monday is before Friday and Friday is after.
    36 Ordering allows iterating among the enumeration set using relational operators and advancement, \eg
    37 \begin{cfa}
    38 for ( cursor = Monday; cursor @<=@ Friday; cursor = @succ@( cursor ) ) ...
    39 \end{cfa}
    40 Here the internal representations for the secondary names are \emph{generated} rather than listing a subset of names.
    41 
    42 
    43 \section{Terminology}
    44 
    45 The term \Newterm{enumeration} defines the set of secondary names, and the term \Newterm{enumerator} represents an arbitrary secondary name.
    46 As well, an enumerated type has three fundamental properties, \Newterm{label}, \Newterm{order}, and \Newterm{value}.
     12Fundamentally, all enumeration systems have an \Newterm{enumeration} type with an associated set of \Newterm{enumerator} names.
     13An enumeration has three universal attributes, \Newterm{position}, \Newterm{label}, and \Newterm{value}, as shown by this representative enumeration, where position and value can be different.
    4714\begin{cquote}
    48 \sf\setlength{\tabcolsep}{3pt}
    49 \begin{tabular}{rcccccccr}
    50 \it\color{red}enumeration       & \multicolumn{8}{c}{\it\color{red}enumerators} \\
    51 $\downarrow$\hspace*{25pt}      & \multicolumn{8}{c}{$\downarrow$}                              \\
    52 @enum@ Week \{                          & Mon,  & Tue,  & Wed,  & Thu,  & Fri,  & Sat,  & Sun = 42      & \};   \\
    53 \it\color{red}label                     & Mon   & Tue   & Wed   & Thu   & Fri   & Sat   & Sun           &               \\
    54 \it\color{red}order                     & 0             & 1             & 2             & 3             & 4             & 5             & 6                     &               \\
    55 \it\color{red}value                     & 0             & 1             & 2             & 3             & 4             & 5             & 42            &
     15\small\sf\setlength{\tabcolsep}{3pt}
     16\begin{tabular}{rccccccccccc}
     17\it\color{red}enumeration & \multicolumn{7}{c}{\it\color{red}enumerators}       \\
     18$\downarrow$\hspace*{25pt} & \multicolumn{7}{c}{$\downarrow$}                           \\
     19@enum@ Weekday \{                               & Monday,       & Tuesday,      & Wednesday,    & Thursday,& Friday,    & Saturday,     & Sunday \}; \\
     20\it\color{red}position                  & 0                     & 1                     & 2                             & 3                             & 4                     & 5                     & 6                     \\
     21\it\color{red}label                             & Monday        & Tuesday       & Wednesday             & Thursday              & Friday        & Saturday      & Sunday        \\
     22\it\color{red}value                             & 0                     & 1                     & 2                             & 3                             & 4                     & 5             & 6
    5623\end{tabular}
    5724\end{cquote}
    58 Here, the enumeration @Week@ defines the enumerator labels @Mon@, @Tue@, @Wed@, @Thu@, @Fri@, @Sat@ and @Sun@.
    59 The implicit ordering implies the successor of @Tue@ is @Mon@ and the predecessor of @Tue@ is @Wed@, independent of any associated enumerator values.
    60 The value is the constant represented by the secondary name, which can be implicitly or explicitly set.
    61 
    62 Specifying complex ordering is possible:
    63 \begin{cfa}
    64 enum E1 { $\color{red}[\(_1\)$ {A, B}, $\color{blue}[\(_2\)$ C $\color{red}]\(_1\)$, {D, E} $\color{blue}]\(_2\)$ }; $\C{// overlapping square brackets}$
    65 enum E2 { {A, {B, C} }, { {D, E}, F };  $\C{// nesting}$
    66 \end{cfa}
    67 For @E1@, there is the partial ordering among @A@, @B@ and @C@, and @C@, @D@ and @E@, but not among @A@, @B@ and @D@, @E@.
    68 For @E2@, there is the total ordering @A@ $<$ @{B, C}@ $<$ @{D, E}@ $<$ @F@.
    69 Only flat total-ordering among enumerators is considered in this work.
    70 
    71 
    72 \section{Motivation}
    73 
    74 Some programming languages only provide secondary renaming, which can be simulated by an enumeration without ordering.
    75 \begin{cfa}
    76 const Size = 20, Pi = 3.14159;
    77 enum { Size = 20, Pi = 3.14159 };   // unnamed enumeration $\(\Rightarrow\)$ no ordering
    78 \end{cfa}
    79 In both cases, it is possible to compare the secondary names, \eg @Size < Pi@, if that is meaningful;
    80 however, without an enumeration type-name, it is impossible to create an iterator cursor.
    81 
    82 Secondary renaming can similate an enumeration, but with extra effort.
    83 \begin{cfa}
    84 const Mon = 1, Tue = 2, Wed = 3, Thu = 4, Fri = 5, Sat = 6, Sun = 7;
    85 \end{cfa}
    86 Furthermore, reordering the enumerators requires manual renumbering.
    87 \begin{cfa}
    88 const Sun = 1, Mon = 2, Tue = 3, Wed = 4, Thu = 5, Fri = 6, Sat = 7;
    89 \end{cfa}
    90 Finally, there is no common type to create a type-checked instance or iterator cursor.
    91 Hence, there is only a weak equivalence between secondary naming and enumerations, justifying the enumeration type in a programming language.
    92 
    93 A variant (algebraic) type is often promoted as a kind of enumeration, \ie a varient type can simulate an enumeration.
    94 A variant type is a tagged-union, where the possible types may be heterogeneous.
    95 \begin{cfa}
    96 @variant@ Variant {
    97         @int tag;@  // optional/implicit: 0 => int, 1 => double, 2 => S
    98         @union {@ // implicit
    99                 case int i;
    100                 case double d;
    101                 case struct S { int i, j; } s;
    102         @};@
    103 };
    104 \end{cfa}
    105 Crucially, the union implies instance storage is shared by all of the variant types.
    106 Hence, a variant is dynamically typed, as in a dynamic-typed programming-language, but the set of types is statically bound, similar to some aspects of dynamic gradual-typing~\cite{Gradual Typing}.
    107 Knowing which type is in a variant instance is crucial for correctness.
    108 Occasionally, it is possible to statically determine all regions where each variant type is used, so a tag and runtime checking is unnecessary;
    109 otherwise, a tag is required to denote the particular type in the variant and the tag checked at runtime using some form of type pattern-matching.
    110 
    111 The tag can be implicitly set by the compiler on assignment, or explicitly set by the program\-mer.
    112 Type pattern-matching is then used to dynamically test the tag and branch to a section of code to safely manipulate the value, \eg:
    113 \begin{cfa}[morekeywords={match}]
    114 Variant v = 3;  // implicitly set tag to 0
    115 @match@( v ) {    // know the type or test the tag
    116         case int { /* only access i field in v */ }
    117         case double { /* only access d field in v */ }
    118         case S { /* only access s field in v */ }
    119 }
    120 \end{cfa}
    121 For safety, either all variant types must be listed or a @default@ case must exist with no field accesses.
    122 
    123 To simulate an enumeration with a variant, the tag is \emph{re-purposed} for either ordering or value and the variant types are omitted.
    124 \begin{cfa}
    125 variant Weekday {
    126         int tag; // implicit 0 => Mon, ..., 6 => Sun
    127         @case Mon;@ // no type
    128         ...
    129         @case Sun;@
    130 };
    131 \end{cfa}
    132 The type system ensures tag setting and testing are correctly done.
    133 However, the enumeration operations are limited to the available tag operations, \eg pattern matching.
    134 \begin{cfa}
    135 Week week = Mon;
    136 if ( @dynamic_cast(Mon)@week ) ... // test tag == Mon
    137 \end{cfa}
    138 While enumerating among tag names is possible:
    139 \begin{cfa}[morekeywords={in}]
    140 for ( cursor in Mon, Wed, Fri, Sun ) ...
    141 \end{cfa}
    142 ordering for iteration would require a \emph{magic} extension, such as a special @enum@ variant, because it has no meaning for a regular variant, \ie @int@ < @double@.
    143 
    144 However, if a special @enum@ variant allows the tags to be heterogeneously typed, ordering must fall back on case positioning, as many types have incomparable values.
    145 Iterating using tag ordering and heterogeneous types, also requires pattern matching.
    146 \begin{cfa}[morekeywords={match}]
    147 for ( cursor = Mon; cursor <= Fri; cursor = succ( cursor) ) {
    148         match( cursor ) {
    149                 case Mon { /* access special type for Mon */ }
    150                 ...
    151                 case Fri { /* access special type for Fri */ }
    152                 default
    153         }
    154 }
    155 \end{cfa}
    156 If the variant type is changed by adding/removing types or the loop range changes, the pattern matching must be adjusted.
    157 As well, if the start/stop values are dynamic, it may be impossible to statically determine if all variant types are listed.
    158 
    159 Re-purposing the notion of enumerating into variant types is ill formed and confusing.
    160 Hence, there is only a weak equivalence between an enumeration and variant type, justifying the enumeration type in a programming language.
    161 
     25Here, the \Newterm{enumeration} @Weekday@ defines the ordered \Newterm{enumerator}s @Monday@, @Tuesday@, @Wednesday@, @Thursday@, @Friday@, @Saturday@ and @Sunday@.
     26By convention, the successor of @Tuesday@ is @Monday@ and the predecessor of @Tuesday@ is @Wednesday@, independent of the associated enumerator constant values.
     27Because an enumerator is a constant, it cannot appear in a mutable context, \eg @Mon = Sun@ is meaningless, and an enumerator has no address, it is an \Newterm{rvalue}\footnote{
     28The term rvalue defines an expression that can only appear on the right-hand side of an assignment.}.
    16229
    16330\section{Contributions}
    164 
    165 The goal of this work is to to extend the simple and unsafe enumeration type in the C programming-language into a sophisticated and safe type in the \CFA programming-language, while maintain backwards compatibility with C.
    166 On the surface, enumerations seem like a simple type.
    167 However, when extended with advanced features, enumerations become complex for both the type system and the runtime implementation.
    168 
    169 \begin{enumerate}
    170 \item
    171 overloading
    172 \item
    173 scoping
    174 \item
    175 typing
    176 \item
    177 subset
    178 \item
    179 inheritance
    180 \end{enumerate}
  • doc/theses/jiada_liang_MMath/relatedwork.tex

    r486caad rdf78cce  
    22\label{s:RelatedWork}
    33
    4 \begin{comment}
    54An algebraic data type (ADT) can be viewed as a recursive sum of product types.
    65A sum type lists values as members.
     
    1615Enumerated types are a special case of product/sum types with non-mutable fields, \ie initialized (constructed) once at the type's declaration, possible restricted to compile-time initialization.
    1716Values of algebraic types are access by subscripting, field qualification, or type (pattern) matching.
    18 \end{comment}
    1917
    2018Enumeration types exist in many popular programming languages, both past and present, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, OCaml~\cite{OCaml} \CC, Go~\cite{Go}, Java~\cite{Java}, Modula-3~\cite{Modula-3}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}.
     
    2220
    2321\section{Pascal}
    24 \label{s:Pascal}
    2522\lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    2623
     
    3027                 PI = 3.14159;   Plus = '+';   Fred = 'Fred';
    3128\end{pascal}
    32 This mechanism is not an enumeration because there is no specific type (pseudo enumeration).
     29Here, there is no enumeration because there is no specific type (pseudo enumeration).
    3330Hence, there is no notion of a (possibly ordered) set, modulo the \lstinline[language=pascal]{set of} type.
    3431The type of each constant name (enumerator) is inferred from the constant-expression type.
     
    8481with Ada.Text_IO; use Ada.Text_IO;
    8582procedure test is
    86         type RGB is ( @Red@, Green, Blue );
    87         type Traffic_Light is ( @Red@, Yellow, Green );         -- overload
    88         procedure @Red@( Colour : RGB ) is begin            -- overload
    89                 Put_Line( "Colour is " & RGB'Image( Colour ) );
    90         end Red;
    91         procedure @Red@( TL : Traffic_Light ) is begin       -- overload
    92                 Put_Line( "Light is " & Traffic_Light'Image( TL ) );
    93         end Red;
     83   type RGB is ( @Red@, Green, Blue );
     84   type Traffic_Light is ( @Red@, Yellow, Green );         -- overload
     85   procedure @Red@( Colour : RGB ) is begin            -- overload
     86       Put_Line( "Colour is " & RGB'Image( Colour ) );
     87   end Red;
     88   procedure @Red@( TL : Traffic_Light ) is begin       -- overload
     89       Put_Line( "Light is " & Traffic_Light'Image( TL ) );
     90   end Red;
    9491begin
    95         @Red@( Blue );                           -- RGB
    96         @Red@( Yellow );                                -- Traffic_Light
    97         @Red@( @RGB'(Red)@ );           -- ambiguous without cast
     92    @Red@( Blue );                               -- RGB
     93    @Red@( Yellow );                            -- Traffic_Light
     94    @Red@( @RGB'(Red)@ );               -- ambiguous without cast
    9895end test;
    9996\end{ada}
     
    227224\lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    228225
    229 \CC has the equivalent of Pascal typed @const@ declarations \see{\VRef{s:Pascal}}, with static and dynamic initialization.
    230 \begin{c++}
    231 const auto one = 0 + 1;                                 $\C{// static intialization}$
    232 const auto NULL = nullptr;
    233 const auto PI = 3.14159;
    234 const auto Plus = '+';
    235 const auto Fred = "Fred";
    236 const auto Mon = 0, Tue = Mon + 1, Wed = Tue + 1, Thu = Wed + 1, Fri = Thu + 1,
    237                                 Sat = Fri + 1, Sun = Sat + 1;
    238 int sa[Sun];
    239 const auto r = random();                                $\C{// dynamic intialization}$
    240 int da[r];                                                              $\C{// VLA}$
    241 \end{c++}
    242 Statically initialized identifiers may appear in any constant-expression context, \eg @case@.
    243 Dynamically intialized identifiers may appear as array dimensions in @g++@, which allows variable-sized arrays.
    244 Interestingly, global \CC @const@ declarations are implicitly marked @static@ (@r@ rather than @R@).
    245 \begin{c++}
    246 $\$$ nm test.o
    247 0000000000000018 @r@ Mon
    248 \end{c++}
    249 
    250 \CC enumeration is largely backwards compatible with C, so it inherited C's enumerations.
    251 However, the following non-backwards compatible changes are made.
     226\CC is largely backwards compatible with C, so it inherited C's enumerations.
     227However, the following non-backwards compatible changes have been made.
    252228
    253229\begin{cquote}
     
    447423\begin{Go}
    448424const ( Mon = iota; Tue; Wed; // 0, 1, 2
    449         @Thu = 10@; Fri; Sat; Sun ) // 10, 10, 10, 10
     425         @Thu = 10@; Fri; Sat; Sun ) // 10, 10, 10, 10
    450426\end{Go}
    451427Auto-incrementing can be restarted with an expression containing \emph{one} \lstinline[language=Go]{iota}.
     
    453429const ( V1 = iota; V2; @V3 = 7;@ V4 = @iota@; V5 ) // 0 1 7 3 4
    454430const ( Mon = iota; Tue; Wed; // 0, 1, 2
    455         @Thu = 10;@ Fri = @iota - Wed + Thu - 1@; Sat; Sun ) // 10, 11, 12, 13
     431         @Thu = 10;@ Fri = @iota - Wed + Thu - 1@; Sat; Sun ) // 10, 11, 12, 13
    456432\end{Go}
    457433Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier.
     
    608584\lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    609585
    610 Rust provides a scoped enumeration based on variant types.
    611 % An enumeration, also referred to as an enum, is a simultaneous definition of a nominal enumerated type as well as a set of constructors, that can be used to create or pattern-match values of the corresponding enumerated type.
    612 An enumeration without constructors is called field-less.
     586Enumerations
    613587\begin{rust}
    614 enum Week { Mon, Tues, Wed, Thu, Fri, Sat, Sun@,@ }
    615 let mut week: Week = Week::Mon;
    616 week = Week::Fri;
     588        Syntax
     589        Enumeration :
     590           enum IDENTIFIER  GenericParams? WhereClause? { EnumItems? }
     591
     592        EnumItems :
     593           EnumItem ( , EnumItem )* ,?
     594
     595        EnumItem :
     596           OuterAttribute* Visibility?
     597           IDENTIFIER ( EnumItemTuple | EnumItemStruct )? EnumItemDiscriminant?
     598
     599        EnumItemTuple :
     600           ( TupleFields? )
     601
     602        EnumItemStruct :
     603           { StructFields? }
     604
     605        EnumItemDiscriminant :
     606           = Expression
    617607\end{rust}
    618 A field-less enumeration with only unit variants is called unit-only.
     608An enumeration, also referred to as an enum, is a simultaneous definition of a nominal enumerated type as well as a set of constructors, that can be used to create or pattern-match values of the corresponding enumerated type.
     609
     610Enumerations are declared with the keyword enum.
     611
     612An example of an enum item and its use:
    619613\begin{rust}
    620 enum Week { Mon = 0, Tues = 1, Wed = 2, Thu = 3, Fri = 4, Sat = 5, Sun = 6 }
     614enum Animal {
     615        Dog,
     616        Cat,
     617}
     618
     619let mut a: Animal = Animal::Dog;
     620a = Animal::Cat;
    621621\end{rust}
    622622Enum constructors can have either named or unnamed fields:
    623623\begin{rust}
    624624enum Animal {
    625         Dog( String, f64 ),
    626         Cat{ name: String, weight: f64 },
    627 }
     625        Dog(String, f64),
     626        Cat { name: String, weight: f64 },
     627}
     628
    628629let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2);
    629630a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
    630631\end{rust}
    631 Here, @Dog@ is an @enum@ variant, whereas @Cat@ is a struct-like variant.
    632 
    633 Each @enum@ type has an implicit integer tag (discriminant), with a unique value for each variant type.
    634 Like a C enumeration, the tag values for the variant types start at 0 with auto incrementing.
    635 The tag is re-purposed for enumeration by allowing it to be explicitly set, and auto incrmenting continues from that value.
    636 \begin{cquote}
    637 \sf\setlength{\tabcolsep}{3pt}
    638 \begin{tabular}{rcccccccr}
    639 @enum@ Week \{  & Mon,  & Tue,  & Wed = 2,      & Thu = 10,     & Fri,  & Sat = 5,      & Sun   & \};   \\
    640 \rm tags                & 0             & 1             & 2                     & 10            & 11    & 5                     & 6             &               \\
    641 \end{tabular}
    642 \end{cquote}
    643 In general, the tag can only be read as an opaque reference for comparison.
     632In this example, Cat is a struct-like enum variant, whereas Dog is simply called an enum variant.
     633
     634An enum where no constructors contain fields are called a field-less enum. For example, this is a fieldless enum:
    644635\begin{rust}
    645 if mem::discriminant(&week) == mem::discriminant(&Week::Mon) ...
     636enum Fieldless {
     637        Tuple(),
     638        Struct{},
     639        Unit,
     640}
    646641\end{rust}
    647 If the enumeration is unit-only, or field-less with no explicit discriminants and where only unit variants are explicit, then the discriminant is accessible with a numeric cast.
     642If a field-less enum only contains unit variants, the enum is called an unit-only enum. For example:
    648643\begin{rust}
    649 if week as isize == Week::Mon as isize ...
     644enum Enum {
     645        Foo = 3,
     646        Bar = 2,
     647        Baz = 1,
     648}
     649\end{rust}
     650
     651\subsection{Discriminants}
     652
     653Each enum instance has a discriminant: an integer logically associated to it that is used to determine which variant it holds.
     654
     655Under the default representation, the discriminant is interpreted as an isize value. However, the compiler is allowed to use a smaller type (or another means of distinguishing variants) in its actual memory layout.
     656
     657\subsection{Assigning discriminant values}
     658
     659\subsection{Explicit discriminants}
     660
     661In two circumstances, the discriminant of a variant may be explicitly set by following the variant name with = and a constant expression:
     662
     663        if the enumeration is "unit-only".
     664
     665        if a primitive representation is used. For example:
     666\begin{rust}
     667        #[repr(u8)]
     668        enum Enum {
     669                Unit = 3,
     670                Tuple(u16),
     671                Struct {
     672                        a: u8,
     673                        b: u16,
     674                } = 1,
     675        }
     676\end{rust}
     677
     678\subsection{Implicit discriminants}
     679
     680If a discriminant for a variant is not specified, then it is set to one higher than the discriminant of the previous variant in the declaration. If the discriminant of the first variant in the declaration is unspecified, then it is set to zero.
     681\begin{rust}
     682enum Foo {
     683        Bar,                    // 0
     684        Baz = 123,        // 123
     685        Quux,              // 124
     686}
     687
     688let baz_discriminant = Foo::Baz as u32;
     689assert_eq!(baz_discriminant, 123);
     690\end{rust}
     691
     692\subsection{Restrictions}
     693
     694It is an error when two variants share the same discriminant.
     695\begin{rust}
     696enum SharedDiscriminantError {
     697        SharedA = 1,
     698        SharedB = 1
     699}
     700
     701enum SharedDiscriminantError2 {
     702        Zero,      // 0
     703        One,            // 1
     704        OneToo = 1  // 1 (collision with previous!)
     705}
     706\end{rust}
     707It is also an error to have an unspecified discriminant where the previous discriminant is the maximum value for the size of the discriminant.
     708\begin{rust}
     709#[repr(u8)]
     710enum OverflowingDiscriminantError {
     711        Max = 255,
     712        MaxPlusOne // Would be 256, but that overflows the enum.
     713}
     714
     715#[repr(u8)]
     716enum OverflowingDiscriminantError2 {
     717        MaxMinusOne = 254, // 254
     718        Max,                       // 255
     719        MaxPlusOne               // Would be 256, but that overflows the enum.
     720}
     721\end{rust}
     722
     723\subsection{Accessing discriminant}
     724
     725\begin{rust}
     726Via mem::discriminant
     727\end{rust}
     728@mem::discriminant@ returns an opaque reference to the discriminant of an enum value which can be compared. This cannot be used to get the value of the discriminant.
     729
     730\subsection{Casting}
     731
     732If an enumeration is unit-only (with no tuple and struct variants), then its discriminant can be directly accessed with a numeric cast; e.g.:
     733\begin{rust}
     734enum Enum {
     735        Foo,
     736        Bar,
     737        Baz,
     738}
     739
     740assert_eq!(0, Enum::Foo as isize);
     741assert_eq!(1, Enum::Bar as isize);
     742assert_eq!(2, Enum::Baz as isize);
     743\end{rust}
     744Field-less enums can be casted if they do not have explicit discriminants, or where only unit variants are explicit.
     745\begin{rust}
     746enum Fieldless {
     747        Tuple(),
     748        Struct{},
     749        Unit,
     750}
     751
     752assert_eq!(0, Fieldless::Tuple() as isize);
     753assert_eq!(1, Fieldless::Struct{} as isize);
     754assert_eq!(2, Fieldless::Unit as isize);
     755\end{rust}
     756\begin{rust}
     757#[repr(u8)]
     758enum FieldlessWithDiscrimants {
     759        First = 10,
     760        Tuple(),
     761        Second = 20,
     762        Struct{},
     763        Unit,
     764}
     765
     766assert_eq!(10, FieldlessWithDiscrimants::First as u8);
     767assert_eq!(11, FieldlessWithDiscrimants::Tuple() as u8);
     768assert_eq!(20, FieldlessWithDiscrimants::Second as u8);
     769assert_eq!(21, FieldlessWithDiscrimants::Struct{} as u8);
     770assert_eq!(22, FieldlessWithDiscrimants::Unit as u8);
     771\end{rust}
     772
     773\subsection{Pointer casting}
     774
     775If the enumeration specifies a primitive representation, then the discriminant may be reliably accessed via unsafe pointer casting:
     776\begin{rust}
     777#[repr(u8)]
     778enum Enum {
     779        Unit,
     780        Tuple(bool),
     781        Struct{a: bool},
     782}
     783
     784impl Enum {
     785        fn discriminant(&self) -> u8 {
     786                unsafe { *(self as *const Self as *const u8) }
     787        }
     788}
     789
     790let unit_like = Enum::Unit;
     791let tuple_like = Enum::Tuple(true);
     792let struct_like = Enum::Struct{a: false};
     793
     794assert_eq!(0, unit_like.discriminant());
     795assert_eq!(1, tuple_like.discriminant());
     796assert_eq!(2, struct_like.discriminant());
     797\end{rust}
     798
     799\subsection{Zero-variant enums}
     800
     801Enums with zero variants are known as zero-variant enums. As they have no valid values, they cannot be instantiated.
     802\begin{rust}
     803enum ZeroVariants {}
     804\end{rust}
     805Zero-variant enums are equivalent to the never type, but they cannot be coerced into other types.
     806\begin{rust}
     807let x: ZeroVariants = panic!();
     808let y: u32 = x; // mismatched type error
     809\end{rust}
     810
     811\subsection{Variant visibility}
     812
     813Enum variants syntactically allow a Visibility annotation, but this is rejected when the enum is validated. This allows items to be parsed with a unified syntax across different contexts where they are used.
     814\begin{rust}
     815macro_rules! mac_variant {
     816        ($vis:vis $name:ident) => {
     817                enum $name {
     818                        $vis Unit,
     819
     820                        $vis Tuple(u8, u16),
     821
     822                        $vis Struct { f: u8 },
     823                }
     824        }
     825}
     826
     827// Empty `vis` is allowed.
     828mac_variant! { E }
     829
     830// This is allowed, since it is removed before being validated.
     831#[cfg(FALSE)]
     832enum E {
     833        pub U,
     834        pub(crate) T(u8),
     835        pub(super) T { f: String }
     836}
    650837\end{rust}
    651838
     
    10131200\lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    10141201
    1015 A Python enumeration is a set of symbolic names bound to \emph{unique} values.
    1016 They are similar to global variables, but offer a more useful @repr()@, grouping, type-safety, and additional features.
    1017 Enumerations inherits from the @Enum@ class, \eg:
    1018 \begin{python}
    1019 class Weekday(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
    1020 class RGB(@Enum@): Red = 1; Green = 2; Blue = 3
    1021 \end{python}
     1202An @Enum@ is a set of symbolic names bound to unique values.
     1203They are similar to global variables, but they offer a more useful @repr()@, grouping, type-safety, and a few other features.
     1204
     1205They are most useful when you have a variable that can take one of a limited selection of values. For example, the days of the week:
     1206\begin{python}
     1207>>> from enum import Enum
     1208>>> class Weekday(Enum):
     1209...    MONDAY = 1
     1210...    TUESDAY = 2
     1211...    WEDNESDAY = 3
     1212...    THURSDAY = 4
     1213...    FRIDAY = 5
     1214...    SATURDAY = 6
     1215...    SUNDAY = 7
     1216\end{python}
     1217Or perhaps the RGB primary colors:
     1218\begin{python}
     1219>>> from enum import Enum
     1220>>> class Color(Enum):
     1221...    RED = 1
     1222...    GREEN = 2
     1223...    BLUE = 3
     1224\end{python}
     1225As you can see, creating an @Enum@ is as simple as writing a class that inherits from @Enum@ itself.
     1226
     1227Note: Case of Enum Members
     1228
     1229Because Enums are used to represent constants, and to help avoid issues with name clashes between mixin-class methods/attributes and enum names, we strongly recommend using @UPPER_CASE@ names for members, and will be using that style in our examples.
    10221230
    10231231Depending 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:
    10241232\begin{python}
    1025 print( repr( Weekday( 3 ) ) )
    1026 <Weekday.Wed: 3>
     1233>>> Weekday(3)
     1234<Weekday.WEDNESDAY: 3>
    10271235\end{python}
    10281236As you can see, the @repr()@ of a member shows the enum name, the member name, and the value.
    10291237The @str()@ of a member shows only the enum name and member name:
    10301238\begin{python}
    1031 print( str( Weekday.Thu ), Weekday.Thu )
    1032 Weekday.Thu Weekday.Thu
     1239print(Weekday.THURSDAY)
     1240Weekday.THURSDAY
    10331241\end{python}
    10341242The type of an enumeration member is the enum it belongs to:
    10351243\begin{python}
    1036 print( type( Weekday.Thu ) )
     1244>>> type(Weekday.MONDAY)
    10371245<enum 'Weekday'>
    1038 print( isinstance(Weekday.Fri, Weekday) )
     1246isinstance(Weekday.FRIDAY, Weekday)
    10391247True
    10401248\end{python}
    10411249Enum members have an attribute that contains just their name:
    10421250\begin{python}
    1043 print(Weekday.TUESDAY.name)
     1251>>> print(Weekday.TUESDAY.name)
    10441252TUESDAY
    10451253\end{python}
    10461254Likewise, they have an attribute for their value:
    10471255\begin{python}
    1048 Weekday.WEDNESDAY.value
     1256>>> Weekday.WEDNESDAY.value
    104912573
    10501258\end{python}
    1051 
    10521259Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added.
    10531260For example, @datetime.date@ has two methods for returning the weekday: @weekday()@ and @isoweekday()@.
     
    10551262Rather 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:
    10561263\begin{python}
    1057 class Weekday(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = 15; Sat = 16; Sun = 17
    10581264$@$classmethod
    10591265def from_date(cls, date):
    1060         return cls(date.isoweekday())
     1266    return cls(date.isoweekday())
     1267\end{python}
     1268The complete Weekday enum now looks like this:
     1269\begin{python}
     1270>>> class Weekday(Enum):
     1271...    MONDAY = 1
     1272...    TUESDAY = 2
     1273...    WEDNESDAY = 3
     1274...    THURSDAY = 4
     1275...    FRIDAY = 5
     1276...    SATURDAY = 6
     1277...    SUNDAY = 7
     1278...    #
     1279...    $@$classmethod
     1280...    def from_date(cls, date):
     1281...        return cls(date.isoweekday())
    10611282\end{python}
    10621283Now we can find out what today is! Observe:
     
    10701291This 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@:
    10711292\begin{python}
    1072 from enum import Flag
    1073 class WeekdayF(@Flag@): Mon = @1@; Tue = @2@; Wed = @4@; Thu = @8@; Fri = @16@; Sat = @32@; Sun = @64@
     1293>>> from enum import Flag
     1294>>> class Weekday(Flag):
     1295...    MONDAY = 1
     1296...    TUESDAY = 2
     1297...    WEDNESDAY = 4
     1298...    THURSDAY = 8
     1299...    FRIDAY = 16
     1300...    SATURDAY = 32
     1301...    SUNDAY = 64
    10741302\end{python}
    10751303We've changed two things: we're inherited from @Flag@, and the values are all powers of 2.
    10761304
    1077 @Flag@ allows combining several members into a single variable:
    1078 \begin{python}
    1079 print( repr(WeekdayF.Sat | WeekdayF.Sun) )
    1080 <WeekdayF.Sun|Sat: 96>
     1305Just like the original @Weekday@ enum above, we can have a single selection:
     1306\begin{python}
     1307>>> first_week_day = Weekday.MONDAY
     1308>>> first_week_day
     1309<Weekday.MONDAY: 1>
     1310\end{python}
     1311But @Flag@ also allows us to combine several members into a single variable:
     1312\begin{python}
     1313>>> weekend = Weekday.SATURDAY | Weekday.SUNDAY
     1314>>> weekend
     1315<Weekday.SATURDAY|SUNDAY: 96>
    10811316\end{python}
    10821317You can even iterate over a @Flag@ variable:
    10831318\begin{python}
    1084 for day in weekend:
    1085         print(day)
     1319>>> for day in weekend:
     1320...    print(day)
    10861321Weekday.SATURDAY
    10871322Weekday.SUNDAY
     
    11471382\subsection{Duplicating enum members and values}
    11481383
    1149 An enum member can have other names associated with it.
     1384Having two enum members with the same name is invalid:
     1385\begin{python}
     1386>>> class Shape(Enum):
     1387...    SQUARE = 2
     1388...    SQUARE = 3
     1389...
     1390Traceback (most recent call last):
     1391...
     1392TypeError: 'SQUARE' already defined as 2
     1393\end{python}
     1394However, an enum member can have other names associated with it.
    11501395Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@.
    11511396By-value lookup of the value of @A@ will return the member @A@.
     
    11531398By-name lookup of @B@ will also return the member @A@:
    11541399\begin{python}
    1155 class Shape(Enum): SQUARE = 2; DIAMOND = 1; CIRCLE = 3; ALIAS_FOR_SQUARE = 2
     1400>>> class Shape(Enum):
     1401...    SQUARE = 2
     1402...    DIAMOND = 1
     1403...    CIRCLE = 3
     1404...    ALIAS_FOR_SQUARE = 2
     1405...
    11561406>>> Shape.SQUARE
    11571407<Shape.SQUARE: 2>
     
    11691419When this behavior isn't desired, you can use the @unique()@ decorator:
    11701420\begin{python}
    1171 from enum import Enum, unique
    1172 $@$unique
    1173 class DupVal(Enum): ONE = 1; TWO = 2; THREE = 3; FOUR = 3
     1421>>> from enum import Enum, unique
     1422>>> $@$unique
     1423... class Mistake(Enum):
     1424...     ONE = 1
     1425...     TWO = 2
     1426...     THREE = 3
     1427...     FOUR = 3
     1428...
     1429Traceback (most recent call last):
     1430...
    11741431ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
    11751432\end{python}
     
    11791436If the exact value is unimportant you can use @auto@:
    11801437\begin{python}
    1181 from enum import Enum, auto
    1182 class RGBa(Enum): RED = auto(); BLUE = auto(); GREEN = auto()
    1183 \end{python}
    1184 (Like Golang @iota@.)
    1185 The values are chosen by @_generate_next_value_()@, which can be overridden:
     1438>>> from enum import Enum, auto
     1439>>> class Color(Enum):
     1440...     RED = auto()
     1441...     BLUE = auto()
     1442...     GREEN = auto()
     1443...
     1444>>> [member.value for member in Color]
     1445[1, 2, 3]
     1446\end{python}
     1447The values are chosen by \_generate\_next\_value\_(), which can be overridden:
    11861448\begin{python}
    11871449>>> class AutoName(Enum):
     
    13201582\begin{python}
    13211583class EnumName([mix-in, ...,] [data-type,] base-enum):
    1322         pass
     1584    pass
    13231585\end{python}
    13241586Also, subclassing an enumeration is allowed only if the enumeration does not define any members.
     
    14371699\begin{python}
    14381700Enum(
    1439         value='NewEnumName',
    1440         names=<...>,
    1441         *,
    1442         module='...',
    1443         qualname='...',
    1444         type=<mixed-in class>,
    1445         start=1,
    1446         )
     1701    value='NewEnumName',
     1702    names=<...>,
     1703    *,
     1704    module='...',
     1705    qualname='...',
     1706    type=<mixed-in class>,
     1707    start=1,
     1708    )
    14471709\end{python}
    14481710\begin{itemize}
     
    16731935\begin{python}
    16741936class IntEnum(int, Enum):
    1675         pass
     1937    pass
    16761938\end{python}
    16771939This demonstrates how similar derived enumerations can be defined;
     
    18082070\begin{python}
    18092071def __bool__(self):
    1810         return bool(self.value)
     2072    return bool(self.value)
    18112073\end{python}
    18122074Plain @Enum@ classes always evaluate as @True@.
     
    21522414
    21532415If @__new__()@ or @__init__()@ is defined, the value of the enum member will be passed to those methods:
    2154 \begin{figure}
    2155 \begin{python}
    2156 from enum import Enum
    2157 class Planet(Enum):
    2158         MERCURY = ( 3.303E23, 2.4397E6 )
    2159         VENUS       = ( 4.869E24, 6.0518E6 )
    2160         EARTH       = (5.976E24, 6.37814E6)
    2161         MARS         = (6.421E23, 3.3972E6)
    2162         JUPITER    = (1.9E27,   7.1492E7)
    2163         SATURN     = (5.688E26, 6.0268E7)
    2164         URANUS    = (8.686E25, 2.5559E7)
    2165         NEPTUNE  = (1.024E26, 2.4746E7)
    2166         def __init__( self, mass, radius ):
    2167                 self.mass = mass                # in kilograms
    2168                 self.radius = radius    # in meters
    2169         def surface_gravity( self ):
    2170                 # universal gravitational constant  (m3 kg-1 s-2)
    2171                 G = 6.67300E-11
    2172                 return G * self.mass / (self.radius * self.radius)
    2173 for p in Planet:
    2174         print( f"{p.name}: {p.value}" )
    2175 
    2176 MERCURY: (3.303e+23, 2439700.0)
    2177 VENUS: (4.869e+24, 6051800.0)
    2178 EARTH: (5.976e+24, 6378140.0)
    2179 MARS: (6.421e+23, 3397200.0)
    2180 JUPITER: (1.9e+27, 71492000.0)
    2181 SATURN: (5.688e+26, 60268000.0)
    2182 URANUS: (8.686e+25, 25559000.0)
    2183 NEPTUNE: (1.024e+26, 24746000.0)
    2184 \end{python}
    2185 \caption{Python Planet Example}
    2186 \label{f:PythonPlanetExample}
    2187 \end{figure}
    2188 
     2416\begin{python}
     2417>>> class Planet(Enum):
     2418...     MERCURY = (3.303e+23, 2.4397e6)
     2419...     VENUS   = (4.869e+24, 6.0518e6)
     2420...     EARTH   = (5.976e+24, 6.37814e6)
     2421...     MARS    = (6.421e+23, 3.3972e6)
     2422...     JUPITER = (1.9e+27,   7.1492e7)
     2423...     SATURN  = (5.688e+26, 6.0268e7)
     2424...     URANUS  = (8.686e+25, 2.5559e7)
     2425...     NEPTUNE = (1.024e+26, 2.4746e7)
     2426...     def __init__(self, mass, radius):
     2427...         self.mass = mass       # in kilograms
     2428...         self.radius = radius   # in meters
     2429...     $\@$property
     2430...     def surface_gravity(self):
     2431...         # universal gravitational constant  (m3 kg-1 s-2)
     2432...         G = 6.67300E-11
     2433...         return G * self.mass / (self.radius * self.radius)
     2434...
     2435>>> Planet.EARTH.value
     2436(5.976e+24, 6378140.0)
     2437>>> Planet.EARTH.surface_gravity
     24389.802652743337129
     2439\end{python}
    21892440
    21902441\subsection{TimePeriod}
     
    22132464\section{OCaml}
    22142465\lstnewenvironment{ocaml}[1][]{\lstset{language=OCaml,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    2215 
    2216 % https://ocaml.org/docs/basic-data-types#enumerated-data-types
    22172466
    22182467OCaml provides a variant (union) type, where multiple heterogeneously-typed objects share the same storage.
     
    23042553With valediction,
    23052554  - Gregor Richards
    2306 
    2307 
    2308 Date: Thu, 14 Mar 2024 21:45:52 -0400
    2309 Subject: Re: OCaml "enums" do come with ordering
    2310 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
    2311 From: Gregor Richards <gregor.richards@uwaterloo.ca>
    2312 
    2313 On 3/14/24 21:30, Peter A. Buhr wrote:
    2314 > I've marked 3 places with your name to shows places with enum ordering.
    2315 >
    2316 > type weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun
    2317 > let day : weekday = Mon
    2318 > let take_class( d : weekday ) =
    2319 >       if d <= Fri then                                (* Gregor *)
    2320 >               Printf.printf "weekday\n"
    2321 >       else if d >= Sat then                   (* Gregor *)
    2322 >               Printf.printf "weekend\n";
    2323 >       match d with
    2324 >               Mon | Wed -> Printf.printf "CS442\n" |
    2325 >               Tue | Thu -> Printf.printf "CS343\n" |
    2326 >               Fri -> Printf.printf "Tutorial\n" |
    2327 >               _ -> Printf.printf "Take a break\n"
    2328 >
    2329 > let _ = take_class( Mon ); take_class( Sat );
    2330 >
    2331 > type colour = Red | Green of string | Blue of int * float
    2332 > let c = Red
    2333 > let _ = match c with Red -> Printf.printf "Red, "
    2334 > let c = Green( "abc" )
    2335 > let _ = match c with Green g -> Printf.printf "%s, " g
    2336 > let c = Blue( 1, 1.5 )
    2337 > let _ = match c with Blue( i, f ) -> Printf.printf "%d %g\n" i f
    2338 >
    2339 > let check_colour(c: colour): string =
    2340 >       if c < Green( "xyz" ) then              (* Gregor *)
    2341 >               Printf.printf "green\n";
    2342 >       match c with
    2343 >               Red -> "Red" |
    2344 >               Green g -> g |
    2345 >               Blue(i, f) -> string_of_int i ^ string_of_float f
    2346 > let _ = check_colour( Red ); check_colour( Green( "xyz" ) );
    2347 >
    2348 > type stringList = Empty | Pair of string * stringList
    2349 > let rec len_of_string_list(l: stringList): int =
    2350 >       match l with
    2351 >               Empty -> 0 |
    2352 >               Pair(_ , r) -> 1 + len_of_string_list r
    2353 >
    2354 > let _ = for i = 1 to 10 do
    2355 >       Printf.printf "%d, " i
    2356 > done
    2357 >
    2358 > (* Local Variables: *)
    2359 > (* tab-width: 4 *)
    2360 > (* compile-command: "ocaml test.ml" *)
    2361 > (* End: *)
    2362 
    2363 My functional-language familiarity is far more with Haskell than OCaml.  I
    2364 mostly view OCaml through a lens of "it's Haskell but with cheating".  Haskell
    2365 "enums" (ADTs) aren't ordered unless you specifically and manually put them in
    2366 the Ord typeclass by defining the comparators.  Apparently, OCaml has some
    2367 other rule, which I would guess is something like "sort by tag then by order of
    2368 parameter". Having a default behavior for comparators is *bizarre*; my guess
    2369 would be that it gained this behavior in its flirtation with object
    2370 orientation, but that's just a guess (and irrelevant).
    2371 
    2372 This gives a total order, but not enumerability (which would still be
    2373 effectively impossible or even meaningless since enums are just a special case
    2374 of ADTs).
    2375 
    2376 With valediction,
    2377   - Gregor Richards
    2378 
    2379 Date: Wed, 20 Mar 2024 18:16:44 -0400
    2380 Subject: Re:
    2381 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
    2382 From: Gregor Richards <gregor.richards@uwaterloo.ca>
    2383 
    2384 
    2385 On 3/20/24 17:26, Peter A. Buhr wrote:
    2386 > Gregor, everyone at this end would like a definition of "enumerability". Can
    2387 > you formulate one?
    2388 
    2389 According to the OED (emphasis added to the meaning I'm after):
    2390 
    2391 enumerate (verb, transitive). To count, ascertain the number of; **more
    2392 usually, to mention (a number of things or persons) separately, as if for the
    2393 purpose of counting**; to specify as in a list or catalogue.
    2394 
    2395 With C enums, if you know the lowest and highest value, you can simply loop
    2396 over them in a for loop (this is, of course, why so many enums come with an
    2397 ENUM_WHATEVER_LAST value). But, I would be hesitant to use the word "loop" to
    2398 describe enumerability, since in functional languages, you would recurse for
    2399 such a purpose.
    2400 
    2401 In Haskell, in order to do something with every member of an "enumeration", you
    2402 would have to explicitly list them all. The type system will help a bit since
    2403 it knows if you haven't listed them all, but you would have to statically have
    2404 every element in the enumeration.  If somebody added new elements to the
    2405 enumeration later, your code to enumerate over them would no longer work
    2406 correctly, because you can't simply say "for each member of this enumeration do
    2407 X". In Haskell that's because there aren't actually enumerations; what they use
    2408 as enumerations are a degenerate form of algebraic datatypes, and ADTs are
    2409 certainly not enumerable. In OCaml, you've demonstrated that they impose
    2410 comparability, but I would still assume that you can't make a loop over every
    2411 member of an enumeration. (But, who knows!)
    2412 
    2413 Since that's literally what "enumerate" means, it seems like a rather important
    2414 property for enumerations to have ;)
    2415 
    2416 With valediction,
    2417   - Gregor Richards
    2418 
    2419 
    2420 From: Andrew James Beach <ajbeach@uwaterloo.ca>
    2421 To: Gregor Richards <gregor.richards@uwaterloo.ca>, Peter Buhr <pabuhr@uwaterloo.ca>
    2422 CC: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>, Fangren Yu <f37yu@uwaterloo.ca>,
    2423     Jiada Liang <j82liang@uwaterloo.ca>
    2424 Subject: Re: Re:
    2425 Date: Thu, 21 Mar 2024 14:26:36 +0000
    2426 
    2427 Does this mean that not all enum declarations in C create enumerations? If you
    2428 declare an enumeration like:
    2429 
    2430 enum Example {
    2431     Label,
    2432     Name = 10,
    2433     Tag = 3,
    2434 };
    2435 
    2436 I don't think there is any way to enumerate (iterate, loop, recurse) over these
    2437 values without listing all of them.
    2438 
    2439 
    2440 Date: Thu, 21 Mar 2024 10:31:49 -0400
    2441 Subject: Re:
    2442 To: Andrew James Beach <ajbeach@uwaterloo.ca>, Peter Buhr <pabuhr@uwaterloo.ca>
    2443 CC: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>, Fangren Yu <f37yu@uwaterloo.ca>,
    2444     Jiada Liang <j82liang@uwaterloo.ca>
    2445 From: Gregor Richards <gregor.richards@uwaterloo.ca>
    2446 
    2447 I consider this conclusion reasonable. C enums can be nothing more than const
    2448 ints, and if used in that way, I personally wouldn't consider them as
    2449 enumerations in any meaningful sense, particularly since the type checker
    2450 essentially does nothing for you there. Then they're a way of writing consts
    2451 repeatedly with some textual indicator that these definitions are related; more
    2452 namespace, less enum.
    2453 
    2454 When somebody writes bitfield members as an enum, is that *really* an
    2455 enumeration, or just a use of the syntax for enums to keep related definitions
    2456 together?
    2457 
    2458 With valediction,
    2459   - Gregor Richards
    24602555\end{comment}
    24612556
     
    24632558\section{Comparison}
    24642559
    2465 \VRef[Table]{t:FeatureLanguageComparison} shows a comparison of enumeration features and programming languages.
    2466 The features are high level and may not capture nuances within a particular language
    2467 The @const@ feature is simple macros substitution and not a typed enumeration.
    2468 
    2469 \begin{table}
    2470 \caption{Enumeration Feature / Language Comparison}
    2471 \label{t:FeatureLanguageComparison}
    2472 \small
    2473 \setlength{\tabcolsep}{3pt}
    2474 \newcommand{\CM}{\checkmark}
    2475 \begin{tabular}{r|c|c|c|c|c|c|c|c|c|c|c|c|c}
    2476                                 &Pascal & Ada   &\Csharp& OCaml & Java  &Modula-3&Golang& Rust  & Swift & Python& C             & \CC   & \CFA  \\
     2560\begin{tabular}{r|ccccccccc}
     2561feat. / lang. & Pascal  & Ada   & \Csharp       & OCaml & Java  & Modula-3      & Rust  & Swift & Python        \\
    24772562\hline
    2478 @const@                 & \CM   &               &               &               &               &               & \CM   &               &               &               &               & \CM   &               \\
    2479 \hline
    2480 \hline
    2481 pure                    &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
    2482 \hline
    2483 typed                   &               &               &               &               &               &               &               &               &               &               & @int@ & integral      & @T@   \\
    2484 \hline
    2485 safe                    &               &               &               &               &               &               &               &               &               &               &               & \CM   & \CM   \\
    2486 \hline
    2487 ordered                 &               &               &               &               &               &               &               &               &               &               & \CM   & \CM   & \CM   \\
    2488 \hline
    2489 dup. values             &               &               &               &               &               &               &               &               &               & alias & \CM   & \CM   & \CM   \\
    2490 \hline
    2491 setable                 &               &               &               &               &               &               &               &               &               &               & \CM   & \CM   & \CM   \\
    2492 \hline
    2493 auto-init               &               &               &               &               &               &               &               &               &               &               & \CM   & \CM   & \CM   \\
    2494 \hline
    2495 (un)scoped              &               &               &               &               &               &               &               &               &               &               & U             & U/S   & U/S   \\
    2496 \hline
    2497 overload                &               & \CM   &               &               &               &               &               &               &               &               &               & \CM   & \CM   \\
    2498 \hline
    2499 switch                  &               &               &               &               &               &               &               &               &               &               & \CM   & \CM   & \CM   \\
    2500 \hline
    2501 loop                    &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
    2502 \hline
    2503 array                   &               &               &               &               &               &               &               &               &               &               & \CM   &               & \CM   \\
    2504 \hline
    2505 subtype                 &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
    2506 \hline
    2507 inheritance             &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
     2563pure            &                       &               &                       &               &               &                       &               &               &                       \\
     2564ordered         &                       &               &                       &               &               &                       &               &               &                       \\
     2565setable         &                       &               &                       &               &               &                       &               &               &                       \\
     2566auto-init       &                       &               &                       &               &               &                       &               &               &                       \\
     2567scoped          &                       &               &                       &               &               &                       &               &               &                       \\
     2568typed           &                       &               &                       &               &               &                       &               &               &                       \\
     2569switch          &                       &               &                       &               &               &                       &               &               &                       \\
     2570loop            &                       &               &                       &               &               &                       &               &               &                       \\
     2571array           &                       &               &                       &               &               &                       &               &               &                       \\
    25082572\end{tabular}
    2509 \end{table}
  • doc/theses/mike_brooks_MMath/array.tex

    r486caad rdf78cce  
    510510
    511511\subsection{Retire pointer arithmetic}
    512 
    513 
    514 \section{\CFA}
    515 
    516 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \\
    517 moved from background chapter \\
    518 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \\
    519 
    520 Traditionally, fixing C meant leaving the C-ism alone, while providing a better alternative beside it.
    521 (For later:  That's what I offer with array.hfa, but in the future-work vision for arrays, the fix includes helping programmers stop accidentally using a broken C-ism.)
    522 
    523 \subsection{\CFA features interacting with arrays}
    524 
    525 Prior work on \CFA included making C arrays, as used in C code from the wild,
    526 work, if this code is fed into @cfacc@.
    527 The quality of this this treatment was fine, with no more or fewer bugs than is typical.
    528 
    529 More mixed results arose with feeding these ``C'' arrays into preexisting \CFA features.
    530 
    531 A notable success was with the \CFA @alloc@ function,
    532 which type information associated with a polymorphic return type
    533 replaces @malloc@'s use of programmer-supplied size information.
    534 \begin{cfa}
    535 // C, library
    536 void * malloc( size_t );
    537 // C, user
    538 struct tm * el1 = malloc(      sizeof(struct tm) );
    539 struct tm * ar1 = malloc( 10 * sizeof(struct tm) );
    540 
    541 // CFA, library
    542 forall( T * ) T * alloc();
    543 // CFA, user
    544 tm * el2 = alloc();
    545 tm (*ar2)[10] = alloc();
    546 \end{cfa}
    547 The alloc polymorphic return compiles into a hidden parameter, which receives a compiler-generated argument.
    548 This compiler's argument generation uses type information from the left-hand side of the initialization to obtain the intended type.
    549 Using a compiler-produced value eliminates an opportunity for user error.
    550 
    551 TODO: fix in following: even the alloc call gives bad code gen: verify it was always this way; walk back the wording about things just working here; assignment (rebind) seems to offer workaround, as in bkgd-cfa-arrayinteract.cfa
    552 
    553 Bringing in another \CFA feature, reference types, both resolves a sore spot of the last example, and gives a first example of an array-interaction bug.
    554 In the last example, the choice of ``pointer to array'' @ar2@ breaks a parallel with @ar1@.
    555 They are not subscripted in the same way.
    556 \begin{cfa}
    557 ar1[5];
    558 (*ar2)[5];
    559 \end{cfa}
    560 Using ``reference to array'' works at resolving this issue.  TODO: discuss connection with Doug-Lea \CC proposal.
    561 \begin{cfa}
    562 tm (&ar3)[10] = *alloc();
    563 ar3[5];
    564 \end{cfa}
    565 The implicit size communication to @alloc@ still works in the same ways as for @ar2@.
    566 
    567 Using proper array types (@ar2@ and @ar3@) addresses a concern about using raw element pointers (@ar1@), albeit a theoretical one.
    568 TODO xref C standard does not claim that @ar1@ may be subscripted,
    569 because no stage of interpreting the construction of @ar1@ has it be that ``there is an \emph{array object} here.''
    570 But both @*ar2@ and the referent of @ar3@ are the results of \emph{typed} @alloc@ calls,
    571 where the type requested is an array, making the result, much more obviously, an array object.
    572 
    573 The ``reference to array'' type has its sore spots too.
    574 TODO see also @dimexpr-match-c/REFPARAM_CALL@ (under @TRY_BUG_1@)
    575 
    576 TODO: I fixed a bug associated with using an array as a T.  I think.  Did I really?  What was the bug?
  • doc/theses/mike_brooks_MMath/background.tex

    r486caad rdf78cce  
    11\chapter{Background}
    22
    3 Since this work builds on C, it is necessary to explain the C mechanisms and their shortcomings for array, linked list, and string,
    4 
    5 
    6 \section{Array}
     3This chapter states facts about the prior work, upon which my contributions build.
     4Each receives a justification of the extent to which its statement is phrased to provoke controversy or surprise.
     5
     6\section{C}
     7
     8\subsection{Common knowledge}
     9
     10The reader is assumed to have used C or \CC for the coursework of at least four university-level courses, or have equivalent experience.
     11The current discussion introduces facts, unaware of which, such a functioning novice may be operating.
     12
     13% TODO: decide if I'm also claiming this collection of facts, and test-oriented presentation is a contribution; if so, deal with (not) arguing for its originality
     14
     15\subsection{Convention: C is more touchable than its standard}
     16
     17When it comes to explaining how C works, I like illustrating definite program semantics.
     18I prefer doing so, over a quoting manual's suggested programmer's intuition, or showing how some compiler writers chose to model their problem.
     19To illustrate definite program semantics, I devise a program, whose behaviour exercises the point at issue, and I show its behaviour.
     20
     21This behaviour is typically one of
     22\begin{itemize}
     23        \item my statement that the compiler accepts or rejects the program
     24        \item the program's printed output, which I show
     25        \item my implied assurance that its assertions do not fail when run
     26\end{itemize}
     27
     28The compiler whose program semantics is shown is
     29\begin{cfa}
     30$ gcc --version
     31gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
     32\end{cfa}
     33running on Architecture @x86_64@, with the same environment targeted.
     34
     35Unless explicit discussion ensues about differences among compilers or with (versions of) the standard, it is further implied that there exists a second version of GCC and some version of Clang, running on and for the same platform, that give substantially similar behaviour.
     36In this case, I do not argue that my sample of major Linux compilers is doing the right thing with respect to the C standard.
     37
     38
     39\subsection{C reports many ill-typed expressions as warnings}
     40
     41These attempts to assign @y@ to @x@ and vice-versa are obviously ill-typed.
     42\lstinput{12-15}{bkgd-c-tyerr.c}
     43with warnings:
     44\begin{cfa}
     45warning: assignment to 'float *' from incompatible pointer type 'void (*)(void)'
     46warning: assignment to 'void (*)(void)' from incompatible pointer type 'float *'
     47\end{cfa}
     48Similarly,
     49\lstinput{17-19}{bkgd-c-tyerr.c}
     50with warning:
     51\begin{cfa}
     52warning: passing argument 1 of 'f' from incompatible pointer type
     53note: expected 'void (*)(void)' but argument is of type 'float *'
     54\end{cfa}
     55with a segmentation fault at runtime.
     56
     57That @f@'s attempt to call @g@ fails is not due to 3.14 being a particularly unlucky choice of value to put in the variable @pi@.
     58Rather, it is because obtaining a program that includes this essential fragment, yet exhibits a behaviour other than "doomed to crash," is a matter for an obfuscated coding competition.
     59
     60A "tractable syntactic method for proving the absence of certain program behaviours by classifying phrases according to the kinds of values they compute"*1 rejected the program.
     61The behaviour (whose absence is unprovable) is neither minor nor unlikely.
     62The rejection shows that the program is ill-typed.
     63
     64Yet, the rejection presents as a GCC warning.
     65
     66In the discussion following, ``ill-typed'' means giving a nonzero @gcc -Werror@ exit condition with a message that discusses typing.
     67
     68*1  TAPL-pg1 definition of a type system
     69
     70
     71\section{C Arrays}
     72
     73\subsection{C has an array type (!)}
    774
    875When a programmer works with an array, C semantics provide access to a type that is different in every way from ``pointer to its first element.''
     
    444511
    445512
    446 \section{Linked List}
    447 
    448 
    449 \section{String}
     513\section{\CFA}
     514
     515Traditionally, fixing C meant leaving the C-ism alone, while providing a better alternative beside it.
     516(For later:  That's what I offer with array.hfa, but in the future-work vision for arrays, the fix includes helping programmers stop accidentally using a broken C-ism.)
     517
     518\subsection{\CFA features interacting with arrays}
     519
     520Prior work on \CFA included making C arrays, as used in C code from the wild,
     521work, if this code is fed into @cfacc@.
     522The quality of this this treatment was fine, with no more or fewer bugs than is typical.
     523
     524More mixed results arose with feeding these ``C'' arrays into preexisting \CFA features.
     525
     526A notable success was with the \CFA @alloc@ function,
     527which type information associated with a polymorphic return type
     528replaces @malloc@'s use of programmer-supplied size information.
     529\begin{cfa}
     530// C, library
     531void * malloc( size_t );
     532// C, user
     533struct tm * el1 = malloc(      sizeof(struct tm) );
     534struct tm * ar1 = malloc( 10 * sizeof(struct tm) );
     535
     536// CFA, library
     537forall( T * ) T * alloc();
     538// CFA, user
     539tm * el2 = alloc();
     540tm (*ar2)[10] = alloc();
     541\end{cfa}
     542The alloc polymorphic return compiles into a hidden parameter, which receives a compiler-generated argument.
     543This compiler's argument generation uses type information from the left-hand side of the initialization to obtain the intended type.
     544Using a compiler-produced value eliminates an opportunity for user error.
     545
     546TODO: fix in following: even the alloc call gives bad code gen: verify it was always this way; walk back the wording about things just working here; assignment (rebind) seems to offer workaround, as in bkgd-cfa-arrayinteract.cfa
     547
     548Bringing in another \CFA feature, reference types, both resolves a sore spot of the last example, and gives a first example of an array-interaction bug.
     549In the last example, the choice of ``pointer to array'' @ar2@ breaks a parallel with @ar1@.
     550They are not subscripted in the same way.
     551\begin{cfa}
     552ar1[5];
     553(*ar2)[5];
     554\end{cfa}
     555Using ``reference to array'' works at resolving this issue.  TODO: discuss connection with Doug-Lea \CC proposal.
     556\begin{cfa}
     557tm (&ar3)[10] = *alloc();
     558ar3[5];
     559\end{cfa}
     560The implicit size communication to @alloc@ still works in the same ways as for @ar2@.
     561
     562Using proper array types (@ar2@ and @ar3@) addresses a concern about using raw element pointers (@ar1@), albeit a theoretical one.
     563TODO xref C standard does not claim that @ar1@ may be subscripted,
     564because no stage of interpreting the construction of @ar1@ has it be that ``there is an \emph{array object} here.''
     565But both @*ar2@ and the referent of @ar3@ are the results of \emph{typed} @alloc@ calls,
     566where the type requested is an array, making the result, much more obviously, an array object.
     567
     568The ``reference to array'' type has its sore spots too.
     569TODO see also @dimexpr-match-c/REFPARAM_CALL@ (under @TRY_BUG_1@)
     570
     571TODO: I fixed a bug associated with using an array as a T.  I think.  Did I really?  What was the bug?
  • doc/theses/mike_brooks_MMath/intro.tex

    r486caad rdf78cce  
    11\chapter{Introduction}
    2 
    3 All modern programming languages provide three high-level containers (collection): array, linked-list, and string.
    4 Often array is part of the programming language, while linked-list is built from pointer types, and string from a combination of array and linked-list.
    52
    63\cite{Blache19}
     
    85\cite{Ruef19}
    96
    10 \section{Array}
     7\section{Arrays}
    118
    12 Array provides a homogeneous container with $O(1)$ access to elements using subscripting.
    13 The array size can be static, dynamic but fixed after creation, or dynamic and variable after creation.
    14 For static and dynamic-fixed, an array can be stack allocated, while dynamic-variable requires the heap.
    15 
    16 
    17 \section{Linked List}
    18 
    19 Linked-list provides a homogeneous container with $O(log N)$/$O(N)$ access to elements using successor and predecessor operations.
    20 Subscripting by value is sometimes available, \eg hash table.
    21 Linked types are normally dynamically sized by adding/removing nodes using link fields internal or external to the elements (nodes).
    22 If a programming language allows pointer to stack storage, linked-list types can be allocated on the stack;
    23 otherwise, elements are heap allocated and explicitly/implicitly managed.
    24 
    25 
    26 \section{String}
    27 
    28 String provides a dynamic array of homogeneous elements, where the elements are often human-readable characters.
    29 What differentiates string from other types in that string operations work on blocks of elements for scanning and changing the elements, rather than accessing individual elements.
    30 Nevertheless, subscripting is often available.
    31 The cost of string operations is less important than the power of the block operation to accomplish complex manipulation.
    32 The dynamic nature of string means storage is normally heap allocated but often implicitly managed, even in unmanaged languages.
    33 
    34 
    35 \section{Motivation}
    36 
    37 The goal of this work is to introduce safe and complex versions of array, link-lists, and string into the programming language \CFA~\cite{CFA}, which is based on C.
    38 Unfortunately, to make C better, while retaining a high level of backwards compatibility, requires a significant knowledge of C's design.
    39 Hence, it is assumed the reader has a medium knowledge of C or \CC, on which extensive new C knowledge is built.
    40 
    41 
    42 \subsection{C?}
    43 
    44 Like many established programming languages, C has a standards committee and multiple ANSI/\-ISO language manuals~\cite{C99,C11,C18,C23}.
    45 However, most programming languages are only partially explained by standard's manuals.
    46 When it comes to explaining how C works, the definitive source is the @gcc@ compiler, which is mimicked by other C compilers, such as Clang~\cite{clang}.
    47 Often other C compilers must \emph{ape} @gcc@ because a large part of the C library (runtime) system contains @gcc@ features.
    48 While some key aspects of C need to be explained by quoting from the language reference manual, to illustrate definite program semantics, I devise a program, whose behaviour exercises the point at issue, and shows its behaviour.
    49 These example programs show
    50 \begin{itemize}
    51         \item the compiler accepts or rejects certain syntax,
    52         \item prints output to buttress a claim of behaviour,
    53         \item executes without triggering any embedded assertions testing pre/post-assertions or invariants.
    54 \end{itemize}
    55 This work has been tested across @gcc@ versions 8--12 and clang version 10 running on ARM, AMD, and Intel architectures.
    56 Any discovered anomalies among compilers or versions is discussed.
    57 In this case, I do not argue that my sample of major Linux compilers is doing the right thing with respect to the C standard.
    58 
    59 
    60 \subsection{Ill-Typed Expressions}
    61 
    62 C reports many ill-typed expressions as warnings.
    63 For example, these attempts to assign @y@ to @x@ and vice-versa are obviously ill-typed.
    64 \lstinput{12-15}{bkgd-c-tyerr.c}
    65 with warnings:
    66 \begin{cfa}
    67 warning: assignment to 'float *' from incompatible pointer type 'void (*)(void)'
    68 warning: assignment to 'void (*)(void)' from incompatible pointer type 'float *'
    69 \end{cfa}
    70 Similarly,
    71 \lstinput{17-19}{bkgd-c-tyerr.c}
    72 with warning:
    73 \begin{cfa}
    74 warning: passing argument 1 of 'f' from incompatible pointer type
    75 note: expected 'void (*)(void)' but argument is of type 'float *'
    76 \end{cfa}
    77 with a segmentation fault at runtime.
    78 Clearly, @gcc@ understands these ill-typed case, and yet allows the program to compile, which seems like madness.
    79 Compiling with flag @-Werror@, which turns warnings into errors, is often too strong, because some warnings are just warnings.
    80 In the following discussion, ``ill-typed'' means giving a nonzero @gcc@ exit condition with a message that discusses typing.
    81 Note, \CFA's type-system rejects all these ill-typed cases as type mismatch errors.
    82 
    83 % That @f@'s attempt to call @g@ fails is not due to 3.14 being a particularly unlucky choice of value to put in the variable @pi@.
    84 % Rather, it is because obtaining a program that includes this essential fragment, yet exhibits a behaviour other than "doomed to crash," is a matter for an obfuscated coding competition.
    85 
    86 % A "tractable syntactic method for proving the absence of certain program behaviours by classifying phrases according to the kinds of values they compute"*1 rejected the program.
    87 % The behaviour (whose absence is unprovable) is neither minor nor unlikely.
    88 % The rejection shows that the program is ill-typed.
    89 %
    90 % Yet, the rejection presents as a GCC warning.
    91 % *1  TAPL-pg1 definition of a type system
    92 
     9\section{Strings}
    9310
    9411\section{Contributions}
    95 
    96 \subsection{Linked List}
    97 
    98 \subsection{Array}
    99 
    100 \subsection{String}
  • doc/theses/mike_brooks_MMath/uw-ethesis.tex

    r486caad rdf78cce  
    218218\input{intro}
    219219\input{background}
     220\input{list}
    220221\input{array}
    221 \input{list}
    222222\input{string}
    223223\input{conclusion}
  • libcfa/src/stdlib.cfa

    r486caad rdf78cce  
    1010// Created On       : Thu Jan 28 17:10:29 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Mar 17 08:25:32 2024
    13 // Update Count     : 699
     12// Last Modified On : Mon Aug 14 18:22:36 2023
     13// Update Count     : 642
    1414//
    1515
     
    2121
    2222#include <string.h>                                                                             // memcpy, memset
     23//#include <math.h>                                                                             // fabsf, fabs, fabsl
    2324#include <complex.h>                                                                    // _Complex_I
    2425#include <assert.h>
    25 #include <ctype.h>                                                                              // isblank
    2626
    2727#pragma GCC visibility push(default)
     
    6565//---------------------------------------
    6666
    67 // Check if all string characters are a specific kind, e.g., checkif( s, isblank )
    68 
    69 bool checkif( const char s[], int (* kind)( int ) ) {
    70         for () {
    71                 if ( *s == '\0' ) return true;
    72                 if ( ! kind( *s ) ) return false;
    73                 s += 1;
    74         } // for
    75 } // checkif
    76 
    77 bool checkif( const char s[], int (* kind)( int, locale_t ), locale_t locale ) {
    78         for () {
    79                 if ( *s == '\0' ) return true;
    80                 if ( ! kind( *s, locale ) ) return false;
    81                 s += 1;
    82         } // for
    83 } // checkif
    84 
    85 //---------------------------------------
    86 
    87 float _Complex strto( const char sptr[], char * eptr[] ) {
    88         float re, im;
    89         char * eeptr;
    90         errno = 0;                                                                                      // reset
    91         re = strtof( sptr, &eeptr );
    92         if ( sptr != eeptr ) {
    93                 im = strtof( eeptr, &eeptr );
    94                 if ( sptr != eeptr ) {
    95                         if ( *eeptr == 'i' ) {
    96                                 if ( eptr != 0p ) *eptr = eeptr + 1;
    97                                 return re + im * _Complex_I;
    98                         } // if
    99                 } // if
    100         } // if
    101         if ( eptr != 0p ) *eptr = eeptr;                                        // error case
    102         return 0.0f + 0.0f * _Complex_I;
    103 } // strto
    104 
    105 double _Complex strto( const char sptr[], char * eptr[] ) {
    106         double re, im;
    107         char * eeptr;
    108         re = strtod( sptr, &eeptr );
    109         if ( sptr != eeptr ) {
    110                 im = strtod( eeptr, &eeptr );
    111                 if ( sptr != eeptr ) {
    112                         if ( *eeptr == 'i' ) {
    113                                 if ( eptr != 0p ) *eptr = eeptr + 1;
    114                                 return re + im * _Complex_I;
    115                         } // if
    116                 } // if
    117         } // if
    118         if ( eptr != 0p ) *eptr = eeptr;                                        // error case
    119         return 0.0 + 0.0 * _Complex_I;
    120 } // strto
    121 
    122 long double _Complex strto( const char sptr[], char * eptr[] ) {
    123         long double re, im;
    124         char * eeptr;
    125         re = strtold( sptr, &eeptr );
    126         if ( sptr != eeptr ) {
    127                 im = strtold( eeptr, &eeptr );
    128                 if ( sptr != eeptr ) {
    129                         if ( *eeptr == 'i' ) {
    130                                 if ( eptr != 0p ) *eptr = eeptr + 1;
    131                                 return re + im * _Complex_I;
    132                         } // if
    133                 } // if
    134         } // if
    135         if ( eptr != 0p ) *eptr = eeptr;                                        // error case
    136         return 0.0L + 0.0L * _Complex_I;
    137 } // strto
    138 
    13967forall( T | { T strto( const char sptr[], char * eptr[], int ); } )
    140 T convert( const char sptr[] ) {                                                // integral
     68T convert( const char sptr[] ) {
    14169        char * eptr;
    14270        errno = 0;                                                                                      // reset
     
    14472        if ( errno == ERANGE ) throw ExceptionInst( out_of_range );
    14573        if ( eptr == sptr ||                                                            // conversion failed, no characters generated
    146                  eptr[0] != '\0' && ! checkif( eptr, isblank ) ) throw ExceptionInst( invalid_argument ); // not at end of blank str ?
     74                 *eptr != '\0' ) throw ExceptionInst( invalid_argument ); // not at end of str ?
    14775        return val;
    14876} // convert
    14977
    150 forall( T | { T strto( const char sptr[], char * eptr[] ); } )
    151 T convert( const char sptr[] ) {                                                // floating-point
    152         char * eptr;
    153         errno = 0;                                                                                      // reset
    154         T val = strto( sptr, &eptr );                                           // attempt conversion
    155         if ( errno == ERANGE ) throw ExceptionInst( out_of_range );
    156         if ( eptr == sptr ||                                                            // conversion failed, no characters generated
    157                  eptr[0] != '\0' && ! checkif( eptr, isblank ) ) throw ExceptionInst( invalid_argument ); // not at end of blank str ?
    158         return val;
    159 } // convert
     78float _Complex strto( const char sptr[], char * eptr[] ) {
     79        float re, im;
     80        char * eeptr;
     81        re = strtof( sptr, &eeptr );
     82        if ( sptr == eeptr ) { if ( eptr != 0 ) *eptr = eeptr; return 0.0f + 0.0f * _Complex_I; }
     83        im = strtof( eeptr, &eeptr );
     84        if ( sptr == eeptr ) { if ( eptr != 0 ) *eptr = eeptr; return 0.0f + 0.0f * _Complex_I; }
     85        if ( *eeptr != 'i' ) { if ( eptr != 0 ) *eptr = eeptr; return 0.0f + 0.0f * _Complex_I; }
     86        return re + im * _Complex_I;
     87} // strto
     88
     89double _Complex strto( const char sptr[], char * eptr[] ) {
     90        double re, im;
     91        char * eeptr;
     92        re = strtod( sptr, &eeptr );
     93        if ( sptr == eeptr ) { if ( eptr != 0 ) *eptr = eeptr; return 0.0 + 0.0 * _Complex_I; }
     94        im = strtod( eeptr, &eeptr );
     95        if ( sptr == eeptr ) { if ( eptr != 0 ) *eptr = eeptr; return 0.0 + 0.0 * _Complex_I; }
     96        if ( *eeptr != 'i' ) { if ( eptr != 0 ) *eptr = eeptr; return 0.0 + 0.0 * _Complex_I; }
     97        return re + im * _Complex_I;
     98} // strto
     99
     100long double _Complex strto( const char sptr[], char * eptr[] ) {
     101        long double re, im;
     102        char * eeptr;
     103        re = strtold( sptr, &eeptr );
     104        if ( sptr == eeptr ) { if ( eptr != 0 ) *eptr = eeptr; return 0.0L + 0.0L * _Complex_I; }
     105        im = strtold( eeptr, &eeptr );
     106        if ( sptr == eeptr ) { if ( eptr != 0 ) *eptr = eeptr; return 0.0L + 0.0L * _Complex_I; }
     107        if ( *eeptr != 'i' ) { if ( eptr != 0 ) *eptr = eeptr; return 0.0L + 0.0L * _Complex_I; }
     108        return re + im * _Complex_I;
     109} // strto
    160110
    161111//---------------------------------------
  • libcfa/src/stdlib.hfa

    r486caad rdf78cce  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Mar 17 08:25:31 2024
    13 // Update Count     : 796
     12// Last Modified On : Sun Oct  8 09:18:28 2023
     13// Update Count     : 789
    1414//
    1515
     
    291291forall( T & | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] );
    292292forall( T & | sized(T) | { void ^?{}( T & ); }, TT... | { void adelete( TT ); } ) void adelete( T arr[], TT rest );
    293 //---------------------------------------
    294 
    295 // Check if all string characters are a specific kind, e.g., checkif( s, isblank )
    296 bool checkif( const char s[], int (* kind)( int ) );
    297 bool checkif( const char s[], int (* kind)( int, locale_t ), locale_t locale );
    298293
    299294//---------------------------------------
     
    320315
    321316forall( T | { T strto( const char sptr[], char * eptr[], int ); } )
    322 T convert( const char sptr[] );                                                 // integrals
    323 forall( T | { T strto( const char sptr[], char * eptr[] ); } )
    324 T convert( const char sptr[] );                                                 // floating-point (no base)
     317T convert( const char sptr[] );
    325318
    326319static inline {
  • src/CodeGen/CodeGenerator.cpp

    r486caad rdf78cce  
    192192        }
    193193
     194        assert( decl->returns.size() < 2 );
    194195        if ( 1 == decl->returns.size() ) {
    195196                ast::ptr<ast::Type> const & type = decl->returns[0]->get_type();
    196197                output << genTypeNoAttr( type, acc.str(), subOptions );
    197         } else if ( 0 == decl->returns.size() ) {
     198        } else {
    198199                output << "void " + acc.str();
    199         } else {
    200                 assertf( !options.genC, "Multi-return should not reach code generation." );
    201                 ast::ptr<ast::Type> type = new ast::TupleType( copy( decl->type->returns ) );
    202                 output << genTypeNoAttr( type, acc.str(), subOptions );
    203200        }
    204201
  • src/Parser/DeclarationNode.cc

    r486caad rdf78cce  
    185185        newnode->type->aggregate.fields = fields;
    186186        newnode->type->aggregate.body = body;
     187        newnode->type->aggregate.tagged = false;
     188        newnode->type->aggregate.parent = nullptr;
    187189        return newnode;
    188190} // DeclarationNode::newAggregate
     
    197199        newnode->type->enumeration.typed = typed;
    198200        newnode->type->enumeration.hiding = hiding;
    199         if ( base ) {
    200                 assert( typed );
    201                 assert( base->type );
     201        if ( base && base->type )  {
    202202                newnode->type->base = base->type;
    203                 base->type = nullptr;
    204                 delete base;
    205203        } // if
    206204
     
    222220
    223221DeclarationNode * DeclarationNode::newEnumValueGeneric( const string * name, InitializerNode * init ) {
    224         if ( nullptr == init ) {
     222        if ( init ) {
     223                if ( init->get_expression() ) {
     224                        return newEnumConstant( name, init->get_expression() );
     225                } else {
     226                        DeclarationNode * newnode = newName( name );
     227                        newnode->initializer = init;
     228                        return newnode;
     229                } // if
     230        } else {
    225231                return newName( name );
    226         } else if ( init->get_expression() ) {
    227                 return newEnumConstant( name, init->get_expression() );
    228         } else {
    229                 DeclarationNode * newnode = newName( name );
    230                 newnode->initializer = init;
    231                 return newnode;
    232232        } // if
    233233} // DeclarationNode::newEnumValueGeneric
     
    502502}
    503503
    504 // This code handles a special issue with the attribute transparent_union.
    505 //
    506 //    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
    507 //
    508 // Here the attribute aligned goes with the typedef_name, so variables declared of this type are
    509 // aligned.  However, the attribute transparent_union must be moved from the typedef_name to
    510 // alias union U.  Currently, this is the only know attribute that must be moved from typedef to
    511 // alias.
    512 static void moveUnionAttribute( DeclarationNode * decl, DeclarationNode * unionDecl ) {
    513         assert( decl->type->kind == TypeData::Symbolic );
    514         assert( decl->type->symbolic.isTypedef );
    515         assert( unionDecl->type->kind == TypeData::Aggregate );
    516 
    517         if ( unionDecl->type->aggregate.kind != ast::AggregateDecl::Union ) return;
    518 
    519         // Ignore the Aggregate_t::attributes. Why did we add that before the rework?
    520         for ( auto attr = decl->attributes.begin() ; attr != decl->attributes.end() ; ) {
    521                 if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
    522                         unionDecl->attributes.emplace_back( attr->release() );
    523                         attr = decl->attributes.erase( attr );
    524                 } else {
    525                         ++attr;
    526                 }
    527         }
    528 }
    529 
    530 // Helper for addTypedef, handles the case where the typedef wraps an
    531 // aggregate declaration (not a type), returns a chain of nodes.
    532 static DeclarationNode * addTypedefAggr(
    533                 DeclarationNode * olddecl, TypeData * newtype ) {
    534         TypeData *& oldaggr = olddecl->type->aggInst.aggregate;
    535 
    536         // Handle anonymous aggregates: typedef struct { int i; } foo
    537         // Give the typedefed type a consistent name across translation units.
    538         if ( oldaggr->aggregate.anon ) {
    539                 delete oldaggr->aggregate.name;
    540                 oldaggr->aggregate.name = new string( "__anonymous_" + *olddecl->name );
    541                 oldaggr->aggregate.anon = false;
    542                 oldaggr->qualifiers.reset();
    543         }
    544 
    545         // Replace the wrapped TypeData with a forward declaration.
    546         TypeData * newaggr = new TypeData( TypeData::Aggregate );
    547         newaggr->aggregate.kind = oldaggr->aggregate.kind;
    548         newaggr->aggregate.name = oldaggr->aggregate.name ? new string( *oldaggr->aggregate.name ) : nullptr;
    549         newaggr->aggregate.body = false;
    550         newaggr->aggregate.anon = oldaggr->aggregate.anon;
    551         swap( newaggr, oldaggr );
    552 
    553         newtype->base = olddecl->type;
    554         olddecl->type = newtype;
    555         DeclarationNode * newdecl = new DeclarationNode;
    556         newdecl->type = newaggr;
    557         newdecl->next = olddecl;
    558 
    559         moveUnionAttribute( olddecl, newdecl );
    560 
    561         return newdecl;
    562 }
    563 
    564 // Helper for addTypedef, handles the case where the typedef wraps an
    565 // enumeration declaration (not a type), returns a chain of nodes.
    566 static DeclarationNode * addTypedefEnum(
    567                 DeclarationNode * olddecl, TypeData * newtype ) {
    568         TypeData *& oldenum = olddecl->type->aggInst.aggregate;
    569 
    570         // Handle anonymous enumeration: typedef enum { A, B, C } foo
    571         // Give the typedefed type a consistent name across translation units.
    572         if ( oldenum->enumeration.anon ) {
    573                 delete oldenum->enumeration.name;
    574                 oldenum->enumeration.name = new string( "__anonymous_" + *olddecl->name );
    575                 oldenum->enumeration.anon = false;
    576                 oldenum->qualifiers.reset();
    577         }
    578 
    579         // Replace the wrapped TypeData with a forward declaration.
    580         TypeData * newenum = new TypeData( TypeData::Enum );
    581         newenum->enumeration.name = oldenum->enumeration.name ? new string( *oldenum->enumeration.name ) : nullptr;
    582         newenum->enumeration.body = false;
    583         newenum->enumeration.anon = oldenum->enumeration.anon;
    584         newenum->enumeration.typed = oldenum->enumeration.typed;
    585         newenum->enumeration.hiding = oldenum->enumeration.hiding;
    586         swap( newenum, oldenum );
    587 
    588         newtype->base = olddecl->type;
    589         olddecl->type = newtype;
    590         DeclarationNode * newdecl = new DeclarationNode;
    591         newdecl->type = newenum;
    592         newdecl->next = olddecl;
    593 
    594         return newdecl;
    595 }
    596 
    597 // Wrap the declaration in a typedef. It actually does that by modifying the
    598 // existing declaration, and may split it into two declarations.
    599 // This only happens if the wrapped type is actually a declaration of a SUE
    600 // type. If it does, the DeclarationNode for the SUE declaration is the node
    601 // returned, make sure later transformations are applied to the right node.
    602504DeclarationNode * DeclarationNode::addTypedef() {
    603505        TypeData * newtype = new TypeData( TypeData::Symbolic );
     
    605507        newtype->symbolic.isTypedef = true;
    606508        newtype->symbolic.name = name ? new string( *name ) : nullptr;
    607         // If this typedef is wrapping an aggregate, separate them out.
    608         if ( TypeData::AggregateInst == type->kind
    609                         && TypeData::Aggregate == type->aggInst.aggregate->kind
    610                         && type->aggInst.aggregate->aggregate.body ) {
    611                 return addTypedefAggr( this, newtype );
    612         // If this typedef is wrapping an enumeration, separate them out.
    613         } else if ( TypeData::AggregateInst == type->kind
    614                         && TypeData::Enum == type->aggInst.aggregate->kind
    615                         && type->aggInst.aggregate->enumeration.body ) {
    616                 return addTypedefEnum( this, newtype );
    617         // There is no internal declaration, just a type.
    618         } else {
    619                 newtype->base = type;
    620                 type = newtype;
    621                 return this;
    622         }
     509        newtype->base = type;
     510        type = newtype;
     511        return this;
    623512}
    624513
     
    822711}
    823712
     713// If a typedef wraps an anonymous declaration, name the inner declaration so it has a consistent name across
     714// translation units.
     715static void nameTypedefedDecl(
     716                DeclarationNode * innerDecl,
     717                const DeclarationNode * outerDecl ) {
     718        TypeData * outer = outerDecl->type;
     719        assert( outer );
     720        // First make sure this is a typedef:
     721        if ( outer->kind != TypeData::Symbolic || !outer->symbolic.isTypedef ) {
     722                return;
     723        }
     724        TypeData * inner = innerDecl->type;
     725        assert( inner );
     726        // Always clear any CVs associated with the aggregate:
     727        inner->qualifiers.reset();
     728        // Handle anonymous aggregates: typedef struct { int i; } foo
     729        if ( inner->kind == TypeData::Aggregate && inner->aggregate.anon ) {
     730                delete inner->aggregate.name;
     731                inner->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
     732                inner->aggregate.anon = false;
     733                assert( outer->base );
     734                delete outer->base->aggInst.aggregate->aggregate.name;
     735                outer->base->aggInst.aggregate->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
     736                outer->base->aggInst.aggregate->aggregate.anon = false;
     737                outer->base->aggInst.aggregate->qualifiers.reset();
     738        // Handle anonymous enumeration: typedef enum { A, B, C } foo
     739        } else if ( inner->kind == TypeData::Enum && inner->enumeration.anon ) {
     740                delete inner->enumeration.name;
     741                inner->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
     742                inner->enumeration.anon = false;
     743                assert( outer->base );
     744                delete outer->base->aggInst.aggregate->enumeration.name;
     745                outer->base->aggInst.aggregate->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
     746                outer->base->aggInst.aggregate->enumeration.anon = false;
     747                // No qualifiers.reset() here.
     748        }
     749}
     750
     751// This code handles a special issue with the attribute transparent_union.
     752//
     753//    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
     754//
     755// Here the attribute aligned goes with the typedef_name, so variables declared of this type are
     756// aligned.  However, the attribute transparent_union must be moved from the typedef_name to
     757// alias union U.  Currently, this is the only know attribute that must be moved from typedef to
     758// alias.
     759static void moveUnionAttribute( ast::Decl * decl, ast::UnionDecl * unionDecl ) {
     760        if ( auto typedefDecl = dynamic_cast<ast::TypedefDecl *>( decl ) ) {
     761                // Is the typedef alias a union aggregate?
     762                if ( nullptr == unionDecl ) return;
     763
     764                // If typedef is an alias for a union, then its alias type was hoisted above and remembered.
     765                if ( auto unionInstType = typedefDecl->base.as<ast::UnionInstType>() ) {
     766                        auto instType = ast::mutate( unionInstType );
     767                        // Remove all transparent_union attributes from typedef and move to alias union.
     768                        for ( auto attr = instType->attributes.begin() ; attr != instType->attributes.end() ; ) {
     769                                assert( *attr );
     770                                if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
     771                                        unionDecl->attributes.emplace_back( attr->release() );
     772                                        attr = instType->attributes.erase( attr );
     773                                } else {
     774                                        attr++;
     775                                }
     776                        }
     777                        typedefDecl->base = instType;
     778                }
     779        }
     780}
     781
    824782// Get the non-anonymous name of the instance type of the declaration,
    825783// if one exists.
     
    842800                try {
    843801                        bool extracted_named = false;
     802                        ast::UnionDecl * unionDecl = nullptr;
    844803
    845804                        if ( DeclarationNode * extr = cur->extractAggregate() ) {
    846805                                assert( cur->type );
     806                                nameTypedefedDecl( extr, cur );
    847807
    848808                                if ( ast::Decl * decl = extr->build() ) {
     809                                        // Remember the declaration if it is a union aggregate ?
     810                                        unionDecl = dynamic_cast<ast::UnionDecl *>( decl );
     811
    849812                                        *out++ = decl;
    850813
     
    865828
    866829                        if ( ast::Decl * decl = cur->build() ) {
     830                                moveUnionAttribute( decl, unionDecl );
     831
    867832                                if ( "" == decl->name && !cur->get_inLine() ) {
    868833                                        // Don't include anonymous declaration for named aggregates,
  • src/Parser/TypeData.cc

    r486caad rdf78cce  
    8888                aggregate.fields = nullptr;
    8989                aggregate.body = false;
     90                aggregate.tagged = false;
     91                aggregate.parent = nullptr;
    9092                aggregate.anon = false;
    9193                break;
     
    219221                newtype->aggregate.kind = aggregate.kind;
    220222                newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr;
     223                newtype->aggregate.parent = aggregate.parent ? new string( *aggregate.parent ) : nullptr;
    221224                newtype->aggregate.params = maybeCopy( aggregate.params );
    222225                newtype->aggregate.actuals = maybeCopy( aggregate.actuals );
     
    225228                newtype->aggregate.body = aggregate.body;
    226229                newtype->aggregate.anon = aggregate.anon;
     230                newtype->aggregate.tagged = aggregate.tagged;
    227231                break;
    228232        case AggregateInst:
  • src/Parser/TypeData.h

    r486caad rdf78cce  
    4848                ast::AggregateDecl::Aggregate kind;
    4949                const std::string * name = nullptr;
     50                const std::string * parent = nullptr;
    5051                DeclarationNode * params = nullptr;
    5152                ExpressionNode * actuals = nullptr;                             // holds actual parameters later applied to AggInst
     
    5455                bool body;
    5556                bool anon;
     57                bool tagged;
    5658        };
    5759
  • src/Parser/parser.yy

    r486caad rdf78cce  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Mar 16 18:19:23 2024
    13 // Update Count     : 6617
     12// Last Modified On : Mon Mar 11 18:30:03 2024
     13// Update Count     : 6589
    1414//
    1515
     
    485485%type<decl> elaborated_type elaborated_type_nobody
    486486
    487 %type<decl> enumerator_list enum_type enum_type_nobody enumerator_type
     487%type<decl> enumerator_list enum_type enum_type_nobody
    488488%type<init> enumerator_value_opt
    489489
     
    27422742
    27432743enum_type:
    2744                 // anonymous, no type name
    2745         ENUM attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
    2746                 {
    2747                         if ( $3 == EnumHiding::Hide ) {
    2748                                 SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr;
    2749                         } // if
    2750                         $$ = DeclarationNode::newEnum( nullptr, $5, true, false )->addQualifiers( $2 );
    2751                 }
    2752         | ENUM enumerator_type attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
    2753                 {
    2754                         if ( $2 && ($2->storageClasses.val != 0 || $2->type->qualifiers.any()) ) {
    2755                                 SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
    2756                         }
    2757                         if ( $4 == EnumHiding::Hide ) {
    2758                                 SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr;
    2759                         } // if
    2760                         $$ = DeclarationNode::newEnum( nullptr, $6, true, true, $2 )->addQualifiers( $3 );
    2761                 }
    2762 
    2763                 // named type
     2744        ENUM attribute_list_opt '{' enumerator_list comma_opt '}'
     2745                { $$ = DeclarationNode::newEnum( nullptr, $4, true, false )->addQualifiers( $2 ); }
     2746        | ENUM attribute_list_opt '!' '{' enumerator_list comma_opt '}' // invalid syntax rule
     2747                { SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
    27642748        | ENUM attribute_list_opt identifier
    27652749                { typedefTable.makeTypedef( *$3, "enum_type 1" ); }
     
    27682752        | ENUM attribute_list_opt typedef_name hide_opt '{' enumerator_list comma_opt '}' // unqualified type name
    27692753                { $$ = DeclarationNode::newEnum( $3->name, $6, true, false, nullptr, $4 )->addQualifiers( $2 ); }
    2770         | ENUM enumerator_type attribute_list_opt identifier attribute_list_opt
    2771                 {
    2772                         if ( $2 && ($2->storageClasses.any() || $2->type->qualifiers.val != 0) ) {
     2754        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
     2755                {
     2756                        if ( $3->storageClasses.val != 0 || $3->type->qualifiers.any() ) {
    27732757                                SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
    27742758                        }
    2775                         typedefTable.makeTypedef( *$4, "enum_type 2" );
     2759                        $$ = DeclarationNode::newEnum( nullptr, $7, true, true, $3 )->addQualifiers( $5 );
     2760                }
     2761        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '!' '{' enumerator_list comma_opt '}' // unqualified type name
     2762                { SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
     2763        | ENUM '(' ')' attribute_list_opt '{' enumerator_list comma_opt '}'
     2764                {
     2765                        $$ = DeclarationNode::newEnum( nullptr, $6, true, true )->addQualifiers( $4 );
     2766                }
     2767        | ENUM '(' ')' attribute_list_opt '!' '{' enumerator_list comma_opt '}' // invalid syntax rule
     2768                { SemanticError( yylloc, "syntax error, hiding ('!') the enumerator names of an anonymous enumeration means the names are inaccessible." ); $$ = nullptr; }
     2769        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
     2770                {
     2771                        if ( $3 && ($3->storageClasses.any() || $3->type->qualifiers.val != 0) ) {
     2772                                SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." );
     2773                        }
     2774                        typedefTable.makeTypedef( *$6, "enum_type 2" );
    27762775                }
    27772776          hide_opt '{' enumerator_list comma_opt '}'
    2778                 { $$ = DeclarationNode::newEnum( $4, $9, true, true, $2, $7 )->addQualifiers( $3 )->addQualifiers( $5 ); }
    2779         | ENUM enumerator_type attribute_list_opt typedef_name attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
    2780                 { $$ = DeclarationNode::newEnum( $4->name, $8, true, true, $2, $6 )->addQualifiers( $3 )->addQualifiers( $5 ); }
    2781 
    2782                 // forward declaration
     2777                {
     2778                        $$ = DeclarationNode::newEnum( $6, $11, true, true, $3, $9 )->addQualifiers( $5 )->addQualifiers( $7 );
     2779                }
     2780        | ENUM '(' ')' attribute_list_opt identifier attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
     2781                {
     2782                        $$ = DeclarationNode::newEnum( $5, $9, true, true, nullptr, $7 )->addQualifiers( $4 )->addQualifiers( $6 );
     2783                }
     2784        | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
     2785                {
     2786                        $$ = DeclarationNode::newEnum( $6->name, $10, true, true, $3, $8 )->addQualifiers( $5 )->addQualifiers( $7 );
     2787                }
     2788        | ENUM '(' ')' attribute_list_opt typedef_name attribute_list_opt hide_opt '{' enumerator_list comma_opt '}'
     2789                {
     2790                        $$ = DeclarationNode::newEnum( $5->name, $9, true, true, nullptr, $7 )->addQualifiers( $4 )->addQualifiers( $6 );
     2791                }
    27832792        | enum_type_nobody
    2784         ;
    2785 
    2786 enumerator_type:
    2787         '(' ')'                                                                                         // pure enumeration
    2788                 { $$ = nullptr; }
    2789         | '(' cfa_abstract_parameter_declaration ')'            // typed enumeration
    2790                 { $$ = $2; }
    27912793        ;
    27922794
  • src/main.cc

    r486caad rdf78cce  
    101101}
    102102
     103// Helpers for checkInvariant:
     104void checkInvariants( std::list< Declaration * > & ) {}
     105using ast::checkInvariants;
     106
    103107#define PASS( name, pass, unit, ... )       \
    104108        if ( errorp ) { cerr << name << endl; } \
     
    108112        Stats::Time::StopBlock();               \
    109113        if ( invariant ) {                      \
    110                 ast::checkInvariants(unit);         \
     114                checkInvariants(unit);              \
    111115        }
    112116
  • tests/.expect/ato.arm64.txt

    r486caad rdf78cce  
    33-123 -123
    44123 123
    5 -123 -123 
    6 123 123 
     5-123 -123
     6123 123
    77-123.456 -123.456
    88-123.456789012346 -123.4567890123456
    9 -123.45678901234567890123456789 -123.45678901234567890123456789 
     9-123.45678901234567890123456789 -123.45678901234567890123456789
    1010-123.456-123.456i -123.456-123.456i
    1111-123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i
    1212123.45678901234567890123456789-123.45678901234567890123456789i 123.45678901234567890123456789-123.45678901234567890123456789i
    13 123.45678901234-123.456789i 123.45678901234 -123.4567890i
     13123.45678901234-123.456789i 123.45678901234-123.4567890i
    1414-123 -123
    1515123 123
    1616-123 -123
    1717123 123
    18 -123 -123 
    19 123 123 
     18-123 -123
     19123 123
    2020-123.456 -123.456
    2121-123.456789012346 -123.4567890123456
    22 -123.45678901234567890123456789 -123.45678901234567890123456789 
     22-123.45678901234567890123456789 -123.45678901234567890123456789
    2323-123.456-123.456i -123.456-123.456i
    24 -123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i
    25 123.45678901234567890123456789-123.45678901234567890123456789i 123.45678901234567890123456789-123.45678901234567890123456789i
    26 123.45678901234-123.456789i 123.45678901234 -123.4567890i
    27 invalid argument 2.0fred
    28 invalid argument 2  3x
    29 -123 -123
    30 123 123
    31 -123 -123
    32 123 123
    33 -123 -123
    34 123 123
    35 -123.456 -123.456
    36 -123.456789012346 -123.4567890123456
    37 -123.45678901234567890123456789 -123.45678901234567890123456789
    38 -123.456-123.456i -123.456-123.456i
     240.+0.i 2  3
    3925-123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i
    4026123.45678901234567890123456789-123.45678901234567890123456789i 123.45678901234567890123456789-123.45678901234567890123456789i
    4127123.45678901234-123.456789i 123.45678901234-123.4567890i
    42 invalid argument 2.0fred
    43 invalid argument 2  3x
  • tests/.expect/ato.x64.txt

    r486caad rdf78cce  
    33-123 -123
    44123 123
    5 -123 -123 
    6 123 123 
     5-123 -123
     6123 123
    77-123.456 -123.456
    88-123.456789012346 -123.4567890123456
    9 -123.456789012345679 -123.45678901234567890123456789 
     9-123.456789012345679 -123.45678901234567890123456789
    1010-123.456-123.456i -123.456-123.456i
    1111-123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i
    1212123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i
    13 123.45678901234-123.456789i 123.45678901234 -123.4567890i
     13123.45678901234-123.456789i 123.45678901234-123.4567890i
    1414-123 -123
    1515123 123
    1616-123 -123
    1717123 123
    18 -123 -123 
    19 123 123 
     18-123 -123
     19123 123
    2020-123.456 -123.456
    2121-123.456789012346 -123.4567890123456
    22 -123.456789012345679 -123.45678901234567890123456789 
     22-123.456789012345679 -123.45678901234567890123456789
    2323-123.456-123.456i -123.456-123.456i
    24 -123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i
    25 123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i
    26 123.45678901234-123.456789i 123.45678901234 -123.4567890i
    27 invalid argument 2.0fred
    28 invalid argument 2  3x
    29 -123 -123
    30 123 123
    31 -123 -123
    32 123 123
    33 -123 -123
    34 123 123
    35 -123.456 -123.456
    36 -123.456789012346 -123.4567890123456
    37 -123.456789012345679 -123.45678901234567890123456789
    38 -123.456-123.456i -123.456-123.456i
     240.+0.i 2  3
    3925-123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i
    4026123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i
    4127123.45678901234-123.456789i 123.45678901234-123.4567890i
    42 invalid argument 2.0fred
    43 invalid argument 2  3x
  • tests/.expect/ato.x86.txt

    r486caad rdf78cce  
    33-123 -123
    44123 123
    5 -123 -123 
    6 123 123 
     5-123 -123
     6123 123
    77-123.456 -123.456
    88-123.456789012346 -123.4567890123456
    9 -123.456789012345679 -123.45678901234567890123456789 
     9-123.456789012345679 -123.45678901234567890123456789
    1010-123.456-123.456i -123.456-123.456i
    1111-123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i
    1212123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i
    13 123.45678901234-123.456789i 123.45678901234 -123.4567890i
     13123.45678901234-123.456789i 123.45678901234-123.4567890i
    1414-123 -123
    1515123 123
    1616-123 -123
    1717123 123
    18 -123 -123 
    19 123 123 
     18-123 -123
     19123 123
    2020-123.456 -123.456
    2121-123.456789012346 -123.4567890123456
    22 -123.456789012345679 -123.45678901234567890123456789 
     22-123.456789012345679 -123.45678901234567890123456789
    2323-123.456-123.456i -123.456-123.456i
    24 -123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i
    25 123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i
    26 123.45678901234-123.456789i 123.45678901234 -123.4567890i
    27 invalid argument 2.0fred
    28 invalid argument 2  3x
    29 -123 -123
    30 123 123
    31 -123 -123
    32 123 123
    33 -123 -123
    34 123 123
    35 -123.456 -123.456
    36 -123.456789012346 -123.4567890123456
    37 -123.456789012345679 -123.45678901234567890123456789
    38 -123.456-123.456i -123.456-123.456i
     240.+0.i 2  3
    3925-123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i
    4026123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i
    4127123.45678901234-123.456789i 123.45678901234-123.4567890i
    42 invalid argument 2.0fred
    43 invalid argument 2  3x
  • tests/ato.cfa

    r486caad rdf78cce  
    1010// Created On       : Thu Feb  4 08:10:57 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 15 17:58:35 2024
    13 // Update Count     : 145
     12// Last Modified On : Tue Dec  4 21:33:53 2018
     13// Update Count     : 92
    1414//
    1515
     
    1818
    1919int main( void ) {
    20         // ato
    21 
    2220        const char * sptr = "-123";
    2321        int i = ato( sptr );
     
    3432        sout | uli | sptr;
    3533
    36         sptr = " -123 ";                                                                        // spaces allowed
     34        sptr = "-123";
    3735        long long int lli = ato( sptr );
    3836        sout | lli | sptr;
    39         sptr = " 123 ";                                                                         // spaces allowed
     37        sptr = "123";
    4038        unsigned long long int ulli = ato( sptr );
    4139        sout | ulli | sptr;
     
    4745        double d = ato( sptr );
    4846        sout | d | sptr;
    49         sptr = " -123.45678901234567890123456789 ";                     // spaces allowed
     47        sptr = "-123.45678901234567890123456789";
    5048        long double ld = ato( sptr );
    5149        sout | ld | sptr;
     
    6058        long double _Complex ldc = ato( sptr );
    6159        sout | ldc | sptr;
    62         sptr = " 123.45678901234 -123.4567890i ";                       // spaces allowed
     60        sptr = "123.45678901234-123.4567890i";
    6361        long double _Complex ldc2 = ato( sptr );
    6462        sout | ldc2 | sptr;
    6563
    66         // strto
    6764
    6865        sptr = "-123";
    69         i = strto( sptr, 0p, 10 );
     66        i = strto( sptr, 0, 10 );
    7067        sout | i | sptr;
    7168        sptr = "123";
    72         ui = strto( sptr, 0p, 10 );
     69        ui = strto( sptr, 0, 10 );
    7370        sout | ui | sptr;
    7471
    7572        sptr = "-123";
    76         li = strto( sptr, 0p, 10 );
     73        li = strto( sptr, 0, 10 );
    7774        sout | li | sptr;
    7875        sptr = "123";
    79         uli = strto( sptr, 0p, 10 );
     76        uli = strto( sptr, 0, 10 );
    8077        sout | uli | sptr;
    8178
    82         sptr = " -123 ";                                                                        // spaces allowed
    83         lli = strto( sptr, 0p, 10 );
     79        sptr = "-123";
     80        lli = strto( sptr, 0, 10 );
    8481        sout | lli | sptr;
    85         sptr = " 123 ";                                                                         // spaces allowed
    86         ulli = strto( sptr, 0p, 10 );
     82        sptr = "123";
     83        ulli = strto( sptr, 0, 10 );
    8784        sout | ulli | sptr;
    8885
    8986        sptr = "-123.456";
    90         f = strto( sptr, 0p );
     87        f = strto( sptr, 0 );
    9188        sout | f | sptr;
    9289        sptr = "-123.4567890123456";
    93         d = strto( sptr, 0p );
     90        d = strto( sptr, 0 );
    9491        sout | d | sptr;
    95         sptr = " -123.45678901234567890123456789 ";                     // spaces allowed
    96         ld = strto( sptr, 0p );
     92        sptr = "-123.45678901234567890123456789";
     93        ld = strto( sptr, 0 );
    9794        sout | ld | sptr;
    9895
    9996        sptr = "-123.456-123.456i";
    100         fc = strto( sptr, 0p );
     97        fc = strto( sptr, 0 );
    10198        sout | fc | sptr;
     99
     100        char * eptr = 0;
     101        // sptr = "2fred";
     102        // fc = strto( sptr, &eptr );
     103        // sout | fc | sptr | eptr;
     104
     105        sptr = "2  3";
     106        fc = strto( sptr, &eptr );
     107        sout | fc | sptr | eptr;
     108
    102109        sptr = "-123.4567890123456+123.4567890123456i";
    103         dc = strto( sptr, 0p );
     110        dc = strto( sptr, 0 );
    104111        sout | dc | sptr;
    105112        sptr = "123.45678901234567890123456789-123.45678901234567890123456789i";
    106         ldc = strto( sptr, 0p );
    107         sout | ldc | sptr;
    108         sptr = " 123.45678901234 -123.4567890i ";                       // spaces allowed
    109         ldc2 = strto( sptr, 0p );
    110         sout | ldc2 | sptr;
    111 
    112         sptr = "2.0fred";
    113         char * eptr = 0p;
    114         errno = 0;                                                                                      // reset
    115         f = strto( sptr, &eptr );
    116         if ( errno == ERANGE ) sout | "out of range";
    117         if ( eptr == sptr ||                                                            // conversion failed, no characters generated
    118                  *eptr != '\0' ) sout | "invalid argument" | sptr; // not at end of str ?
    119         else assert( false );
    120 
    121         sptr = "2  3x";
    122         eptr = 0p;
    123         errno = 0;                                                                                      // reset
    124         fc = strto( sptr, &eptr );
    125         if ( errno == ERANGE ) sout | "out of range";
    126         if ( eptr == sptr ||                                                            // conversion failed, no characters generated
    127                  *eptr != '\0' ) sout | "invalid argument" | sptr; // not at end of str ?
    128         else assert( false );
    129 
    130         // convert
    131 
    132         sptr = "-123";
    133         i = convert( sptr );
    134         sout | i | sptr;
    135         sptr = "123";
    136         ui = convert( sptr );
    137         sout | ui | sptr;
    138 
    139         sptr = "-123";
    140         li = convert( sptr );
    141         sout | li | sptr;
    142         sptr = "123";
    143         uli = convert( sptr );
    144         sout | uli | sptr;
    145 
    146         sptr = " -123 ";                                                                        // spaces allowed
    147         lli = convert( sptr );
    148         sout | lli | sptr;
    149         sptr = " 123 ";                                                                         // spaces allowed
    150         ulli = convert( sptr );
    151         sout | ulli | sptr;
    152 
    153         sptr = "-123.456";
    154         f = convert( sptr );
    155         sout | f | sptr;
    156         sptr = "-123.4567890123456";
    157         d = convert( sptr );
    158         sout | d | sptr;
    159         sptr = " -123.45678901234567890123456789 ";                     // spaces allowed
    160         ld = convert( sptr );
    161         sout | ld | sptr;
    162 
    163         sptr = "-123.456-123.456i";
    164         fc = convert( sptr );
    165         sout | fc | sptr;
    166         sptr = "-123.4567890123456+123.4567890123456i";
    167         dc = convert( sptr );
    168         sout | dc | sptr;
    169         sptr = "123.45678901234567890123456789-123.45678901234567890123456789i";
    170         ldc = convert( sptr );
     113        ldc = strto( sptr, 0 );
    171114        sout | ldc | sptr;
    172115        sptr = "123.45678901234-123.4567890i";
    173         ldc2 = convert( sptr );
     116        ldc2 = strto( sptr, 0 );
    174117        sout | ldc2 | sptr;
    175 
    176         sptr = "2.0fred";
    177         try {
    178                 f = convert( sptr );
    179                 assert( false );
    180         } catch( invalid_argument * ) {
    181                 sout | "invalid argument" | sptr;
    182         } // try
    183 
    184         sptr = "2  3x";
    185         try {
    186                 fc = convert( sptr );
    187                 assert( false );
    188         } catch( invalid_argument * ) {
    189                 sout | "invalid argument" | sptr;
    190         } // try
    191118} // main
    192119
Note: See TracChangeset for help on using the changeset viewer.