source: doc/theses/jiada_liang_MMath/CFAenum.tex @ 5aeb1a9

Last change on this file since 5aeb1a9 was 5aeb1a9, checked in by JiadaL <j82liang@…>, 5 days ago

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

  • Property mode set to 100644
File size: 23.1 KB
Line 
1\chapter{\CFA Enumeration}
2
3% \CFA supports C enumeration using the same syntax and semantics for backwards compatibility.
4% \CFA also extends C-Style enumeration by adding a number of new features that bring enumerations inline with other modern programming languages.
5% Any enumeration extensions must be intuitive to C programmers both in syntax and semantics.
6% The following sections detail all of my new contributions to enumerations in \CFA.
7\CFA extends the enumeration declaration by parameterizing with a type (like a generic type).
8\begin{clang}[identifierstyle=\linespread{0.9}\it]
9$\it enum$-specifier:
10        enum @(type-specifier$\(_{opt}\)$)@ identifier$\(_{opt}\)$ { cfa-enumerator-list }
11        enum @(type-specifier$\(_{opt}\)$)@ identifier$\(_{opt}\)$ { cfa-enumerator-list , }
12        enum @(type-specifier$\(_{opt}\)$)@ identifier
13cfa-enumerator-list:
14        cfa-enumerator
15        cfa-enumerator, cfa-enumerator-list
16cfa-enumerator:
17        enumeration-constant
18        $\it inline$ identifier
19        enumeration-constant = expression
20\end{clang}
21A \newterm{\CFA enumeration}, or \newterm{\CFA enum}, has an optional type declaration in the bracket next to the @enum@ keyword.
22Without optional type declarations, the syntax defines "opaque enums".
23Otherwise, \CFA enum with type declaration are "typed enums".
24
25\section{Opaque Enum}
26\label{s:OpaqueEnum}
27Opaque enum is a special CFA enumeration type, where the internal representation is chosen by the compiler and hidden from users.
28Compared C enum, opaque enums are more restrictive in terms of typing, and cannot be implicitly converted to integers.
29Enumerators of opaque enum cannot have initializer. Declaring initializer in the body of opaque enum results in a syntax error.
30\begin{cfa}
31enum@()@ Planets { MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE };
32
33Planet p = URANUS;
34@int i = VENUS; // Error, VENUS cannot be converted into an integral type@
35\end{cfa}
36Each opage enum has two @attributes@: @position@ and @label@. \CFA auto-generates @attribute functions@ @posn()@ and @label()@ for every \CFA enum to returns the respective attributes.
37\begin{cfa}
38// Auto-generated
39int posn(Planet p);
40char * s label(Planet p);
41\end{cfa}
42
43\begin{cfa}
44unsigned i = posn(VENUS); // 1
45char * s = label(MARS); // "MARS"
46\end{cfa}
47
48% \subsection{Representation}
49\CFA uses chooses signed int as the underlying representation of an opaque enum variable, holding the value of enumeration position. Therefore, @posn()@ is in fact a cast that bypassing type system, converting an
50cfa enum to its integral representation.
51
52Labels information are stored in a global array. @label()@ is a function that maps enum position to an element of the array.
53
54\section{Typed Enum}
55\label{s:EnumeratorTyping}
56
57\CFA extends the enumeration declaration by parameterizing with a type (like a generic type), allowing enumerators to be assigned any values from the declared type.
58Figure~\ref{f:EumeratorTyping} shows a series of examples illustrating that all \CFA types can be use with an enumeration and each type's constants used to set the enumerator constants.
59Note, the synonyms @Liz@ and @Beth@ in the last declaration.
60Because enumerators are constants, the enumeration type is implicitly @const@, so all the enumerator types in Figure~\ref{f:EumeratorTyping} are logically rewritten with @const@.
61
62\begin{figure}
63\begin{cfa}
64// integral
65        enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' };
66        enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 };
67        enum( @long long int@ ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 };
68// non-integral
69        enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 };
70        enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i };
71// pointer
72        enum( @const char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
73        int i, j, k;
74        enum( @int *@ ) ptr { I = &i,  J = &j,  K = &k };
75        enum( @int &@ ) ref { I = i,   J = j,   K = k };
76// tuple
77        enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$
78// function
79        void f() {...}   void g() {...}
80        enum( @void (*)()@ ) funs { F = f,  G = g };
81// aggregate
82        struct Person { char * name; int age, height; };
83@***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz,
84                                                                        Jon = { "JONATHAN", 35, 190 } };
85\end{cfa}
86\caption{Enumerator Typing}
87\label{f:EumeratorTyping}
88\end{figure}
89
90An advantage of the typed enumerations is eliminating the \emph{harmonizing} problem between an enumeration and companion data \see{\VRef{s:Usage}}:
91\begin{cfa}
92enum( char * ) integral_types {
93        chr = "char", schar = "signed char", uschar = "unsigned char",
94        sshort = "signed short int", ushort = "unsigned short int",
95        sint = "signed int", usint = "unsigned int",
96        ...
97};
98\end{cfa}
99Note, the enumeration type can be a structure (see @Person@ in Figure~\ref{f:EumeratorTyping}), so it is possible to have the equivalent of multiple arrays of companion data using an array of structures.
100
101While the enumeration type can be any C aggregate, the aggregate's \CFA constructors are not used to evaluate an enumerator's value.
102\CFA enumeration constants are compile-time values (static);
103calling constructors happens at runtime (dynamic).
104
105@value@ is an @attribute@ that defined for typed enum along with position and label. @values@ of a typed enum are stored in a global array of declared typed, initialized with
106value of enumerator initializers. @value()@ functions maps an enum to an elements of the array.
107
108
109\subsection{Implicit Conversion}
110C has an implicit type conversion from an enumerator to its base type @int@.
111Correspondingly, \CFA has an implicit (safe) conversion from a typed enumerator to its base type.
112\begin{cfa}
113char currency = Dollar;
114string fred = Fred;                                             $\C{// implicit conversion from char * to \CFA string type}$
115Person student = Beth;
116\end{cfa}
117
118% The implicit conversion is accomplished by the compiler adding @value()@ function calls as a candidate with safe cost. Therefore, the expression
119% \begin{cfa}
120% char currency = Dollar;
121% \end{cfa}
122% is equivalent to
123% \begin{cfa}
124% char currency = value(Dollar);
125% \end{cfa}
126% Such conversion an @additional@ safe
127
128The implicit conversion is accomplished by the resolver adding call to @value()@ functions as a resolution candidate with a @implicit@ cost.
129Implicit cost is an additional category to Aaron's cost model. It is more signicant than @unsafe@ to have
130the compiler choosing implicit conversion over the narrowing conversion; It is less signicant to @poly@
131so that function overloaded with enum traits will be selected over the implicit. @Enum trait@ will be discussed in the chapter.
132
133Therefore, \CFA conversion cost is 8-tuple
134@@(unsafe, implicit, poly, safe, sign, vars, specialization, reference)@@
135
136\section{Auto Initialization}
137
138C auto-initialization works for the integral type @int@ with constant expressions.
139\begin{cfa}
140enum Alphabet ! {
141        A = 'A', B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
142        a = 'a', b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z
143};
144\end{cfa}
145The complexity of the constant expression depends on the level of runtime computation the compiler implements, \eg \CC \lstinline[language={[GNU]C++}]{constexpr} provides complex compile-time computation across multiple types, which blurs the compilation/runtime boundary.
146
147% The notion of auto-initialization can be generalized in \CFA through the trait @AutoInitializable@.
148% \begin{cfa}
149% forall(T) @trait@ AutoInitializable {
150%       void ?{}( T & o, T v );                         $\C{// initialization}$
151%       void ?{}( T & t, zero_t );                      $\C{// 0}$
152%       T ?++( T & t);                                          $\C{// increment}$
153% };
154% \end{cfa}
155% In addition, there is an implicit enumeration counter, @ecnt@ of type @T@, managed by the compiler.
156% For example, the type @Odd@ satisfies @AutoInitializable@:
157% \begin{cfa}
158% struct Odd { int i; };
159% void ?{}( Odd & o, int v ) { if ( v & 1 ) o.i = v; else /* error not odd */ ; };
160% void ?{}( Odd & o, zero_t ) { o.i = 1; };
161% Odd ?++( Odd o ) { return (Odd){ o.i + 2 }; };
162% \end{cfa}
163% and implicit initialization is available.
164% \begin{cfa}
165% enum( Odd ) { A, B, C = 7, D };                       $\C{// 1, 3, 7, 9}$
166% \end{cfa}
167% where the compiler performs the following transformation and runs the code.
168% \begin{cfa}
169% enum( Odd ) {
170%       ?{}( ecnt, @0@ }  ?{}( A, ecnt },       ?++( ecnt )  ?{}( B, ecnt ),
171%       ?{}( ecnt, 7 )  ?{}( C, ecnt ), ?++( ecnt )  ?{}( D, ecnt )
172% };
173% \end{cfa}
174
175The notion of auto-initialization is generalized in \CFA enum in the following way:
176Enumerator e is the first enumerator of \CFA enumeration E with base type T. If e declares no no initializer, e is auto-initialized by the $zero\_t$ constructor of T.
177\CFA reports a compile time error if T has no $zero\_t$ constructor.
178Enumerator e is an enumerator of base-type T enumeration E that position i, where $i \neq 0$. And d is the enumerator with position @i-1@, e is auto-initialized with
179the result of @value(d)++@. If operator @?++@ is not defined for type T, \CFA reports a compile time error.
180
181Unfortunately, auto-initialization is not implemented because \CFA is only a transpiler, relying on generated C code to perform the detail work.
182C does not have the equivalent of \CC \lstinline[language={[GNU]C++}]{constexpr}, and it is currently beyond the scope of the \CFA project to implement a complex runtime interpreter in the transpiler.
183Nevertheless, the necessary language concepts exist to support this feature.
184
185
186
187\section{Enumeration Inheritance}
188
189\CFA Plan-9 inheritance may be used with enumerations, where Plan-9 inheritance is containment inheritance with implicit unscoping (like a nested unnamed @struct@/@union@ in C).
190
191\begin{cfa}
192enum( char * ) Names { /* as above */ };
193enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" };
194enum( char * ) Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" };
195\end{cfa}
196
197Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a @subtype@ of enumeration @Name2@.
198Note, that enumerators must be unique in inheritance but enumerator values may be repeated.
199
200% The enumeration type for the inheriting type must be the same as the inherited type;
201% hence the enumeration type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for @Name3@.
202% When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important.
203Specifically, the inheritance relationship for @Names@ is:
204\begin{cfa}
205Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\C{// enum type of Names}$
206\end{cfa}
207
208Inlined from \CFA enumeration @O@, new enumeration @N@ copies all enumerators from @O@, including those @O@ obtains through inheritance. Enumerators inherited from @O@
209keeps same @label@ and @value@, but @position@ may shift to the right if other enumerators or inline enumeration declared in prior of @inline A@.
210\begin{cfa}
211enum() Phynchocephalia { Tuatara };
212enum() Squamata { Snake, Lizard };
213enum() Lepidosauromorpha { inline Phynchocephalia, inline Squamata, Kuehneosauridae };
214\end{cfa}
215Snake, for example, has the position 0 in Squamata, but 1 in Lepidosauromorpha as Tuatara inherited from Phynchocephalia is position 0 in Lepidosauromorpha.
216
217A subtype enumeration can be casted, or implicitly converted into its supertype, with a safe cost.
218\begin{cfa}
219enum Squamata squamata_lizard = Lizard;
220posn(quamata_lizard); // 1
221enum Lepidosauromorpha lepidosauromorpha_lizard = squamata_lizard;
222posn(lepidosauromorpha_lizard); // 2
223void foo( Lepidosauromorpha l );
224foo( squamata_lizard );
225posn( (Lepidosauromorpha) squamata_lizard ); // 2
226
227Lepidosauromorpha s = Snake;
228\end{cfa}
229The last expression in the preceding example is umabigious. While both @Squamata.Snake@ and @Lepidosauromorpha.Snake@ are valid candidate, @Squamata.Snake@ has
230an associated safe cost and \CFA select the zero cost candidate @Lepidosauromorpha.Snake@.
231
232As discussed in \VRef{s:OpaqueEnum}, \CFA chooses position as a representation of \CFA enum. Conversion involves both change of typing
233and possibly @position@.
234
235When converting a subtype to a supertype, the position can only be a larger value. The difference between the position in subtype and in supertype is an "offset".
236\CFA runs a the following algorithm to determine the offset for an enumerator to a super type.
237% In a summary, \CFA loops over members (include enumerators and inline enums) of the supertype.
238% If the member is the matching enumerator, the algorithm returns its position.
239% If the member is a inline enumeration, the algorithm trys to find the enumerator in the inline enumeration. If success, it returns the position of enumerator in the inline enumeration, plus
240% the position in the current enumeration. Otherwises, it increase the offset by the size of inline enumeration.
241
242\begin{cfa}
243struct Enumerator;
244struct CFAEnum {
245        vector<variant<CFAEnum, Enumerator>> members;
246};
247pair<bool, int> calculateEnumOffset( CFAEnum dst, Enumerator e ) {
248        int offset = 0;
249        for( auto v: dst.members ) {
250                if ( v.holds_alternative<Enumerator>() ) {
251                        auto m = v.get<Enumerator>();
252                        if ( m == e ) return make_pair( true, 0 );
253                        offset++;
254                } else {
255                        auto p = calculateEnumOffset( v, e );
256                        if ( p.first ) return make_pair( true, offset + p.second );
257                        offset += p.second;
258                }
259        }
260        return make_pair( false, offset );
261}
262\end{cfa}
263
264% \begin{cfa}
265% Names fred = Name.Fred;
266% (Names2) fred; (Names3) fred; (Name3) Names.Jack;  $\C{// cast to super type}$
267% Names2 fred2 = fred; Names3 fred3 = fred2; $\C{// assign to super type}$
268% \end{cfa}
269For the given function prototypes, the following calls are valid.
270\begin{cquote}
271\begin{tabular}{ll}
272\begin{cfa}
273void f( Names );
274void g( Names2 );
275void h( Names3 );
276void j( const char * );
277\end{cfa}
278&
279\begin{cfa}
280f( Fred );
281g( Fred );   g( Jill );
282h( Fred );   h( Jill );   h( Sue );
283j( Fred );    j( Jill );    j( Sue );    j( "WILL" );
284\end{cfa}
285\end{tabular}
286\end{cquote}
287Note, the validity of calls is the same for call-by-reference as for call-by-value, and @const@ restrictions are the same as for other types.
288
289\section{Enumerator Control Structures}
290
291Enumerators can be used in multiple contexts.
292In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution).
293However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts.
294In these contexts, a programmer's initition assumes an implicit conversion to position.
295
296For example, an intuitive use of enumerations is with the \CFA @switch@/@choose@ statement, where @choose@ performs an implicit @break@ rather than a fall-through at the end of a @case@ clause.
297(For this discussion, ignore the fact that @case@ requires a compile-time constant.)
298\begin{cfa}[belowskip=0pt]
299enum Count { First, Second, Third, Fourth };
300Count e;
301\end{cfa}
302\begin{cquote}
303\setlength{\tabcolsep}{15pt}
304\noindent
305\begin{tabular}{@{}ll@{}}
306\begin{cfa}[aboveskip=0pt]
307
308choose( e ) {
309        case @First@: ...;
310        case @Second@: ...;
311        case @Third@: ...;
312        case @Fourth@: ...;
313}
314\end{cfa}
315&
316\begin{cfa}[aboveskip=0pt]
317// rewrite
318choose( @value@( e ) ) {
319        case @value@( First ): ...;
320        case @value@( Second ): ...;
321        case @value@( Third ): ...;
322        case @value@( Fourth ): ...;
323}
324\end{cfa}
325\end{tabular}
326\end{cquote}
327Here, the intuitive code on the left is implicitly transformed into the standard implementation on the right, using the value of the enumeration variable and enumerators.
328However, this implementation is fragile, \eg if the enumeration is changed to:
329\begin{cfa}
330enum Count { First, Second, Third @= First@, Fourth };
331\end{cfa}
332making @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicate @case@ clauses.
333To better match with programmer intuition, \CFA toggles between value and position semantics depending on the language context.
334For conditional clauses and switch statements, \CFA uses the robust position implementation.
335\begin{cfa}
336if ( @posn@( e ) < posn( Third ) ) ...
337choose( @posn@( e ) ) {
338        case @posn@( First ): ...;
339        case @posn@( Second ): ...;
340        case @posn@( Third ): ...;
341        case @posn@( Fourth ): ...;
342}
343\end{cfa}
344
345\CFA provides a special form of for-control for enumerating through an enumeration, where the range is a type.
346\begin{cfa}
347for ( cx; @Count@ ) { sout | cx | nonl; } sout | nl;
348for ( cx; +~= Count ) { sout | cx | nonl; } sout | nl;
349for ( cx; -~= Count ) { sout | cx | nonl; } sout | nl;
350First Second Third Fourth
351First Second Third Fourth
352Fourth Third Second First
353\end{cfa}
354The enumeration type is syntax sugar for looping over all enumerators and assigning each enumerator to the loop index, whose type is inferred from the range type.
355The prefix @+~=@ or @-~=@ iterate forward or backwards through the inclusive enumeration range, where no prefix defaults to @+~=@.
356
357C has an idiom for @if@ and loop predicates of comparing the predicate result ``not equal to 0''.
358\begin{cfa}
359if ( x + y /* != 0 */ ) ...
360while ( p /* != 0 */ ) ...
361\end{cfa}
362This idiom extends to enumerations because there is a boolean conversion in terms of the enumeration value, if and only if such a conversion is available.
363For example, such a conversion exists for all numerical types (integral and floating-point).
364It is possible to explicitly extend this idiom to any typed enumeration by overloading the @!=@ operator.
365\begin{cfa}
366bool ?!=?( Name n, zero_t ) { return n != Fred; }
367Name n = Mary;
368if ( n ) ... // result is true
369\end{cfa}
370Specialize meanings are also possible.
371\begin{cfa}
372enum(int) ErrorCode { Normal = 0, Slow = 1, Overheat = 1000, OutOfResource = 1001 };
373bool ?!=?( ErrorCode ec, zero_t ) { return ec >= Overheat; }
374ErrorCode code = ...;
375if ( code ) { problem(); }
376\end{cfa}
377
378
379\section{Enumeration Dimension}
380
381\VRef{s:EnumeratorTyping} introduced the harmonizing problem between an enumeration and secondary information.
382When possible, using a typed enumeration for the secondary information is the best approach.
383However, there are times when combining these two types is not possible.
384For example, the secondary information might precede the enumeration and/or its type is needed directly to declare parameters of functions.
385In these cases, having secondary arrays of the enumeration size are necessary.
386
387To support some level of harmonizing in these cases, an array dimension can be defined using an enumerator type, and the enumerators used as subscripts.
388\begin{cfa}
389enum E { A, B, C, N }; // possibly predefined
390float H1[N] = { [A] : 3.4, [B] : 7.1, [C] : 0.01 }; // C
391float H2[@E@] = { [A] : 3.4, [B] : 7.1, [C] : 0.01 }; // CFA
392\end{cfa}
393(Note, C uses the symbol, @'='@ for designator initialization, but \CFA had to change to @':'@ because of problems with tuple syntax.)
394This approach is also necessary for a predefined typed enumeration (unchangeable), when additional secondary-information need to be added.
395
396
397\section{Enumeration I/O}
398
399As seen in multiple examples, enumerations can be printed and the default property printed is the enumerator's label, which is similar in other programming languages.
400However, very few programming languages provide a mechanism to read in enumerator values.
401Even the @boolean@ type in many languages does not have a mechanism for input using the enumerators @true@ or @false@.
402\VRef[Figure]{f:EnumerationI/O} show \CFA enumeration input based on the enumerator labels.
403When the enumerator labels are packed together in the input stream, the input algorithm scans for the longest matching string.
404For basic types in \CFA, the constants use to initialize a variable in a program are available to initialize a variable using input, where strings constants can be quoted or unquoted.
405
406\begin{figure}
407\begin{cquote}
408\setlength{\tabcolsep}{15pt}
409\begin{tabular}{@{}ll@{}}
410\begin{cfa}
411int main() {
412        enum(int ) E { BBB = 3, AAA, AA, AB, B };
413        E e;
414
415        for () {
416                try {
417                        @sin | e@;
418                } catch( missing_data * ) {
419                        sout | "missing data";
420                        continue; // try again
421                }
422          if ( eof( sin ) ) break;
423                sout | e | "= " | value( e );
424        }
425}
426\end{cfa}
427&
428\begin{cfa}
429$\rm input$
430BBBABAAAAB
431BBB AAA AA AB B
432
433$\rm output$
434BBB = 3
435AB = 6
436AAA = 4
437AB = 6
438BBB = 3
439AAA = 4
440AA = 5
441AB = 6
442B = 7
443
444\end{cfa}
445\end{tabular}
446\end{cquote}
447\caption{Enumeration I/O}
448\label{f:EnumerationI/O}
449\end{figure}
450
451
452
453\section{Planet Example}
454
455\VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating most of the \CFA enumeration features.
456@Planet@ is an enumeration of type @MR@.
457Each planet enumerator is initialized to a specific mass/radius, @MR@, value.
458The unnamed enumeration provides the gravitational-constant enumerator @G@.
459Function @surfaceGravity@ uses the @with@ clause to remove @p@ qualification from fields @mass@ and @radius@.
460The program main uses the pseudo function @countof@ to obtain the number of enumerators in @Planet@, and safely converts the random value into a @Planet@ enumerator using @fromInt@.
461The resulting random orbital-body is used in a @choose@ statement.
462The enumerators in the @case@ clause use the enumerator position for testing.
463The prints use @label@ to print an enumerator's name.
464Finally, a loop enumerates through the planets computing the weight on each planet for a given earth mass.
465The print statement does an equality comparison with an enumeration variable and enumerator (@p == MOON@).
466
467\begin{figure}
468\small
469\begin{cfa}
470struct MR { double mass, radius; };                     $\C{// planet definition}$
471enum( @MR@ ) Planet {                                           $\C{// typed enumeration}$
472        //                      mass (kg)   radius (km)
473        MERCURY = { 0.330_E24, 2.4397_E6 },
474        VENUS      = { 4.869_E24, 6.0518_E6 },
475        EARTH       = { 5.976_E24, 6.3781_E6 },
476        MOON        = { 7.346_E22, 1.7380_E6 }, $\C{// not a planet}$
477        MARS         = { 0.642_E24, 3.3972_E6 },
478        JUPITER    = { 1898._E24, 71.492_E6 },
479        SATURN     = { 568.8_E24, 60.268_E6 },
480        URANUS    = { 86.86_E24, 25.559_E6 },
481        NEPTUNE  = { 102.4_E24, 24.746_E6 },
482        PLUTO       = { 1.303_E22, 1.1880_E6 }, $\C{// not a planet}$
483};
484enum( double ) { G = 6.6743_E-11 };                     $\C{// universal gravitational constant (m3 kg-1 s-2)}$
485static double surfaceGravity( Planet p ) @with( p )@ {
486        return G * mass / ( radius @\@ 2 );             $\C{// no qualification, exponentiation}$
487}
488static double surfaceWeight( Planet p, double otherMass ) {
489        return otherMass * surfaceGravity( p );
490}
491int main( int argc, char * argv[] ) {
492        if ( argc != 2 ) @exit@ | "Usage: " | argv[0] | "earth-weight";  // terminate program
493        double earthWeight = convert( argv[1] );
494        double earthMass = earthWeight / surfaceGravity( EARTH );
495        Planet rp = @fromInt@( prng( @countof@( Planet ) ) ); $\C{// select random orbiting body}$
496        @choose( rp )@ {                                                $\C{// implicit breaks}$
497          case MERCURY, VENUS, EARTH, MARS:
498                sout | @rp@ | "is a rocky planet";
499          case JUPITER, SATURN, URANUS, NEPTUNE:
500                sout | rp | "is a gas-giant planet";
501          default:
502                sout | rp | "is not a planet";
503        }
504        for ( @p; Planet@ ) {                                   $\C{// enumerate}$
505                sout | "Your weight on" | ( @p == MOON@ ? "the" : " " ) | p
506                           | "is" | wd( 1,1,  surfaceWeight( p, earthMass ) ) | "kg";
507        }
508}
509$\$$ planet 100
510JUPITER is a gas-giant planet
511Your weight on MERCURY is 37.7 kg
512Your weight on VENUS is 90.5 kg
513Your weight on EARTH is 100.0 kg
514Your weight on the MOON is 16.6 kg
515Your weight on MARS is 37.9 kg
516Your weight on JUPITER is 252.8 kg
517Your weight on SATURN is 106.6 kg
518Your weight on URANUS is 90.5 kg
519Your weight on NEPTUNE is 113.8 kg
520Your weight on PLUTO is 6.3 kg
521\end{cfa}
522\caption{Planet Example}
523\label{f:PlanetExample}
524\end{figure}
Note: See TracBrowser for help on using the repository browser.