Changes in / [486caad:df78cce]
- Files:
-
- 1 deleted
- 22 edited
-
doc/bibliography/pl.bib (modified) (10 diffs)
-
doc/papers/general/SPE_CforallModernFeatures.pdf (deleted)
-
doc/theses/jiada_liang_MMath/CFAenum.tex (modified) (10 diffs)
-
doc/theses/jiada_liang_MMath/background.tex (modified) (2 diffs)
-
doc/theses/jiada_liang_MMath/implementation.tex (modified) (1 diff)
-
doc/theses/jiada_liang_MMath/intro.tex (modified) (1 diff)
-
doc/theses/jiada_liang_MMath/relatedwork.tex (modified) (24 diffs)
-
doc/theses/mike_brooks_MMath/array.tex (modified) (1 diff)
-
doc/theses/mike_brooks_MMath/background.tex (modified) (2 diffs)
-
doc/theses/mike_brooks_MMath/intro.tex (modified) (2 diffs)
-
doc/theses/mike_brooks_MMath/uw-ethesis.tex (modified) (1 diff)
-
libcfa/src/stdlib.cfa (modified) (4 diffs)
-
libcfa/src/stdlib.hfa (modified) (3 diffs)
-
src/CodeGen/CodeGenerator.cpp (modified) (1 diff)
-
src/Parser/DeclarationNode.cc (modified) (8 diffs)
-
src/Parser/TypeData.cc (modified) (3 diffs)
-
src/Parser/TypeData.h (modified) (2 diffs)
-
src/Parser/parser.yy (modified) (4 diffs)
-
src/main.cc (modified) (2 diffs)
-
tests/.expect/ato.arm64.txt (modified) (1 diff)
-
tests/.expect/ato.x64.txt (modified) (1 diff)
-
tests/.expect/ato.x86.txt (modified) (1 diff)
-
tests/ato.cfa (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
doc/bibliography/pl.bib
r486caad rdf78cce 1263 1263 school = {School of Computer Science, University of Waterloo}, 1264 1264 year = 2019, 1265 address = {Waterloo, Ontario, Canada, N2L 3G1},1265 optaddress = {Waterloo, Ontario, Canada, N2L 3G1}, 1266 1266 note = {\url{https://uwspace.uwaterloo.ca/handle/10012/14584}}, 1267 1267 } … … 1955 1955 school = {School of Computer Sc., University of Waterloo}, 1956 1956 year = 2015, 1957 address = {Waterloo, Ontario, Canada, N2L 3G1},1957 optaddress = {Waterloo, Ontario, Canada, N2L 3G1}, 1958 1958 note = {\url{https://uwspace.uwaterloo.ca/handle/10012/10013}}, 1959 1959 } … … 4130 4130 school = {School of Computer Sc., University of Waterloo}, 4131 4131 year = 2019, 4132 address = {Waterloo, Ontario, Canada, N2L 3G1},4132 optaddress = {Waterloo, Ontario, Canada, N2L 3G1}, 4133 4133 note = {\url{https://uwspace.uwaterloo.ca/handle/10012/14706}}, 4134 4134 } … … 4323 4323 school = {School of Computer Science, University of Waterloo}, 4324 4324 year = 2003, 4325 address = {Waterloo, Ontario, Canada, N2L 3G1},4325 optaddress = {Waterloo, Ontario, Canada, N2L 3G1}, 4326 4326 note = {\url{http://plg.uwaterloo.ca/theses/BilsonThesis.pdf}}, 4327 4327 } … … 4364 4364 year = 2018, 4365 4365 month = sep, 4366 address = {Waterloo, Ontario, Canada, N2L 3G1},4366 optaddress = {Waterloo, Ontario, Canada, N2L 3G1}, 4367 4367 note = {\url{https://uwspace.uwaterloo.ca/handle/10012/13935}}, 4368 4368 } … … 5990 5990 key = {OCaml}, 5991 5991 title = {The {OC}aml system, release 5.1}, 5992 address = {Rust Project Developers},5992 optaddress = {Rust Project Developers}, 5993 5993 year = 2023, 5994 5994 note = {\url{https://v2.ocaml.org/manual/}}, … … 7007 7007 organization= {United States Department of Defense}, 7008 7008 edition = {{ANSI/MIL-STD-1815A-1983}}, 7009 address = {Springer, New York},7010 7009 month = feb, 7011 7010 year = 1983, 7011 note = {Springer, New York}, 7012 7012 } 7013 7013 … … 7421 7421 school = {School of Computer Science, University of Waterloo}, 7422 7422 year = 2017, 7423 address = {Waterloo, Ontario, Canada, N2L 3G1},7423 optaddress = {Waterloo, Ontario, Canada, N2L 3G1}, 7424 7424 note = {\url{https://uwspace.uwaterloo.ca/handle/10012/11830}}, 7425 7425 } … … 7508 7508 key = {Rust}, 7509 7509 title = {{R}ust Programming Language}, 7510 address = {Rust Project Developers},7510 optaddress = {Rust Project Developers}, 7511 7511 year = 2015, 7512 7512 note = {\url{https://doc.rust-lang.org/reference.html}}, … … 7729 7729 publisher = {Morgan \& Claypool}, 7730 7730 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}, 7731 7753 } 7732 7754 -
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. 5 5 \CFA also extends C-Style enumeration by adding a number of new features that bring enumerations inline with other modern programming languages. 6 6 … … 16 16 Finally, qualification is provided to disambiguate any ambiguous situations. 17 17 \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; }18 enum C1 { First, Second, Third, Fourth }; 19 enum C2 { @Fourth@, @Third@, @Second@, @First@ }; 20 C1 p() { return Third; } $\C{// correctly resolved duplicate names}$ 21 C2 p() { return Fourth; } 22 22 void foo() { 23 E1 e1 = First; E2 e2 = First;23 C1 e1 = First; C2 e2 = First; 24 24 e1 = Second; e2 = Second; 25 25 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. 32 30 33 31 … … 36 34 An enumeration can be scoped, so the enumerator constants are not projected into the enclosing scope, using @'!'@. 37 35 \begin{cfa} 38 enum Weekday @!@ { Mon, Tue, Wed, Thu = 10, Fri, Sat, Sun};39 enum RGB @!@ { Red, Green, Blue};36 enum Weekday @!@ { /* as above */ }; 37 enum( char * ) Names @!@ { /* as above */ }; 40 38 \end{cfa} 41 39 Now the enumerators \emph{must} be qualified with the associated enumeration. 42 40 \begin{cfa} 43 Weekday weekday = @Weekday@.Mon; 44 weekday = @Weekday@.Sat; 45 RGB rgb = RGB.Red; 46 rgb = RGB.Blue; 41 Weekday weekday = @Weekday@.Monday; 42 Names names = @Names.@Fred; 43 names = @Names.@Jane; 47 44 \end{cfa} 48 45 It 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}). 49 46 \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. 47 Weekday weekday; 48 with ( @Weekday@, @Names@ ) { $\C{// type names}$ 49 Names names = @Fred@; 50 names = @Jane@; 51 weekday = Saturday; 52 } 53 \end{cfa} 54 As 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. 56 55 57 56 \section{Enumerator Typing} … … 81 80 \begin{cfa} 82 81 // 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$' }; 84 83 enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 }; 85 84 enum( @long long int@ ) BigNum { X = 123_456_789_012_345, Y = 345_012_789_456_123 }; … … 88 87 enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i }; 89 88 // pointer 90 enum( @c onst char *@ ) Name{ Fred = "FRED", Mary = "MARY", Jane = "JANE" };89 enum( @char *@ ) Names { Fred = "FRED", Mary = "MARY", Jane = "JANE" }; 91 90 int i, j, k; 92 91 enum( @int *@ ) ptr { I = &i, J = &j, K = &k }; … … 99 98 // aggregate 100 99 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 } }; 103 101 \end{cfa} 104 102 \caption{Enumerator Typing} … … 142 140 \begin{cfa} 143 141 enum() 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; 143 bool b = iomode == O_RDONLY || iomode < O_APPEND; 144 int i = iomode; $\C{\color{red}// disallowed}$ 147 145 \end{cfa} 148 146 … … 151 149 If follows from enumerator typing that the enumerator type can be another enumerator. 152 150 \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 };151 enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$' }; 152 enum( @Currency@ ) Europe { Euro = Currency.Euro, Pound = Currency.Pound }; // intersection 155 153 enum( char ) Letter { A = 'A', B = 'B', C = 'C', ..., Z = 'Z' }; 156 154 enum( @Letter@ ) Greek { Alph = A, Beta = B, ..., Zeta = Z }; // intersection … … 160 158 \begin{cfa} 161 159 Letter letter = A; 162 Greak greek = Beta;163 letter = Beta; $\C{// allowed, greek== B}$164 @greek = A;@ $\C{// disallowed}$160 @***@Greak greek = Beta; 161 letter = Beta; $\C{// allowed, letter == B}$ 162 greek = A; $\C{\color{red}// disallowed}$ 165 163 \end{cfa} 166 164 … … 279 277 p(variable_d); // 3 280 278 \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 radius296 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 1 1 \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 010 static const int Mon = 0;11 enum { Mon };12 \end{clang}13 \begin{enumerate}[leftmargin=*]14 \item15 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 \item18 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.o22 0000000000000018 r Mon23 \end{clang}24 \item25 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}27 2 28 3 29 \section{C \lstinline{const}}4 \section{C-Style Enum} 30 5 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} 6 The C-Style enumeration has the following syntax and semantics. 7 \begin{cfa} 8 enum Weekday { Monday, Tuesday, Wednesday, Thursday@ = 10@, Friday, Saturday, Sunday }; 9 \end{cfa} 55 10 Enumerators 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@.11 For 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@. 57 12 Initialization may occur in any order. 58 \begin{c lang}59 enum Weekday { Thu @ = 10@, Fri, Sat, Sun, Mon@ = 0@, Tue, Wed};60 \end{c lang}13 \begin{cfa} 14 enum Weekday { Thursday@ = 10@, Friday, Saturday, Sunday, Monday@ = 0@, Tuesday, Wednesday }; 15 \end{cfa} 61 16 Note, the comma in the enumerator list can be a terminator or a separator, allowing the list to end with a dangling comma. 62 \begin{c lang}17 \begin{cfa} 63 18 enum Weekday { 64 Thu = 10, Fri, Sat, Sun,65 Mon = 0, Tue, Wed@,@ // terminating comma19 Thursday = 10, Friday, Saturday, Sunday, 20 Monday = 0, Tuesday, Wednesday@,@ // terminating comma 66 21 }; 67 \end{c lang}22 \end{cfa} 68 23 This feature allow enumerator lines to be interchanged without moving a comma.\footnote{ 69 24 A terminating comma appears in other C syntax, \eg the initializer list.} … … 73 28 In 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. 74 29 Finally, there is an implicit bidirectional conversion between an enumeration and its integral type. 75 \begin{c lang}30 \begin{cfa} 76 31 { 77 32 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}$ 81 36 weekday = 10000; $\C{// UNDEFINED! implicit conversion to Weekday}$ 82 37 } 83 int j = Wed ; $\C{// ERROR! Wedis not declared in this scope}$84 \end{c lang}38 int j = Wednesday; $\C{// ERROR! Wednesday is not declared in this scope}$ 39 \end{cfa} 85 40 The implicit conversion from @int@ to an enumeration type is an unnecessary source of error. 41 42 It is common for C programmers to ``believe'' there are 3 equivalent forms of constant enumeration. 43 \begin{cfa} 44 #define Monday 0 45 static const int Monday = 0; 46 enum { Monday }; 47 \end{cfa} 48 For @#define@, the programmer has to play compiler and explicitly manage the enumeration values; 49 furthermore, these are independent constants outside of any language type mechanism. 50 The same explicit management is true for @const@ declarations, and the @const@ variable cannot appear in constant-expression locations, like @case@ labels, array dimensions,\footnote{ 51 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++}.} and immediate operands of assembler instructions. 52 Only 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 548 548 \begin{cfa} 549 549 enum(int) Weekday { 550 Mon = 10, Tue, ...550 Monday=10, Tuesday, ... 551 551 }; 552 552 -
doc/theses/jiada_liang_MMath/intro.tex
r486caad rdf78cce 1 1 \chapter{Introduction} 2 2 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. 3 Naming values is a common practice in mathematics and engineering, \eg $\pi$, $\tau$ (2$\pi$), $\phi$ (golden ratio), MHz (1E6), etc. 4 Naming 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). 5 Many programming languages capture this important software engineering capability through a mechanism called an \Newterm{enumeration}. 6 An 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. 7 Note, all enumeration names must be unique but different names can represent the same value (eight note, quaver), which are synonyms. 7 8 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.}. 9 Specifically, an enumerated type restricts its values to a fixed set of named constants. 10 While 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. 14 11 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}. 12 Fundamentally, all enumeration systems have an \Newterm{enumeration} type with an associated set of \Newterm{enumerator} names. 13 An 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. 47 14 \begin{cquote} 48 \s f\setlength{\tabcolsep}{3pt}49 \begin{tabular}{rccccccc r}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 56 23 \end{tabular} 57 24 \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 25 Here, the \Newterm{enumeration} @Weekday@ defines the ordered \Newterm{enumerator}s @Monday@, @Tuesday@, @Wednesday@, @Thursday@, @Friday@, @Saturday@ and @Sunday@. 26 By convention, the successor of @Tuesday@ is @Monday@ and the predecessor of @Tuesday@ is @Wednesday@, independent of the associated enumerator constant values. 27 Because 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{ 28 The term rvalue defines an expression that can only appear on the right-hand side of an assignment.}. 162 29 163 30 \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 \item171 overloading172 \item173 scoping174 \item175 typing176 \item177 subset178 \item179 inheritance180 \end{enumerate} -
doc/theses/jiada_liang_MMath/relatedwork.tex
r486caad rdf78cce 2 2 \label{s:RelatedWork} 3 3 4 \begin{comment}5 4 An algebraic data type (ADT) can be viewed as a recursive sum of product types. 6 5 A sum type lists values as members. … … 16 15 Enumerated 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. 17 16 Values of algebraic types are access by subscripting, field qualification, or type (pattern) matching. 18 \end{comment}19 17 20 18 Enumeration 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}. … … 22 20 23 21 \section{Pascal} 24 \label{s:Pascal}25 22 \lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{} 26 23 … … 30 27 PI = 3.14159; Plus = '+'; Fred = 'Fred'; 31 28 \end{pascal} 32 This mechanism is not anenumeration because there is no specific type (pseudo enumeration).29 Here, there is no enumeration because there is no specific type (pseudo enumeration). 33 30 Hence, there is no notion of a (possibly ordered) set, modulo the \lstinline[language=pascal]{set of} type. 34 31 The type of each constant name (enumerator) is inferred from the constant-expression type. … … 84 81 with Ada.Text_IO; use Ada.Text_IO; 85 82 procedure test is 86 type RGB is ( @Red@, Green, Blue );87 type Traffic_Light is ( @Red@, Yellow, Green ); -- overload88 procedure @Red@( Colour : RGB ) is begin -- overload89 Put_Line( "Colour is " & RGB'Image( Colour ) );90 end Red;91 procedure @Red@( TL : Traffic_Light ) is begin -- overload92 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; 94 91 begin 95 @Red@( Blue ); -- RGB96 @Red@( Yellow ); -- Traffic_Light97 @Red@( @RGB'(Red)@ ); -- ambiguous without cast92 @Red@( Blue ); -- RGB 93 @Red@( Yellow ); -- Traffic_Light 94 @Red@( @RGB'(Red)@ ); -- ambiguous without cast 98 95 end test; 99 96 \end{ada} … … 227 224 \lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{} 228 225 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. 227 However, the following non-backwards compatible changes have been made. 252 228 253 229 \begin{cquote} … … 447 423 \begin{Go} 448 424 const ( Mon = iota; Tue; Wed; // 0, 1, 2 449 @Thu = 10@; Fri; Sat; Sun ) // 10, 10, 10, 10425 @Thu = 10@; Fri; Sat; Sun ) // 10, 10, 10, 10 450 426 \end{Go} 451 427 Auto-incrementing can be restarted with an expression containing \emph{one} \lstinline[language=Go]{iota}. … … 453 429 const ( V1 = iota; V2; @V3 = 7;@ V4 = @iota@; V5 ) // 0 1 7 3 4 454 430 const ( Mon = iota; Tue; Wed; // 0, 1, 2 455 @Thu = 10;@ Fri = @iota - Wed + Thu - 1@; Sat; Sun ) // 10, 11, 12, 13431 @Thu = 10;@ Fri = @iota - Wed + Thu - 1@; Sat; Sun ) // 10, 11, 12, 13 456 432 \end{Go} 457 433 Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier. … … 608 584 \lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{} 609 585 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. 586 Enumerations 613 587 \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 617 607 \end{rust} 618 A field-less enumeration with only unit variants is called unit-only. 608 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. 609 610 Enumerations are declared with the keyword enum. 611 612 An example of an enum item and its use: 619 613 \begin{rust} 620 enum Week { Mon = 0, Tues = 1, Wed = 2, Thu = 3, Fri = 4, Sat = 5, Sun = 6 } 614 enum Animal { 615 Dog, 616 Cat, 617 } 618 619 let mut a: Animal = Animal::Dog; 620 a = Animal::Cat; 621 621 \end{rust} 622 622 Enum constructors can have either named or unnamed fields: 623 623 \begin{rust} 624 624 enum Animal { 625 Dog( String, f64 ), 626 Cat{ name: String, weight: f64 }, 627 } 625 Dog(String, f64), 626 Cat { name: String, weight: f64 }, 627 } 628 628 629 let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2); 629 630 a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 }; 630 631 \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. 632 In this example, Cat is a struct-like enum variant, whereas Dog is simply called an enum variant. 633 634 An enum where no constructors contain fields are called a field-less enum. For example, this is a fieldless enum: 644 635 \begin{rust} 645 if mem::discriminant(&week) == mem::discriminant(&Week::Mon) ... 636 enum Fieldless { 637 Tuple(), 638 Struct{}, 639 Unit, 640 } 646 641 \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.642 If a field-less enum only contains unit variants, the enum is called an unit-only enum. For example: 648 643 \begin{rust} 649 if week as isize == Week::Mon as isize ... 644 enum Enum { 645 Foo = 3, 646 Bar = 2, 647 Baz = 1, 648 } 649 \end{rust} 650 651 \subsection{Discriminants} 652 653 Each enum instance has a discriminant: an integer logically associated to it that is used to determine which variant it holds. 654 655 Under 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 661 In 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 680 If 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} 682 enum Foo { 683 Bar, // 0 684 Baz = 123, // 123 685 Quux, // 124 686 } 687 688 let baz_discriminant = Foo::Baz as u32; 689 assert_eq!(baz_discriminant, 123); 690 \end{rust} 691 692 \subsection{Restrictions} 693 694 It is an error when two variants share the same discriminant. 695 \begin{rust} 696 enum SharedDiscriminantError { 697 SharedA = 1, 698 SharedB = 1 699 } 700 701 enum SharedDiscriminantError2 { 702 Zero, // 0 703 One, // 1 704 OneToo = 1 // 1 (collision with previous!) 705 } 706 \end{rust} 707 It 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)] 710 enum OverflowingDiscriminantError { 711 Max = 255, 712 MaxPlusOne // Would be 256, but that overflows the enum. 713 } 714 715 #[repr(u8)] 716 enum 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} 726 Via 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 732 If 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} 734 enum Enum { 735 Foo, 736 Bar, 737 Baz, 738 } 739 740 assert_eq!(0, Enum::Foo as isize); 741 assert_eq!(1, Enum::Bar as isize); 742 assert_eq!(2, Enum::Baz as isize); 743 \end{rust} 744 Field-less enums can be casted if they do not have explicit discriminants, or where only unit variants are explicit. 745 \begin{rust} 746 enum Fieldless { 747 Tuple(), 748 Struct{}, 749 Unit, 750 } 751 752 assert_eq!(0, Fieldless::Tuple() as isize); 753 assert_eq!(1, Fieldless::Struct{} as isize); 754 assert_eq!(2, Fieldless::Unit as isize); 755 \end{rust} 756 \begin{rust} 757 #[repr(u8)] 758 enum FieldlessWithDiscrimants { 759 First = 10, 760 Tuple(), 761 Second = 20, 762 Struct{}, 763 Unit, 764 } 765 766 assert_eq!(10, FieldlessWithDiscrimants::First as u8); 767 assert_eq!(11, FieldlessWithDiscrimants::Tuple() as u8); 768 assert_eq!(20, FieldlessWithDiscrimants::Second as u8); 769 assert_eq!(21, FieldlessWithDiscrimants::Struct{} as u8); 770 assert_eq!(22, FieldlessWithDiscrimants::Unit as u8); 771 \end{rust} 772 773 \subsection{Pointer casting} 774 775 If the enumeration specifies a primitive representation, then the discriminant may be reliably accessed via unsafe pointer casting: 776 \begin{rust} 777 #[repr(u8)] 778 enum Enum { 779 Unit, 780 Tuple(bool), 781 Struct{a: bool}, 782 } 783 784 impl Enum { 785 fn discriminant(&self) -> u8 { 786 unsafe { *(self as *const Self as *const u8) } 787 } 788 } 789 790 let unit_like = Enum::Unit; 791 let tuple_like = Enum::Tuple(true); 792 let struct_like = Enum::Struct{a: false}; 793 794 assert_eq!(0, unit_like.discriminant()); 795 assert_eq!(1, tuple_like.discriminant()); 796 assert_eq!(2, struct_like.discriminant()); 797 \end{rust} 798 799 \subsection{Zero-variant enums} 800 801 Enums with zero variants are known as zero-variant enums. As they have no valid values, they cannot be instantiated. 802 \begin{rust} 803 enum ZeroVariants {} 804 \end{rust} 805 Zero-variant enums are equivalent to the never type, but they cannot be coerced into other types. 806 \begin{rust} 807 let x: ZeroVariants = panic!(); 808 let y: u32 = x; // mismatched type error 809 \end{rust} 810 811 \subsection{Variant visibility} 812 813 Enum 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} 815 macro_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. 828 mac_variant! { E } 829 830 // This is allowed, since it is removed before being validated. 831 #[cfg(FALSE)] 832 enum E { 833 pub U, 834 pub(crate) T(u8), 835 pub(super) T { f: String } 836 } 650 837 \end{rust} 651 838 … … 1013 1200 \lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{} 1014 1201 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} 1202 An @Enum@ is a set of symbolic names bound to unique values. 1203 They are similar to global variables, but they offer a more useful @repr()@, grouping, type-safety, and a few other features. 1204 1205 They 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} 1217 Or 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} 1225 As you can see, creating an @Enum@ is as simple as writing a class that inherits from @Enum@ itself. 1226 1227 Note: Case of Enum Members 1228 1229 Because 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. 1022 1230 1023 1231 Depending on the nature of the enum a member's value may or may not be important, but either way that value can be used to get the corresponding member: 1024 1232 \begin{python} 1025 print( repr( Weekday( 3 ) ))1026 <Weekday.W ed: 3>1233 >>> Weekday(3) 1234 <Weekday.WEDNESDAY: 3> 1027 1235 \end{python} 1028 1236 As you can see, the @repr()@ of a member shows the enum name, the member name, and the value. 1029 1237 The @str()@ of a member shows only the enum name and member name: 1030 1238 \begin{python} 1031 print( str( Weekday.Thu ), Weekday.Thu)1032 Weekday.T hu Weekday.Thu1239 print(Weekday.THURSDAY) 1240 Weekday.THURSDAY 1033 1241 \end{python} 1034 1242 The type of an enumeration member is the enum it belongs to: 1035 1243 \begin{python} 1036 print( type( Weekday.Thu ))1244 >>> type(Weekday.MONDAY) 1037 1245 <enum 'Weekday'> 1038 print( isinstance(Weekday.Fri, Weekday))1246 isinstance(Weekday.FRIDAY, Weekday) 1039 1247 True 1040 1248 \end{python} 1041 1249 Enum members have an attribute that contains just their name: 1042 1250 \begin{python} 1043 print(Weekday.TUESDAY.name)1251 >>> print(Weekday.TUESDAY.name) 1044 1252 TUESDAY 1045 1253 \end{python} 1046 1254 Likewise, they have an attribute for their value: 1047 1255 \begin{python} 1048 Weekday.WEDNESDAY.value1256 >>> Weekday.WEDNESDAY.value 1049 1257 3 1050 1258 \end{python} 1051 1052 1259 Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added. 1053 1260 For example, @datetime.date@ has two methods for returning the weekday: @weekday()@ and @isoweekday()@. … … 1055 1262 Rather than keep track of that ourselves we can add a method to the @Weekday@ enum to extract the day from the date instance and return the matching enum member: 1056 1263 \begin{python} 1057 class Weekday(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = 15; Sat = 16; Sun = 171058 1264 $@$classmethod 1059 1265 def from_date(cls, date): 1060 return cls(date.isoweekday()) 1266 return cls(date.isoweekday()) 1267 \end{python} 1268 The 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()) 1061 1282 \end{python} 1062 1283 Now we can find out what today is! Observe: … … 1070 1291 This Weekday enum is great if our variable only needs one day, but what if we need several? Maybe we're writing a function to plot chores during a week, and don't want to use a @list@ -- we could use a different type of @Enum@: 1071 1292 \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 1074 1302 \end{python} 1075 1303 We've changed two things: we're inherited from @Flag@, and the values are all powers of 2. 1076 1304 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> 1305 Just 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} 1311 But @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> 1081 1316 \end{python} 1082 1317 You can even iterate over a @Flag@ variable: 1083 1318 \begin{python} 1084 for day in weekend:1085 print(day)1319 >>> for day in weekend: 1320 ... print(day) 1086 1321 Weekday.SATURDAY 1087 1322 Weekday.SUNDAY … … 1147 1382 \subsection{Duplicating enum members and values} 1148 1383 1149 An enum member can have other names associated with it. 1384 Having two enum members with the same name is invalid: 1385 \begin{python} 1386 >>> class Shape(Enum): 1387 ... SQUARE = 2 1388 ... SQUARE = 3 1389 ... 1390 Traceback (most recent call last): 1391 ... 1392 TypeError: 'SQUARE' already defined as 2 1393 \end{python} 1394 However, an enum member can have other names associated with it. 1150 1395 Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@. 1151 1396 By-value lookup of the value of @A@ will return the member @A@. … … 1153 1398 By-name lookup of @B@ will also return the member @A@: 1154 1399 \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 ... 1156 1406 >>> Shape.SQUARE 1157 1407 <Shape.SQUARE: 2> … … 1169 1419 When this behavior isn't desired, you can use the @unique()@ decorator: 1170 1420 \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 ... 1429 Traceback (most recent call last): 1430 ... 1174 1431 ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE 1175 1432 \end{python} … … 1179 1436 If the exact value is unimportant you can use @auto@: 1180 1437 \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} 1447 The values are chosen by \_generate\_next\_value\_(), which can be overridden: 1186 1448 \begin{python} 1187 1449 >>> class AutoName(Enum): … … 1320 1582 \begin{python} 1321 1583 class EnumName([mix-in, ...,] [data-type,] base-enum): 1322 pass1584 pass 1323 1585 \end{python} 1324 1586 Also, subclassing an enumeration is allowed only if the enumeration does not define any members. … … 1437 1699 \begin{python} 1438 1700 Enum( 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 ) 1447 1709 \end{python} 1448 1710 \begin{itemize} … … 1673 1935 \begin{python} 1674 1936 class IntEnum(int, Enum): 1675 pass1937 pass 1676 1938 \end{python} 1677 1939 This demonstrates how similar derived enumerations can be defined; … … 1808 2070 \begin{python} 1809 2071 def __bool__(self): 1810 return bool(self.value)2072 return bool(self.value) 1811 2073 \end{python} 1812 2074 Plain @Enum@ classes always evaluate as @True@. … … 2152 2414 2153 2415 If @__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 2438 9.802652743337129 2439 \end{python} 2189 2440 2190 2441 \subsection{TimePeriod} … … 2213 2464 \section{OCaml} 2214 2465 \lstnewenvironment{ocaml}[1][]{\lstset{language=OCaml,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{} 2215 2216 % https://ocaml.org/docs/basic-data-types#enumerated-data-types2217 2466 2218 2467 OCaml provides a variant (union) type, where multiple heterogeneously-typed objects share the same storage. … … 2304 2553 With valediction, 2305 2554 - Gregor Richards 2306 2307 2308 Date: Thu, 14 Mar 2024 21:45:52 -04002309 Subject: Re: OCaml "enums" do come with ordering2310 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 | Sun2317 > let day : weekday = Mon2318 > 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 with2324 > 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 * float2332 > let c = Red2333 > let _ = match c with Red -> Printf.printf "Red, "2334 > let c = Green( "abc" )2335 > let _ = match c with Green g -> Printf.printf "%s, " g2336 > let c = Blue( 1, 1.5 )2337 > let _ = match c with Blue( i, f ) -> Printf.printf "%d %g\n" i f2338 >2339 > let check_colour(c: colour): string =2340 > if c < Green( "xyz" ) then (* Gregor *)2341 > Printf.printf "green\n";2342 > match c with2343 > Red -> "Red" |2344 > Green g -> g |2345 > Blue(i, f) -> string_of_int i ^ string_of_float f2346 > let _ = check_colour( Red ); check_colour( Green( "xyz" ) );2347 >2348 > type stringList = Empty | Pair of string * stringList2349 > let rec len_of_string_list(l: stringList): int =2350 > match l with2351 > Empty -> 0 |2352 > Pair(_ , r) -> 1 + len_of_string_list r2353 >2354 > let _ = for i = 1 to 10 do2355 > Printf.printf "%d, " i2356 > done2357 >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. I2364 mostly view OCaml through a lens of "it's Haskell but with cheating". Haskell2365 "enums" (ADTs) aren't ordered unless you specifically and manually put them in2366 the Ord typeclass by defining the comparators. Apparently, OCaml has some2367 other rule, which I would guess is something like "sort by tag then by order of2368 parameter". Having a default behavior for comparators is *bizarre*; my guess2369 would be that it gained this behavior in its flirtation with object2370 orientation, but that's just a guess (and irrelevant).2371 2372 This gives a total order, but not enumerability (which would still be2373 effectively impossible or even meaningless since enums are just a special case2374 of ADTs).2375 2376 With valediction,2377 - Gregor Richards2378 2379 Date: Wed, 20 Mar 2024 18:16:44 -04002380 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". Can2387 > 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; **more2392 usually, to mention (a number of things or persons) separately, as if for the2393 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 loop2396 over them in a for loop (this is, of course, why so many enums come with an2397 ENUM_WHATEVER_LAST value). But, I would be hesitant to use the word "loop" to2398 describe enumerability, since in functional languages, you would recurse for2399 such a purpose.2400 2401 In Haskell, in order to do something with every member of an "enumeration", you2402 would have to explicitly list them all. The type system will help a bit since2403 it knows if you haven't listed them all, but you would have to statically have2404 every element in the enumeration. If somebody added new elements to the2405 enumeration later, your code to enumerate over them would no longer work2406 correctly, because you can't simply say "for each member of this enumeration do2407 X". In Haskell that's because there aren't actually enumerations; what they use2408 as enumerations are a degenerate form of algebraic datatypes, and ADTs are2409 certainly not enumerable. In OCaml, you've demonstrated that they impose2410 comparability, but I would still assume that you can't make a loop over every2411 member of an enumeration. (But, who knows!)2412 2413 Since that's literally what "enumerate" means, it seems like a rather important2414 property for enumerations to have ;)2415 2416 With valediction,2417 - Gregor Richards2418 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 +00002426 2427 Does this mean that not all enum declarations in C create enumerations? If you2428 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 these2437 values without listing all of them.2438 2439 2440 Date: Thu, 21 Mar 2024 10:31:49 -04002441 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 const2448 ints, and if used in that way, I personally wouldn't consider them as2449 enumerations in any meaningful sense, particularly since the type checker2450 essentially does nothing for you there. Then they're a way of writing consts2451 repeatedly with some textual indicator that these definitions are related; more2452 namespace, less enum.2453 2454 When somebody writes bitfield members as an enum, is that *really* an2455 enumeration, or just a use of the syntax for enums to keep related definitions2456 together?2457 2458 With valediction,2459 - Gregor Richards2460 2555 \end{comment} 2461 2556 … … 2463 2558 \section{Comparison} 2464 2559 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} 2561 feat. / lang. & Pascal & Ada & \Csharp & OCaml & Java & Modula-3 & Rust & Swift & Python \\ 2477 2562 \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 \\ 2563 pure & & & & & & & & & \\ 2564 ordered & & & & & & & & & \\ 2565 setable & & & & & & & & & \\ 2566 auto-init & & & & & & & & & \\ 2567 scoped & & & & & & & & & \\ 2568 typed & & & & & & & & & \\ 2569 switch & & & & & & & & & \\ 2570 loop & & & & & & & & & \\ 2571 array & & & & & & & & & \\ 2508 2572 \end{tabular} 2509 \end{table} -
doc/theses/mike_brooks_MMath/array.tex
r486caad rdf78cce 510 510 511 511 \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 type533 replaces @malloc@'s use of programmer-supplied size information.534 \begin{cfa}535 // C, library536 void * malloc( size_t );537 // C, user538 struct tm * el1 = malloc( sizeof(struct tm) );539 struct tm * ar1 = malloc( 10 * sizeof(struct tm) );540 541 // CFA, library542 forall( T * ) T * alloc();543 // CFA, user544 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.cfa552 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 1 1 \chapter{Background} 2 2 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} 3 This chapter states facts about the prior work, upon which my contributions build. 4 Each 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 10 The reader is assumed to have used C or \CC for the coursework of at least four university-level courses, or have equivalent experience. 11 The 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 17 When it comes to explaining how C works, I like illustrating definite program semantics. 18 I prefer doing so, over a quoting manual's suggested programmer's intuition, or showing how some compiler writers chose to model their problem. 19 To illustrate definite program semantics, I devise a program, whose behaviour exercises the point at issue, and I show its behaviour. 20 21 This 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 28 The compiler whose program semantics is shown is 29 \begin{cfa} 30 $ gcc --version 31 gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 32 \end{cfa} 33 running on Architecture @x86_64@, with the same environment targeted. 34 35 Unless 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. 36 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. 37 38 39 \subsection{C reports many ill-typed expressions as warnings} 40 41 These attempts to assign @y@ to @x@ and vice-versa are obviously ill-typed. 42 \lstinput{12-15}{bkgd-c-tyerr.c} 43 with warnings: 44 \begin{cfa} 45 warning: assignment to 'float *' from incompatible pointer type 'void (*)(void)' 46 warning: assignment to 'void (*)(void)' from incompatible pointer type 'float *' 47 \end{cfa} 48 Similarly, 49 \lstinput{17-19}{bkgd-c-tyerr.c} 50 with warning: 51 \begin{cfa} 52 warning: passing argument 1 of 'f' from incompatible pointer type 53 note: expected 'void (*)(void)' but argument is of type 'float *' 54 \end{cfa} 55 with a segmentation fault at runtime. 56 57 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@. 58 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. 59 60 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. 61 The behaviour (whose absence is unprovable) is neither minor nor unlikely. 62 The rejection shows that the program is ill-typed. 63 64 Yet, the rejection presents as a GCC warning. 65 66 In 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 (!)} 7 74 8 75 When 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.'' … … 444 511 445 512 446 \section{Linked List} 447 448 449 \section{String} 513 \section{\CFA} 514 515 Traditionally, 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 520 Prior work on \CFA included making C arrays, as used in C code from the wild, 521 work, if this code is fed into @cfacc@. 522 The quality of this this treatment was fine, with no more or fewer bugs than is typical. 523 524 More mixed results arose with feeding these ``C'' arrays into preexisting \CFA features. 525 526 A notable success was with the \CFA @alloc@ function, 527 which type information associated with a polymorphic return type 528 replaces @malloc@'s use of programmer-supplied size information. 529 \begin{cfa} 530 // C, library 531 void * malloc( size_t ); 532 // C, user 533 struct tm * el1 = malloc( sizeof(struct tm) ); 534 struct tm * ar1 = malloc( 10 * sizeof(struct tm) ); 535 536 // CFA, library 537 forall( T * ) T * alloc(); 538 // CFA, user 539 tm * el2 = alloc(); 540 tm (*ar2)[10] = alloc(); 541 \end{cfa} 542 The alloc polymorphic return compiles into a hidden parameter, which receives a compiler-generated argument. 543 This compiler's argument generation uses type information from the left-hand side of the initialization to obtain the intended type. 544 Using a compiler-produced value eliminates an opportunity for user error. 545 546 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 547 548 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. 549 In the last example, the choice of ``pointer to array'' @ar2@ breaks a parallel with @ar1@. 550 They are not subscripted in the same way. 551 \begin{cfa} 552 ar1[5]; 553 (*ar2)[5]; 554 \end{cfa} 555 Using ``reference to array'' works at resolving this issue. TODO: discuss connection with Doug-Lea \CC proposal. 556 \begin{cfa} 557 tm (&ar3)[10] = *alloc(); 558 ar3[5]; 559 \end{cfa} 560 The implicit size communication to @alloc@ still works in the same ways as for @ar2@. 561 562 Using proper array types (@ar2@ and @ar3@) addresses a concern about using raw element pointers (@ar1@), albeit a theoretical one. 563 TODO xref C standard does not claim that @ar1@ may be subscripted, 564 because no stage of interpreting the construction of @ar1@ has it be that ``there is an \emph{array object} here.'' 565 But both @*ar2@ and the referent of @ar3@ are the results of \emph{typed} @alloc@ calls, 566 where the type requested is an array, making the result, much more obviously, an array object. 567 568 The ``reference to array'' type has its sore spots too. 569 TODO see also @dimexpr-match-c/REFPARAM_CALL@ (under @TRY_BUG_1@) 570 571 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/intro.tex
r486caad rdf78cce 1 1 \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.5 2 6 3 \cite{Blache19} … … 8 5 \cite{Ruef19} 9 6 10 \section{Array }7 \section{Arrays} 11 8 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} 93 10 94 11 \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 218 218 \input{intro} 219 219 \input{background} 220 \input{list} 220 221 \input{array} 221 \input{list}222 222 \input{string} 223 223 \input{conclusion} -
libcfa/src/stdlib.cfa
r486caad rdf78cce 10 10 // Created On : Thu Jan 28 17:10:29 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Mar 17 08:25:32 202413 // Update Count : 6 9912 // Last Modified On : Mon Aug 14 18:22:36 2023 13 // Update Count : 642 14 14 // 15 15 … … 21 21 22 22 #include <string.h> // memcpy, memset 23 //#include <math.h> // fabsf, fabs, fabsl 23 24 #include <complex.h> // _Complex_I 24 25 #include <assert.h> 25 #include <ctype.h> // isblank26 26 27 27 #pragma GCC visibility push(default) … … 65 65 //--------------------------------------- 66 66 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 } // for75 } // checkif76 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 } // for83 } // checkif84 85 //---------------------------------------86 87 float _Complex strto( const char sptr[], char * eptr[] ) {88 float re, im;89 char * eeptr;90 errno = 0; // reset91 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 } // if99 } // if100 } // if101 if ( eptr != 0p ) *eptr = eeptr; // error case102 return 0.0f + 0.0f * _Complex_I;103 } // strto104 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 } // if116 } // if117 } // if118 if ( eptr != 0p ) *eptr = eeptr; // error case119 return 0.0 + 0.0 * _Complex_I;120 } // strto121 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 } // if133 } // if134 } // if135 if ( eptr != 0p ) *eptr = eeptr; // error case136 return 0.0L + 0.0L * _Complex_I;137 } // strto138 139 67 forall( T | { T strto( const char sptr[], char * eptr[], int ); } ) 140 T convert( const char sptr[] ) { // integral68 T convert( const char sptr[] ) { 141 69 char * eptr; 142 70 errno = 0; // reset … … 144 72 if ( errno == ERANGE ) throw ExceptionInst( out_of_range ); 145 73 if ( eptr == sptr || // conversion failed, no characters generated 146 eptr[0] != '\0' && ! checkif( eptr, isblank ) ) throw ExceptionInst( invalid_argument ); // not at end of blankstr ?74 *eptr != '\0' ) throw ExceptionInst( invalid_argument ); // not at end of str ? 147 75 return val; 148 76 } // convert 149 77 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 78 float _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 89 double _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 100 long 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 160 110 161 111 //--------------------------------------- -
libcfa/src/stdlib.hfa
r486caad rdf78cce 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Mar 17 08:25:31 202413 // Update Count : 7 9612 // Last Modified On : Sun Oct 8 09:18:28 2023 13 // Update Count : 789 14 14 // 15 15 … … 291 291 forall( T & | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] ); 292 292 forall( 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 );298 293 299 294 //--------------------------------------- … … 320 315 321 316 forall( 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) 317 T convert( const char sptr[] ); 325 318 326 319 static inline { -
src/CodeGen/CodeGenerator.cpp
r486caad rdf78cce 192 192 } 193 193 194 assert( decl->returns.size() < 2 ); 194 195 if ( 1 == decl->returns.size() ) { 195 196 ast::ptr<ast::Type> const & type = decl->returns[0]->get_type(); 196 197 output << genTypeNoAttr( type, acc.str(), subOptions ); 197 } else if ( 0 == decl->returns.size() ){198 } else { 198 199 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 );203 200 } 204 201 -
src/Parser/DeclarationNode.cc
r486caad rdf78cce 185 185 newnode->type->aggregate.fields = fields; 186 186 newnode->type->aggregate.body = body; 187 newnode->type->aggregate.tagged = false; 188 newnode->type->aggregate.parent = nullptr; 187 189 return newnode; 188 190 } // DeclarationNode::newAggregate … … 197 199 newnode->type->enumeration.typed = typed; 198 200 newnode->type->enumeration.hiding = hiding; 199 if ( base ) { 200 assert( typed ); 201 assert( base->type ); 201 if ( base && base->type ) { 202 202 newnode->type->base = base->type; 203 base->type = nullptr;204 delete base;205 203 } // if 206 204 … … 222 220 223 221 DeclarationNode * 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 { 225 231 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;232 232 } // if 233 233 } // DeclarationNode::newEnumValueGeneric … … 502 502 } 503 503 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 are509 // aligned. However, the attribute transparent_union must be moved from the typedef_name to510 // alias union U. Currently, this is the only know attribute that must be moved from typedef to511 // 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 an531 // 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; } foo537 // 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 an565 // 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 } foo571 // 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 the598 // existing declaration, and may split it into two declarations.599 // This only happens if the wrapped type is actually a declaration of a SUE600 // type. If it does, the DeclarationNode for the SUE declaration is the node601 // returned, make sure later transformations are applied to the right node.602 504 DeclarationNode * DeclarationNode::addTypedef() { 603 505 TypeData * newtype = new TypeData( TypeData::Symbolic ); … … 605 507 newtype->symbolic.isTypedef = true; 606 508 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; 623 512 } 624 513 … … 822 711 } 823 712 713 // If a typedef wraps an anonymous declaration, name the inner declaration so it has a consistent name across 714 // translation units. 715 static 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. 759 static 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 824 782 // Get the non-anonymous name of the instance type of the declaration, 825 783 // if one exists. … … 842 800 try { 843 801 bool extracted_named = false; 802 ast::UnionDecl * unionDecl = nullptr; 844 803 845 804 if ( DeclarationNode * extr = cur->extractAggregate() ) { 846 805 assert( cur->type ); 806 nameTypedefedDecl( extr, cur ); 847 807 848 808 if ( ast::Decl * decl = extr->build() ) { 809 // Remember the declaration if it is a union aggregate ? 810 unionDecl = dynamic_cast<ast::UnionDecl *>( decl ); 811 849 812 *out++ = decl; 850 813 … … 865 828 866 829 if ( ast::Decl * decl = cur->build() ) { 830 moveUnionAttribute( decl, unionDecl ); 831 867 832 if ( "" == decl->name && !cur->get_inLine() ) { 868 833 // Don't include anonymous declaration for named aggregates, -
src/Parser/TypeData.cc
r486caad rdf78cce 88 88 aggregate.fields = nullptr; 89 89 aggregate.body = false; 90 aggregate.tagged = false; 91 aggregate.parent = nullptr; 90 92 aggregate.anon = false; 91 93 break; … … 219 221 newtype->aggregate.kind = aggregate.kind; 220 222 newtype->aggregate.name = aggregate.name ? new string( *aggregate.name ) : nullptr; 223 newtype->aggregate.parent = aggregate.parent ? new string( *aggregate.parent ) : nullptr; 221 224 newtype->aggregate.params = maybeCopy( aggregate.params ); 222 225 newtype->aggregate.actuals = maybeCopy( aggregate.actuals ); … … 225 228 newtype->aggregate.body = aggregate.body; 226 229 newtype->aggregate.anon = aggregate.anon; 230 newtype->aggregate.tagged = aggregate.tagged; 227 231 break; 228 232 case AggregateInst: -
src/Parser/TypeData.h
r486caad rdf78cce 48 48 ast::AggregateDecl::Aggregate kind; 49 49 const std::string * name = nullptr; 50 const std::string * parent = nullptr; 50 51 DeclarationNode * params = nullptr; 51 52 ExpressionNode * actuals = nullptr; // holds actual parameters later applied to AggInst … … 54 55 bool body; 55 56 bool anon; 57 bool tagged; 56 58 }; 57 59 -
src/Parser/parser.yy
r486caad rdf78cce 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Mar 16 18:19:23 202413 // Update Count : 6 61712 // Last Modified On : Mon Mar 11 18:30:03 2024 13 // Update Count : 6589 14 14 // 15 15 … … 485 485 %type<decl> elaborated_type elaborated_type_nobody 486 486 487 %type<decl> enumerator_list enum_type enum_type_nobody enumerator_type487 %type<decl> enumerator_list enum_type enum_type_nobody 488 488 %type<init> enumerator_value_opt 489 489 … … 2742 2742 2743 2743 enum_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; } 2764 2748 | ENUM attribute_list_opt identifier 2765 2749 { typedefTable.makeTypedef( *$3, "enum_type 1" ); } … … 2768 2752 | ENUM attribute_list_opt typedef_name hide_opt '{' enumerator_list comma_opt '}' // unqualified type name 2769 2753 { $$ = DeclarationNode::newEnum( $3->name, $6, true, false, nullptr, $4 )->addQualifiers( $2 ); } 2770 | ENUM enumerator_type attribute_list_opt identifier attribute_list_opt2771 { 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() ) { 2773 2757 SemanticError( yylloc, "syntax error, storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); 2774 2758 } 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" ); 2776 2775 } 2777 2776 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 } 2783 2792 | enum_type_nobody 2784 ;2785 2786 enumerator_type:2787 '(' ')' // pure enumeration2788 { $$ = nullptr; }2789 | '(' cfa_abstract_parameter_declaration ')' // typed enumeration2790 { $$ = $2; }2791 2793 ; 2792 2794 -
src/main.cc
r486caad rdf78cce 101 101 } 102 102 103 // Helpers for checkInvariant: 104 void checkInvariants( std::list< Declaration * > & ) {} 105 using ast::checkInvariants; 106 103 107 #define PASS( name, pass, unit, ... ) \ 104 108 if ( errorp ) { cerr << name << endl; } \ … … 108 112 Stats::Time::StopBlock(); \ 109 113 if ( invariant ) { \ 110 ast::checkInvariants(unit);\114 checkInvariants(unit); \ 111 115 } 112 116 -
tests/.expect/ato.arm64.txt
r486caad rdf78cce 3 3 -123 -123 4 4 123 123 5 -123 -123 6 123 123 5 -123 -123 6 123 123 7 7 -123.456 -123.456 8 8 -123.456789012346 -123.4567890123456 9 -123.45678901234567890123456789 -123.45678901234567890123456789 9 -123.45678901234567890123456789 -123.45678901234567890123456789 10 10 -123.456-123.456i -123.456-123.456i 11 11 -123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i 12 12 123.45678901234567890123456789-123.45678901234567890123456789i 123.45678901234567890123456789-123.45678901234567890123456789i 13 123.45678901234-123.456789i 123.45678901234 -123.4567890i13 123.45678901234-123.456789i 123.45678901234-123.4567890i 14 14 -123 -123 15 15 123 123 16 16 -123 -123 17 17 123 123 18 -123 -123 19 123 123 18 -123 -123 19 123 123 20 20 -123.456 -123.456 21 21 -123.456789012346 -123.4567890123456 22 -123.45678901234567890123456789 -123.45678901234567890123456789 22 -123.45678901234567890123456789 -123.45678901234567890123456789 23 23 -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 24 0.+0.i 2 3 39 25 -123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i 40 26 123.45678901234567890123456789-123.45678901234567890123456789i 123.45678901234567890123456789-123.45678901234567890123456789i 41 27 123.45678901234-123.456789i 123.45678901234-123.4567890i 42 invalid argument 2.0fred43 invalid argument 2 3x -
tests/.expect/ato.x64.txt
r486caad rdf78cce 3 3 -123 -123 4 4 123 123 5 -123 -123 6 123 123 5 -123 -123 6 123 123 7 7 -123.456 -123.456 8 8 -123.456789012346 -123.4567890123456 9 -123.456789012345679 -123.45678901234567890123456789 9 -123.456789012345679 -123.45678901234567890123456789 10 10 -123.456-123.456i -123.456-123.456i 11 11 -123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i 12 12 123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i 13 123.45678901234-123.456789i 123.45678901234 -123.4567890i13 123.45678901234-123.456789i 123.45678901234-123.4567890i 14 14 -123 -123 15 15 123 123 16 16 -123 -123 17 17 123 123 18 -123 -123 19 123 123 18 -123 -123 19 123 123 20 20 -123.456 -123.456 21 21 -123.456789012346 -123.4567890123456 22 -123.456789012345679 -123.45678901234567890123456789 22 -123.456789012345679 -123.45678901234567890123456789 23 23 -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 24 0.+0.i 2 3 39 25 -123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i 40 26 123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i 41 27 123.45678901234-123.456789i 123.45678901234-123.4567890i 42 invalid argument 2.0fred43 invalid argument 2 3x -
tests/.expect/ato.x86.txt
r486caad rdf78cce 3 3 -123 -123 4 4 123 123 5 -123 -123 6 123 123 5 -123 -123 6 123 123 7 7 -123.456 -123.456 8 8 -123.456789012346 -123.4567890123456 9 -123.456789012345679 -123.45678901234567890123456789 9 -123.456789012345679 -123.45678901234567890123456789 10 10 -123.456-123.456i -123.456-123.456i 11 11 -123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i 12 12 123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i 13 123.45678901234-123.456789i 123.45678901234 -123.4567890i13 123.45678901234-123.456789i 123.45678901234-123.4567890i 14 14 -123 -123 15 15 123 123 16 16 -123 -123 17 17 123 123 18 -123 -123 19 123 123 18 -123 -123 19 123 123 20 20 -123.456 -123.456 21 21 -123.456789012346 -123.4567890123456 22 -123.456789012345679 -123.45678901234567890123456789 22 -123.456789012345679 -123.45678901234567890123456789 23 23 -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 24 0.+0.i 2 3 39 25 -123.456789012346+123.456789012346i -123.4567890123456+123.4567890123456i 40 26 123.456789012345679-123.456789012345679i 123.45678901234567890123456789-123.45678901234567890123456789i 41 27 123.45678901234-123.456789i 123.45678901234-123.4567890i 42 invalid argument 2.0fred43 invalid argument 2 3x -
tests/ato.cfa
r486caad rdf78cce 10 10 // Created On : Thu Feb 4 08:10:57 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 15 17:58:35 202413 // Update Count : 14512 // Last Modified On : Tue Dec 4 21:33:53 2018 13 // Update Count : 92 14 14 // 15 15 … … 18 18 19 19 int main( void ) { 20 // ato21 22 20 const char * sptr = "-123"; 23 21 int i = ato( sptr ); … … 34 32 sout | uli | sptr; 35 33 36 sptr = " -123 "; // spaces allowed34 sptr = "-123"; 37 35 long long int lli = ato( sptr ); 38 36 sout | lli | sptr; 39 sptr = " 123 "; // spaces allowed37 sptr = "123"; 40 38 unsigned long long int ulli = ato( sptr ); 41 39 sout | ulli | sptr; … … 47 45 double d = ato( sptr ); 48 46 sout | d | sptr; 49 sptr = " -123.45678901234567890123456789 "; // spaces allowed47 sptr = "-123.45678901234567890123456789"; 50 48 long double ld = ato( sptr ); 51 49 sout | ld | sptr; … … 60 58 long double _Complex ldc = ato( sptr ); 61 59 sout | ldc | sptr; 62 sptr = " 123.45678901234 -123.4567890i "; // spaces allowed60 sptr = "123.45678901234-123.4567890i"; 63 61 long double _Complex ldc2 = ato( sptr ); 64 62 sout | ldc2 | sptr; 65 63 66 // strto67 64 68 65 sptr = "-123"; 69 i = strto( sptr, 0 p, 10 );66 i = strto( sptr, 0, 10 ); 70 67 sout | i | sptr; 71 68 sptr = "123"; 72 ui = strto( sptr, 0 p, 10 );69 ui = strto( sptr, 0, 10 ); 73 70 sout | ui | sptr; 74 71 75 72 sptr = "-123"; 76 li = strto( sptr, 0 p, 10 );73 li = strto( sptr, 0, 10 ); 77 74 sout | li | sptr; 78 75 sptr = "123"; 79 uli = strto( sptr, 0 p, 10 );76 uli = strto( sptr, 0, 10 ); 80 77 sout | uli | sptr; 81 78 82 sptr = " -123 "; // spaces allowed83 lli = strto( sptr, 0 p, 10 );79 sptr = "-123"; 80 lli = strto( sptr, 0, 10 ); 84 81 sout | lli | sptr; 85 sptr = " 123 "; // spaces allowed86 ulli = strto( sptr, 0 p, 10 );82 sptr = "123"; 83 ulli = strto( sptr, 0, 10 ); 87 84 sout | ulli | sptr; 88 85 89 86 sptr = "-123.456"; 90 f = strto( sptr, 0 p);87 f = strto( sptr, 0 ); 91 88 sout | f | sptr; 92 89 sptr = "-123.4567890123456"; 93 d = strto( sptr, 0 p);90 d = strto( sptr, 0 ); 94 91 sout | d | sptr; 95 sptr = " -123.45678901234567890123456789 "; // spaces allowed96 ld = strto( sptr, 0 p);92 sptr = "-123.45678901234567890123456789"; 93 ld = strto( sptr, 0 ); 97 94 sout | ld | sptr; 98 95 99 96 sptr = "-123.456-123.456i"; 100 fc = strto( sptr, 0 p);97 fc = strto( sptr, 0 ); 101 98 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 102 109 sptr = "-123.4567890123456+123.4567890123456i"; 103 dc = strto( sptr, 0 p);110 dc = strto( sptr, 0 ); 104 111 sout | dc | sptr; 105 112 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 ); 171 114 sout | ldc | sptr; 172 115 sptr = "123.45678901234-123.4567890i"; 173 ldc2 = convert( sptr);116 ldc2 = strto( sptr, 0 ); 174 117 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 } // try183 184 sptr = "2 3x";185 try {186 fc = convert( sptr );187 assert( false );188 } catch( invalid_argument * ) {189 sout | "invalid argument" | sptr;190 } // try191 118 } // main 192 119
Note:
See TracChangeset
for help on using the changeset viewer.