Changes in / [ce02877:38e20a80]


Ignore:
Files:
5 deleted
13 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/mike_brooks_MMath/array.tex

    rce02877 r38e20a80  
    66
    77Arrays in C are possible the single most misunderstood and incorrectly used features in the language, resulting in the largest proportion of runtime errors and security violations.
    8 This chapter describes the new \CFA language and library features that introduce a length-checked array-type to the \CFA standard library~\cite{Cforall}.
    9 
    10 Specifically, a new \CFA array is declared:
    11 \begin{cfa}
    12 @array( float, 99 )@ x;                                 $\C[2.75in]{// x contains 99 floats}$
    13 \end{cfa}
    14 using generic type @array@ with arguments @float@ and @99@.
    15 A function @f@ is declared with an @array@ parameter of length @42@.
    16 \begin{cfa}
     8This chapter describes the new \CFA language and library features that introduce a length-checked array-type to the \CFA standard library~\cite{Cforall}, \eg:
     9\begin{cfa}
     10@array( float, 99 )@ x;                                 $\C{// x contains 99 floats}$
    1711void f( @array( float, 42 )@ & p ) {}   $\C{// p accepts 42 floats}$
    1812f( x );                                                                 $\C{// statically rejected: types are different, 99 != 42}$
    1913
    20 test2.cfa:3:1 error: Invalid application of existing declaration(s) in expression.
    21 Applying untyped:  Name: f ... to:  Name: x
    22 \end{cfa}
     14forall( T, [N] )
     15void g( @array( T, N )@ & p, int i ) {
     16        T elem = p[i];                                          $\C{// dynamically checked: requires 0 <= i < N}$
     17}
     18g( x, 0 );                                                              $\C{// T is float, N is 99, dynamic subscript check succeeds}$
     19g( x, 1000 );                                                   $\C{// T is float, N is 99, dynamic subscript check fails}$
     20\end{cfa}
     21This example declares variable @x@, with generic type @array@ using arguments @float@ and @99@.
     22Function @f@ is declared with an @array@ parameter of length @42@.
    2323The call @f( x )@ is invalid because the @array@ lengths @99@ and @42@ do not match.
    24 
    2524Next, function @g@ introduces a @forall@ prefix on type parameter @T@ and arbitrary \emph{dimension parameter} @N@, the new feature that represents a count of elements managed by the type system.
    26 \begin{cfa}
    27 forall( T, @[N]@ )
    28 void g( array( T, @N@ ) & p, int i ) {
    29         T elem = p[i];                                          $\C{// dynamically checked: requires 0 <= i < N}$
    30 }
    31 g( x, 0 );                                                              $\C{// T is float, N is 99, dynamic subscript check succeeds}$
    32 g( x, 1000 );                                                   $\C{// T is float, N is 99, dynamic subscript check fails}\CRT$
    33 
    34 Cforall Runtime error: subscript 1000 exceeds dimension range [0,99) $for$ array 0x555555558020.
    35 \end{cfa}
    3625The call @g( x, 0 )@ is valid because @g@ accepts any length of array, where the type system infers @float@ for @T@ and length @99@ for @N@.
    3726Inferring values for @T@ and @N@ is implicit without programmer involvement.
     
    4635forall( [N] )
    4736void declDemo() {
    48         float x1[N];                                            $\C{// built-in type ("C array")}$
    49         array(float, N) x2;                                     $\C{// type from library}$
     37        float x1[N];                            $\C{// built-in type ("C array")}$
     38        array(float, N) x2;                     $\C{// type from library}$
    5039}
    5140\end{cfa}
    5241Both of the locally-declared array variables, @x1@ and @x2@, have 42 elements, each element being a @float@.
    5342The two variables have identical size and layout; they both encapsulate 42-float, stack \vs heap allocations with no additional ``bookkeeping'' allocations or headers.
    54 Providing this explicit generic approach requires a significant extension to the \CFA type system to support a full-feature, safe, efficient (space and time) array-type, which forms the foundation for more complex array forms in \CFA.
     43Providing this explicit generic approach required a significant extension to the \CFA type system to support a full-feature, safe, efficient (space and time) array-type, which forms the foundation for more complex array forms in \CFA.
    5544
    5645Admittedly, the @array@ library type (type for @x2@) is syntactically different from its C counterpart.
    5746A future goal (TODO xref) is to provide a built-in array type with syntax approaching C's (type for @x1@);
    5847then, the library @array@ type can be removed giving \CFA a largely uniform array type.
    59 At present, the C syntax @array@ is only partially supported, so the generic @array@ is used exclusively in the discussion;
     48At present, the built-in array is only partially supported, so the generic @array@ is used exclusively in the discussion;
    6049feature support and C compatibility are revisited in Section ? TODO.
    6150
    62 Offering the @array@ type, as a distinct alternative to the C array, is consistent with \CFA's goal of backwards compatibility, \ie virtually all existing C (@gcc@) programs can be compiled by \CFA with only a small number of changes, similar to \CC (@g++@).
     51Offering an @array@ type, as a distinct alternative to the C array, is consistent with \CFA's goal of backwards compatibility, \ie virtually all existing C (gcc) programs can be compiled by \CFA with only a small number of changes, similar to \CC (g++).
    6352However, a few compatibility-breaking changes to the behaviour of the C array are necessary, both as an implementation convenience and to fix C's lax treatment of arrays.
    6453Hence, the @array@ type is an opportunity to start from a clean slate and show a cohesive selection of features, making it unnecessary to deal with every inherited complexity introduced by the C array TODO xref.
    6554
    66 My contributions in this chapter are:
     55My contributions are:
    6756\begin{enumerate}
    6857\item A type system enhancement that lets polymorphic functions and generic types be parameterized by a numeric value: @forall( [N] )@.
     
    111100\end{figure}
    112101
    113 \VRef[Figure]{f:fHarness} shows a harness that uses function @f@ to illustrate how dynamic values are fed into the @array@ type.
    114 Here, the dimension of arrays @x@, @y@, and @result@ is specified from a command-line value, @dim@, and these arrays are allocated on the stack.
     102\VRef[Figure]{f:fHarness} shows a harness that uses the @f@ function illustrating how dynamic values are fed into the @array@ type.
     103Here, the dimension of the @x@, @y@, and @result@ arrays is specified from a command-line value and these arrays are allocated on the stack.
    115104Then the @x@ array is initialized with decreasing values, and the @y@ array with amounts offset by constant @0.005@, giving relative differences within tolerance initially and diverging for later values.
    116105The program main is run (see figure bottom) with inputs @5@ and @7@ for sequence lengths.
    117 The loops follow the familiar pattern of using the variable @dim@ to iterate through the arrays.
    118 Most importantly, the type system implicitly captures @dim@ at the call of @f@ and makes it available throughout @f@ as @N@.
    119 The example shows @dim@ adapting into a type-system managed length at the declarations of @x@, @y@, and @result@, @N@ adapting in the same way at @f@'s loop bound, and a pass-thru use of @dim@ at @f@'s declaration of @ret@.
     106The loops follow the familiar pattern of using the variable @n@ to iterate through the arrays.
     107Most importantly, the type system implicitly captures @n@ at the call of @f@ and makes it available throughout @f@ as @N@.
     108The example shows @n@ adapting into a type-system managed length at the declarations of @x@, @y@, and @result@, @N@ adapting in the same way at @f@'s loop bound, and a pass-thru use of @n@ at @f@'s declaration of @ret@.
    120109Except for the lifetime-management issue of @result@, \ie explicit @free@, this program has eliminated both the syntactic and semantic problems associated with C arrays and their usage.
    121110These benefits cannot be underestimated.
     
    152141\CC has a (mistaken) belief that references are not objects, but pointers are objects.
    153142In the \CC example, the arrays fall back on C arrays, which have a duality with references with respect to automatic dereferencing.
    154 The \CFA array is a contiguous object with an address, which can be stored as a reference or pointer.
     143The \CFA array is a contiguous object with an address, which can stored as a reference or pointer.
    155144\item
    156145C/\CC arrays cannot be copied, while \CFA arrays can be copied, making them a first-class object (although array copy is often avoided for efficiency).
     
    162151
    163152@template< typename T, size_t N >@
    164 void copy( T ret[@N@], T x[@N@] ) {
     153void copy( T ret[N], T x[N] ) {
    165154        for ( int i = 0; i < N; i += 1 ) ret[i] = x[i];
    166155}
     
    178167int main() {
    179168        @forall( T, [N] )@   // nested function
    180         void copy( array( T, @N@ ) & ret, array( T, @N@ ) & x ) {
     169        void copy( array( T, N ) & ret, array( T, N ) & x ) {
    181170                for ( i; 10 ) ret[i] = x[i];
    182171        }
     
    196185
    197186Continuing the discussion of \VRef[Figure]{f:fHarness}, the example has @f@ expecting two arrays of the same length.
    198 As stated previous, a compile-time error occurs when attempting to call @f@ with arrays of differing lengths.
     187A compile-time error occurs when attempting to call @f@ with arrays of differing lengths.
    199188% removing leading whitespace
    200189\lstinput[tabsize=1]{52-53}{hello-array.cfa}
    201190\lstinput[tabsize=1,aboveskip=0pt]{62-64}{hello-array.cfa}
    202 C allows casting to assert knowledge not shared with the type system.
     191As is common practice in C, the programmer is free to cast, \ie to assert knowledge not shared with the type system.
    203192\lstinput{70-74}{hello-array.cfa}
    204193
     
    208197\lstinput{10-15}{hello-accordion.cfa}
    209198This structure's layout has the starting offset of @municipalities@ varying in @NprovTerty@, and the offset of @total_pt@ and @total_mun@ varying in both generic parameters.
    210 For a function that operates on a @CanPop@ structure, the type system handles this variation transparently.
     199For a function that operates on a @CanadaPop@ structure, the type system handles this variation transparently.
    211200\lstinput{40-45}{hello-accordion.cfa}
    212 \VRef[Figure]{f:checkHarness} shows the @CanPop@ harness and results with different array sizes, if the municipalities changed after a census.
     201\VRef[Figure]{f:checkHarness} shows program results where different offset values being used.
     202The output values show that @summarize@ and its caller agree on both the offsets (where the callee starts reading @cost_contribs@ and where the callee writes @total_cost@).
     203Yet the call site just says, ``pass the request.''
    213204
    214205\begin{figure}
    215206\lstinput{60-68}{hello-accordion.cfa}
    216 \lstinput{70-75}{hello-accordion.cfa}
     207\lstinput{70-72}{hello-accordion.cfa}
    217208\caption{\lstinline{check} Harness}
    218209\label{f:checkHarness}
     
    241232In general, storage layout is hidden by subscripting, and only appears when passing arrays among different programming languages or accessing specific hardware.
    242233
    243 \VRef[Figure]{f:FixedVariable} shows two C90 approaches for manipulating a contiguous matrix.
     234\VRef[Figure]{f:FixedVariable} shows two C90 approaches for manipulating contiguous arrays.
    244235Note, C90 does not support VLAs.
    245 The fixed-dimension approach (left) uses the type system;
     236The fixed-dimension approach uses the type system;
    246237however, it requires all dimensions except the first to be specified at compile time, \eg @m[][6]@, allowing all subscripting stride calculations to be generated with constants.
    247238Hence, every matrix passed to @fp1@ must have exactly 6 columns but the row size can vary.
    248 The variable-dimension approach (right) ignores (violates) the type system, \ie argument and parameters types do not match, and subscripting is performed manually using pointer arithmetic in the macro @sub@.
     239The variable-dimension approach ignores (violates) the type system, \ie argument and parameters types do not match, and manually performs pointer arithmetic for subscripting in the macro @sub@.
    249240
    250241\begin{figure}
     
    267258        ...  printf( "%d ", @sub( m, r, c )@ );  ...
    268259}
    269 int vm1[@4@][@4@], vm2[@6@][@8@]; // no VLA
     260int vm1[4][4], vm2[6][8]; // no VLA
    270261// initialize matrixes
    271262fp2( 4, 4, vm1 );
     
    299290The language decides if the matrix and array-of-array are laid out the same or differently.
    300291For example, an array-of-array may be an array of row pointers to arrays of columns, so the rows may not be contiguous in memory nor even the same length (triangular matrix).
    301 Regardless, there is usually a uniform subscripting syntax masking the memory layout, even though a language could differentiated between the two forms using subscript syntax, \eg @m[1,2]@ \vs @aa[1][2]@.
     292Regardless, there is usually a uniform subscripting syntax masking the memory layout, even though the two array forms could be differentiated at the subscript level, \eg @m[1,2]@ \vs @aa[1][2]@.
    302293Nevertheless, controlling memory layout can make a difference in what operations are allowed and in performance (caching/NUMA effects).
    303294
     
    310301The focus of this work is on the contiguous multidimensional arrays in C.
    311302The reason is that programmers are often forced to use the more complex array-of-array form when a contiguous array would be simpler, faster, and safer.
    312 Nevertheless, the C array-of-array form is still important for special circumstances.
     303Nevertheless, the C array-of-array form continues to be useful for special circumstances.
    313304
    314305\VRef[Figure]{f:ContiguousNon-contiguous} shows the extensions made in C99 for manipulating contiguous \vs non-contiguous arrays.\footnote{C90 also supported non-contiguous arrays.}
     
    322313While this contiguous-array capability is a step forward, it is still the programmer's responsibility to manually manage the number of dimensions and their sizes, both at the function definition and call sites.
    323314That is, the array does not automatically carry its structure and sizes for use in computing subscripts.
    324 While the non-contiguous style in @faa@ looks very similar to @fc@, the compiler only understands the unknown-sized array of row pointers, and it relies on the programmer to traverse the columns in a row correctly with a correctly bounded loop index.
     315While the non-contiguous style in @faa@ looks very similar to @fc@, the compiler only understands the unknown-sized array of row pointers, and it relies on the programmer to traverse the columns in a row correctly.
    325316Specifically, there is no requirement that the rows are the same length, like a poem with different length lines.
    326317
     
    374365this model has no awareness of dimensions just the ability to access memory at a distance from a reference point (base-displacement addressing), \eg @x + 23@ or @x[23}@ $\Rightarrow$ 23rd element from the start of @x@.
    375366A programmer must manually build any notion of dimensions using other tools;
    376 hence, this style is not offering multidimensional arrays \see{\VRef[Figure]{f:FixedVariable} right example}.
     367hence, this style is not offering multidimensional arrays \see{\VRef[Figure]{f:FixedVariable}}.
    377368\end{enumerate}
    378369
     
    390381A C/\CFA array interface includes the resulting memory layout.
    391382The defining requirement of a type-2 system is the ability to slice a column from a column-finest matrix.
    392 The required memory shape of such a slice is fixed, before any discussion of implementation.
     383The required memory shape of such a slice is set, before any discussion of implementation.
    393384The implementation presented here is how the \CFA array library wrangles the C type system, to make it do memory steps that are consistent with this layout.
    394385TODO: do I have/need a presentation of just this layout, just the semantics of -[all]?
     
    398389Beyond what C's array type offers, the new array brings direct support for working with a noncontiguous array slice, allowing a program to work with dimension subscripts given in a non-physical order.
    399390
    400 The following examples use the matrix declaration @array( float, 5, 7 ) m@, loaded with values incremented by $0.1$, when stepping across the length-7 finely-strided column dimension, and stepping across the length-5 coarsely-strided row dimension.
    401 \par
     391The following examples use an @array( float, 5, 7) m@, loaded with values incremented by $0.1$, when stepping across the length-7 finely-strided column dimension, and stepping across the length-5 coarsely-strided row dimension.
     392\par\noindent
    402393\mbox{\lstinput{121-126}{hello-md.cfa}}
    403394\par\noindent
     
    414405Specifically, declaring the parameter @r@ with type @array@ means that @r@ is contiguous, which is unnecessarily restrictive.
    415406That is, @r@ need only be of a container type that offers a subscript operator (of type @ptrdiff_t@ $\rightarrow$ @float@) with managed length @N@.
    416 The new-array library provides the trait @ar@, so-defined.
     407The new-array library provides the trait @ix@, so-defined.
    417408With it, the original declaration can be generalized with the same body.
    418409\lstinput{43-44}{hello-md.cfa}
    419410\lstinput[aboveskip=0pt]{145-145}{hello-md.cfa}
    420411The nontrivial slicing in this example now allows passing a \emph{noncontiguous} slice to @print1d@, where the new-array library provides a ``subscript by all'' operation for this purpose.
    421 In a multi-dimensional subscript operation, any dimension given as @all@ is a placeholder, \ie ``not yet subscripted by a value'', waiting for such a value, implementing the @ar@ trait.
     412In a multi-dimensional subscript operation, any dimension given as @all@ is a placeholder, \ie ``not yet subscripted by a value'', waiting for such a value, implementing the @ix@ trait.
    422413\lstinput{150-151}{hello-md.cfa}
    423414
     
    480471In both cases, value 2 selects from the coarser dimension (rows of @x@),
    481472while the value 3 selects from the finer dimension (columns of @x@).
    482 The figure illustrates the value of each subexpression, comparing how numeric subscripting proceeds from @x@, \vs from @x[all]@.
     473The figure illustrates the value of each subexpression, comparing how numeric subscripting proceeds from @x@, vs from @x[all]@.
    483474Proceeding from @x@ gives the numeric indices as coarse then fine, while proceeding from @x[all]@ gives them fine then coarse.
    484475These two starting expressions, which are the example's only multidimensional subexpressions
    485476(those that received zero numeric indices so far), are illustrated with vertical steps where a \emph{first} numeric index would select.
    486477
    487 The figure's presentation offers an intuition answering to: What is an atomic element of @x[all]@?
    488 From there, @x[all]@ itself is simply a two-dimensional array, in the strict C sense, of these building blocks.
     478The figure's presentation offers an intuition answering, What is an atomic element of @x[all]@?
     479From there, @x[all]@ itself is simply a two-dimensional array, in the strict C sense, of these strange building blocks.
    489480An atom (like the bottommost value, @x[all][3][2]@), is the contained value (in the square box)
    490481and a lie about its size (the wedge above it, growing upward).
    491 An array of these atoms (like the intermediate @x[all][3]@) is just a contiguous arrangement of them, done according to their size;
    492 call such an array a column.
    493 A column is almost ready to be arranged into a matrix;
    494 it is the \emph{contained value} of the next-level building block, but another lie about size is required.
    495 At first, an atom needs to be arranged as if it were bigger, but now a column needs to be arranged as if it is smaller (the wedge above it, shrinking upward).
     482An array of these atoms (like the intermediate @x[all][3]@) is just a contiguous arrangement of them,
     483done according to their size, as announced.  Call such an array a column.
     484A column is almost ready to be arranged into a matrix; it is the \emph{contained value} of the next-level building block,
     485but another lie about size is required.
     486At first, an atom needed to be arranged as if it were bigger,
     487but now a column needs to be arranged as if it is smaller (the wedge above it, shrinking upward).
    496488These lying columns, arranged contiguously according to their size (as announced) form the matrix @x[all]@.
    497 Because @x[all]@ takes indices, first for the fine stride, then for the coarse stride, it achieves the requirement of representing the transpose of @x@.
    498 Yet every time the programmer presents an index, a C-array subscript is achieving the offset calculation.
     489Because @x[all]@ takes indices, first for the fine stride, then for the coarse stride,
     490it achieves the requirement of representing the transpose of @x@.
     491Yet every time the programmer presents an index, a mere C-array subscript is achieving the offset calculation.
    499492
    500493In the @x[all]@ case, after the finely strided subscript is done (column 3 is selected),
     
    502495compared with where analogous rows appear when the row-level option is presented for @x@.
    503496
    504 \PAB{I don't understand this paragraph: These size lies create an appearance of overlap.
    505 For example, in \lstinline{x[all]}, the shaded band touches atoms 2.0, 2.1, 2.2, 2.3, 1.4, 1.5 and 1.6.
     497These size lies create an appearance of overlap.
     498For example, in @x[all]@, the shaded band touches atoms 2.0, 2.1, 2.2, 2.3, 1.4, 1.5 and 1.6.
    506499But only the atom 2.3 is storing its value there.
    507 The rest are lying about (conflicting) claims on this location, but never exercising these alleged claims.}
     500The rest are lying about (conflicting) claims on this location, but never exercising these alleged claims.
    508501
    509502Lying is implemented as casting.
     
    511504This structure uses one type in its internal field declaration and offers a different type as the return of its subscript operator.
    512505The field within is a plain-C array of the fictional type, which is 7 floats long for @x[all][3][2]@ and 1 float long for @x[all][3]@.
    513 The subscript operator presents what is really inside, by casting to the type below the wedge of the lie.
     506The subscript operator presents what's really inside, by casting to the type below the wedge of lie.
    514507
    515508%  Does x[all] have to lie too?  The picture currently glosses over how it it advertises a size of 7 floats.  I'm leaving that as an edge case benignly misrepresented in the picture.  Edge cases only have to be handled right in the code.
    516509
    517 Casting, overlapping, and lying are unsafe.
    518 The mission is to implement a style-1 feature in the type system for safe use by a programmer.
    519 The offered style-1 system is allowed to be internally unsafe,
    520 just as C's implementation of a style-2 system (upon a style-3 system) is unsafe within, even when the programmer is using it without casts or pointer arithmetic.
    521 Having a style-1 system relieves the programmer from resorting to unsafe pointer arithmetic when working with noncontiguous slices.
    522 
    523 % PAB: repeat from previous paragraph.
    524 % The choice to implement this style-1 system upon C's style-2 arrays, rather than its style-3 pointer arithmetic, reduces the attack surface of unsafe code.
    525 % My casting is unsafe, but I do not do any pointer arithmetic.
    526 % When a programmer works in the common-case style-2 subset (in the no-@[all]@ top of Figure~\ref{fig:subscr-all}), my casts are identities, and the C compiler is doing its usual displacement calculations.
    527 % If I had implemented my system upon style-3 pointer arithmetic, then this common case would be circumventing C's battle-hardened displacement calculations in favour of my own.
    528 
    529 % \noindent END: Paste looking for a home
     510Casting, overlapping and lying are unsafe.
     511The mission here is to implement a style-2 feature that the type system helps the programmer use safely.
     512The offered style-2 system is allowed to be internally unsafe,
     513just as C's implementation of a style-3 system (upon a style-4 system) is unsafe within,
     514even when the programmer is using it without casts or pointer arithmetic.
     515Having a style-2 system relieves the programmer from resorting to unsafe pointer arithmetic when working with noncontiguous slices.
     516
     517The choice to implement this style-2 system upon C's style-3 arrays, rather than its style-4 pointer arithmetic,
     518reduces the attack surface of unsafe code.
     519My casting is unsafe, but I do not do any pointer arithmetic.
     520When a programmer works in the common-case style-3 subset (in the no-@[all]@ top of Figure~\ref{fig:subscr-all}),
     521my casts are identities, and the C compiler is doing its usual displacement calculations.
     522If I had implemented my system upon style-4 pointer arithmetic,
     523then this common case would be circumventing C's battle-hardened displacement calculations in favour of my own.
     524
     525\noindent END: Paste looking for a home
    530526
    531527The new-array library defines types and operations that ensure proper elements are accessed soundly in spite of the overlapping.
    532 The @arpk@ structure and its @-[i]@ operator are defined as:
    533 \begin{cfa}
    534 forall(
    535         [N],                                    $\C{// length of current dimension}$
    536         S & | sized(S),                 $\C{// masquerading-as}$
    537         Timmed &,                               $\C{// immediate element, often another array}$
    538         Tbase &                                 $\C{// base element, e.g. float, never array}$
     528The private @arpk@ structure (array with explicit packing) is generic over these two types (and more): the contained element, what it is masquerading as.
     529This structure's public interface is the @array(...)@ construction macro and the two subscript operators.
     530Construction by @array@ initializes the masquerading-as type information to be equal to the contained-element information.
     531Subscripting by @all@ rearranges the order of masquerading-as types to achieve, in general, nontrivial striding.
     532Subscripting by a number consumes the masquerading-as size of the contained element type, does normal array stepping according to that size, and returns there element found there, in unmasked form.
     533
     534The @arpk@ structure and its @-[i]@ operator are thus defined as:
     535\begin{cfa}
     536forall( ztype(N),                       $\C{// length of current dimension}$
     537        dtype(S) | sized(S),    $\C{// masquerading-as}$
     538        dtype E_im,                             $\C{// immediate element, often another array}$
     539        dtype E_base                    $\C{// base element, e.g. float, never array}$
    539540) { // distribute forall to each element
    540541        struct arpk {
    541542                S strides[N];           $\C{// so that sizeof(this) is N of S}$
    542543        };
    543         // expose Timmed, stride by S
    544         static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, long int i ) {
    545                 subcheck( a, i, 0, N );
    546                 return (Timmed &)a.strides[i];
     544        // expose E_im, stride by S
     545        E_im & ?[?]( arpk(N, S, E_im, E_base) & a, ptrdiff_t i ) {
     546                return (E_im &) a.strides[i];
    547547        }
    548548}
    549549\end{cfa}
    550 The private @arpk@ structure (array with explicit packing) is generic over four types: dimension length, masquerading-as, ...
    551 This structure's public interface is hidden behind the @array(...)@ macro and the subscript operator.
    552 Construction by @array@ initializes the masquerading-as type information to be equal to the contained-element information.
    553 Subscripting by @all@ rearranges the order of masquerading-as types to achieve, in general, nontrivial striding.
    554 Subscripting by a number consumes the masquerading-as size of the contained element type, does normal array stepping according to that size, and returns there element found there, in unmasked form.
    555550
    556551An instantiation of the @arpk@ generic is given by the @array(E_base, N0, N1, ...)@ expansion, which is @arpk( N0, Rec, Rec, E_base )@, where @Rec@ is @array(E_base, N1, ...)@.
     
    573568This section provides a demonstration of the effect.
    574569
    575 The experiment compares the \CFA array system with the padded-room system [TODO:xref] most typically exemplified by Java arrays, but also reflected in the \CC pattern where restricted vector usage models a checked array.
     570The experiment compares the \CFA array system with the padded-room system [TODO:xref] most typically exemplified by Java arrays, but also reflected in the C++ pattern where restricted vector usage models a checked array.
    576571The essential feature of this padded-room system is the one-to-one correspondence between array instances and the symbolic bounds on which dynamic checks are based.
    577 The experiment compares with the \CC version to keep access to generated assembly code simple.
    578 
    579 As a control case, a simple loop (with no reused dimension sizes) is seen to get the same optimization treatment in both the \CFA and \CC versions.
     572The experiment compares with the C++ version to keep access to generated assembly code simple.
     573
     574As a control case, a simple loop (with no reused dimension sizes) is seen to get the same optimization treatment in both the \CFA and C++ versions.
    580575When the programmer treats the array's bound correctly (making the subscript ``obviously fine''), no dynamic bound check is observed in the program's optimized assembly code.
    581576But when the bounds are adjusted, such that the subscript is possibly invalid, the bound check appears in the optimized assembly, ready to catch an occurrence the mistake.
     
    594589\section{Comparison with other arrays}
    595590
    596 
    597 \subsection{Rust}
    598 
    599591\CFA's array is the first lightweight application of dependently-typed bound tracking to an extension of C.
    600 Other extensions of C that apply dependently-typed bound tracking are heavyweight, in that the bound tracking is part of a linearly-typed ownership-system, which further helps guarantee statically the validity of every pointer deference.
     592Other extensions of C that apply dependently-typed bound tracking are heavyweight, in that the bound tracking is part of a linearly typed ownership system that further helps guarantee statically the validity of every pointer deference.
    601593These systems, therefore, ask the programmer to convince the type checker that every pointer dereference is valid.
    602594\CFA imposes the lighter-weight obligation, with the more limited guarantee, that initially-declared bounds are respected thereafter.
     
    606598The \CFA array, applied to accordion structures [TOD: cross-reference] \emph{implies} the necessary pointer arithmetic, generated automatically, and not appearing at all in a user's program.
    607599
    608 
    609 \subsection{Java}
    610 
    611 Java arrays are arrays-of-arrays because all objects are references \see{\VRef{toc:mdimpl}}.
    612 For each array, Java implicitly storages the array dimension in a descriptor, supporting array length, subscript checking, and allowing dynamically-sized array-parameter declarations.
    613 \begin{cquote}
     600\subsection{Safety in a padded room}
     601
     602Java's array [TODO:cite] is a straightforward example of assuring safety against undefined behaviour, at a cost of expressiveness for more applied properties.
     603Consider the array parameter declarations in:
     604
    614605\begin{tabular}{rl}
    615606C      &  @void f( size_t n, size_t m, float x[n][m] );@ \\
    616 Java   &  @void f( float x[][] );@
     607Java   &  @void f( float[][] a );@
    617608\end{tabular}
    618 \end{cquote}
    619 However, in the C prototype, the parameters @n@ and @m@  are documentation only as the intended size of the first and second dimension of @x@.
    620 \VRef[Figure]{f:JavaVsCTriangularMatrix} compares a triangular matrix (array-of-arrays) in dynamically safe Java to unsafe C.
    621 Each dynamically sized row in Java stores its dimension, while C requires the programmer to manage these sizes explicitly (@rlnth@).
    622 All subscripting is Java has bounds checking, while C has none.
    623 Both Java and C require explicit null checking, otherwise there is a runtime failure.
    624 
    625 \begin{figure}
    626 \setlength{\tabcolsep}{15pt}
    627 \begin{tabular}{ll@{}}
    628 \begin{java}
    629 int m[][] = {  // triangular matrix
    630         new int [4],
    631         new int [3],
    632         new int [2],
    633         new int [1],
    634         null
    635 };
    636 
    637 for ( int r = 0; r < m.length; r += 1 ) {
    638         if ( m[r] == null ) continue;
    639         for ( int c = 0; c < m[r].length; c += 1 ) {
    640                 m[r][c] = c + r; // subscript checking
    641         }
    642 
    643 }
    644 
    645 for ( int r = 0; r < m.length; r += 1 ) {
    646         if ( m[r] == null ) {
    647                 System.out.println( "null row" );
    648                 continue;
    649         }
    650         for ( int c = 0; c < m[r].length; c += 1 ) {
    651                 System.out.print( m[r][c] + " " );
    652         }
    653         System.out.println();
    654 
    655 }
    656 \end{java}
    657 &
    658 \begin{cfa}
    659 int * m[5] = {  // triangular matrix
    660         calloc( 4, sizeof(int) ),
    661         calloc( 3, sizeof(int) ),
    662         calloc( 2, sizeof(int) ),
    663         calloc( 1, sizeof(int) ),
    664         NULL
    665 };
    666 int rlnth = 4;
    667 for ( int r = 0; r < 5; r += 1 ) {
    668         if ( m[r] == NULL ) continue;
    669         for ( int c = 0; c < rlnth; c += 1 ) {
    670                 m[r][c] = c + r; // no subscript checking
    671         }
    672         rlnth -= 1;
    673 }
    674 rlnth = 4;
    675 for ( int r = 0; r < 5; r += 1 ) {
    676         if ( m[r] == NULL ) {
    677                 printf( "null row\n" );
    678                 continue;
    679         }
    680         for ( int c = 0; c < rlnth; c += 1 ) {
    681                 printf( "%d ", m[r][c] );
    682         }
    683         printf( "\n" );
    684         rlnth -= 1;
    685 }
    686 \end{cfa}
    687 \end{tabular}
    688 \caption{Java (left) \vs C (right) Triangular Matrix}
    689 \label{f:JavaVsCTriangularMatrix}
    690 \end{figure}
    691 
    692 The downside of the arrays-of-arrays approach is performance due to pointer chasing versus pointer arithmetic for a contiguous arrays.
    693 Furthermore, there is the cost of managing the implicit array descriptor.
    694 It is unlikely that a JIT can dynamically rewrite an arrays-of-arrays form into a contiguous form.
    695 
    696 
    697 \subsection{\CC}
    698 
    699 Because C arrays are difficult and dangerous, the mantra for \CC programmers is to use @std::vector@ in place of the C array.
    700 While the vector size can grow and shrink dynamically, \vs a fixed-size dynamic size with VLAs, the cost of this extra feature is mitigated by preallocating the maximum size (like the VLA) at the declaration (one dynamic call) to avoid using @push_back@.
    701 \begin{c++}
    702 vector< vector< int > > m( 5, vector<int>(8) ); // initialize size of 5 x 8 with 6 dynamic allocations
    703 \end{c++}
    704 Multidimensional arrays are arrays-of-arrays with associated costs.
    705 Each @vector@ array has an array descriptor contain the dimension, which allows bound checked using @x.at(i)@ in place of @x[i]@.
    706 Used with these restrictions, out-of-bound accesses are caught, and in-bound accesses never exercise the vector's ability to grow, preventing costly reallocate and copy, and never invalidate references to contained values.
    707 This scheme matches Java's safety and expressiveness exactly, but with the inherent costs.
    708 
     609
     610Java's safety against undefined behaviour assures the callee that, if @x@ is non-null, then @a.length@ is a valid access (say, evaluating to the number $\ell$) and if @i@ is in $[0, \ell)$ then @x[i]@ is a valid access.
     611If a value of @i@ outside this range is used, a runtime error is guaranteed.
     612In these respects, C offers no guarantees at all.
     613Notably, the suggestion that @n@ is the intended size of the first dimension of @x@ is documentation only.
     614Indeed, many might prefer the technically equivalent declarations @float x[][m]@ or @float (*a)[m]@ as emphasizing the ``no guarantees'' nature of an infrequently used language feature, over using the opportunity to explain a programmer intention.
     615Moreover, even if @x[0][0]@ is valid for the purpose intended, C's basic infamous feature is the possibility of an @i@, such that @x[i][0]@ is not valid for the same purpose, and yet, its evaluation does not produce an error.
     616
     617Java's lack of expressiveness for more applied properties means these outcomes are possible:
     618\begin{itemize}
     619\item @x[0][17]@ and @x[2][17]@ are valid accesses, yet @x[1][17]@ is a runtime error, because @x[1]@ is a null pointer
     620\item the same observation, now because @x[1]@ refers to an array of length 5
     621\item execution times vary, because the @float@ values within @x@ are sometimes stored nearly contiguously, and other times, not at all
     622\end{itemize}
     623C's array has none of these limitations, nor do any of the ``array language'' comparators discussed in this section.
     624
     625This Java level of safety and expressiveness is also exemplified in the C family, with the commonly given advice [TODO:cite example], for C++ programmers to use @std::vector@ in place of the C++ language's array, which is essentially the C array.
     626The advice is that, while a vector is also more powerful (and quirky) than an array, its capabilities include options to preallocate with an upfront size, to use an available bound-checked accessor (@a.at(i)@ in place of @x[i]@), to avoid using @push_back@, and to use a vector of vectors.
     627Used with these restrictions, out-of-bound accesses are stopped, and in-bound accesses never exercise the vector's ability to grow, which is to say, they never make the program slow to reallocate and copy, and they never invalidate the program's other references to the contained values.
     628Allowing this scheme the same referential integrity assumption that \CFA enjoys [TODO:xref], this scheme matches Java's safety and expressiveness exactly.
     629[TODO: decide about going deeper; some of the Java expressiveness concerns have mitigations, up to even more tradeoffs.]
    709630
    710631\subsection{Levels of dependently typed arrays}
     
    734655it can also do these other cool checks, but watch how I can mess with its conservativeness and termination
    735656
    736 Two current, state-of-the-art array languages, Dex\cite{arr:dex:long} and Futhark\cite{arr:futhark:tytheory}, offer novel contributions concerning similar, restricted dependent types for tracking array length.
     657Two current, state-of-the-art array languages, Dex\cite{arr:dex:long} and Futhark\cite{arr:futhark:tytheory}, offer offer novel contributions concerning similar, restricted dependent types for tracking array length.
    737658Unlike \CFA, both are garbage-collected functional languages.
    738659Because they are garbage-collected, referential integrity is built-in, meaning that the heavyweight analysis, that \CFA aims to avoid, is unnecessary.
     
    806727[TODO: introduce Ada in the comparators]
    807728
    808 In Ada and Dex, an array is conceived as a function whose domain must satisfy only certain structural assumptions, while in C, \CC, Java, Futhark and \CFA today, the domain is a prefix of the natural numbers.
     729In Ada and Dex, an array is conceived as a function whose domain must satisfy only certain structural assumptions, while in C, C++, Java, Futhark and \CFA today, the domain is a prefix of the natural numbers.
    809730The generality has obvious aesthetic benefits for programmers working on scheduling resources to weekdays, and for programmers who prefer to count from an initial number of their own choosing.
    810731
  • doc/theses/mike_brooks_MMath/programs/hello-accordion.cfa

    rce02877 r38e20a80  
    99
    1010forall( T, @[NprovTerty]@, @[Nmunicipalities]@ )
    11 struct CanPop {
     11struct CanadaPop {
    1212        array( T, @NprovTerty@ ) provTerty; $\C{// nested VLA}$
    1313        array( T, @Nmunicipalities@ ) municipalities; $\C{// nested VLA}$
     
    1919
    2020forall( T, [NprovTerty], [Nmunicipalities] )
    21         void ?{}( T &, CanPop( T, NprovTerty, Nmunicipalities ) & this ) {}
     21        void ?{}( T &, CanadaPop( T, NprovTerty, Nmunicipalities ) & this ) {}
    2222
    2323forall( T &, [NprovTerty], [Nmunicipalities] )
    24         void ^?{}( CanPop( T, NprovTerty, Nmunicipalities ) & this ) {}
     24        void ^?{}( CanadaPop( T, NprovTerty, Nmunicipalities ) & this ) {}
    2525
    2626
     
    3939
    4040forall( T, [NprovTerty], [Nmunicipalities] )
    41 void check( CanPop( T, NprovTerty, Nmunicipalities ) & pop ) with( pop ) {
     41void check( CanadaPop( T, NprovTerty, Nmunicipalities ) & pop ) with( pop ) {
    4242        total_pt = total_mun = 0;
    4343        for ( i; NprovTerty ) total_pt += provTerty[i];
     
    6060int main( int argc, char * argv[] ) {
    6161        const int npt = ato( argv[1] ), nmun = ato( argv[2] );
    62         @CanPop( int, npt, nmun ) pop;@
     62        @CanadaPop( int, npt, nmun ) pop;@
    6363        // read in population numbers
    6464        @check( pop );@
     
    7171Total province/territory: 36,991,981
    7272Total municipalities: 36,991,981
    73 $\$$ ./a.out  13  3654
    74 Total province/territory: 36,991,981
    75 Total municipalities: 36,991,981
    7673*/
    7774
  • doc/theses/mike_brooks_MMath/programs/hello-array.cfa

    rce02877 r38e20a80  
    99
    1010forall( [@N@] )                                                         $\C{// array dimension}$
    11 array( bool, @N@ ) & f( array( float, @N@ ) & x, array( float, @N@ ) & y ) {
     11array( bool, @N@) & f( array( float, @N@ ) & x, array( float, @N@ ) & y ) {
    1212        array( bool, @N@ ) & ret = *@alloc@();  $\C{// sizeof ret  used by alloc}$
    1313        for ( i; @N@ ) {
     
    2929
    3030int main( int argc, char * argv[] ) {
    31         const int @dim@ = ato( argv[1] );               $\C{// deduce conversion type}$
    32         array( float, @dim@ ) x, y;                             $\C{// VLAs}$
    33         for ( i; dim ) {                                                $\C{// initialize arrays}$
     31        const int @n@ = ato( argv[1] );                 $\C{// deduce conversion type}$
     32        array( float, @n@ ) x, y;                               $\C{// VLAs}$
     33        for ( i; n ) {                                                  $\C{// initialize arrays}$
    3434                x[i] = 3.14 / (i + 1);
    3535                y[i] = x[i] + 0.005 ;
    3636        }
    37         array( bool, @dim@ ) & result = @f( x, y )@; $\C{// call}$
     37        array( bool, @n@ ) & result = @f( x, y )@; $\C{// call}$
    3838        sout | "result: " | nonl;                               $\C{// print result}$
    39         for ( i; dim )
     39        for ( i; n )
    4040                sout | result[i] | nonl;
    4141        sout | nl;
  • doc/theses/mike_brooks_MMath/programs/hello-md.cfa

    rce02877 r38e20a80  
    138138
    139139
    140 print1d_cstyle( @m[ 2 ]@ );  $\C{// row 2:  2.0  2.1  2.2  2.3  2.4  2.5  2.6}$
     140print1d_cstyle( m[ 2 ] );  $\C{// row 2:  2.0  2.1  2.2  2.3  2.4  2.5  2.6}$
    141141
    142142
  • doc/theses/mike_brooks_MMath/uw-ethesis-frontpgs.tex

    rce02877 r38e20a80  
    140140
    141141I would like to thank all the little people who made this thesis possible.
    142 
    143 Finally, a special thank you to Huawei Canada for funding this work.
    144142\cleardoublepage
    145143\phantomsection    % allows hyperref to link to the correct page
  • doc/theses/mike_brooks_MMath/uw-ethesis.tex

    rce02877 r38e20a80  
    105105\lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    106106\lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    107 \lstnewenvironment{java}[1][]{\lstset{language=java,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
    108107\lstset{inputpath={programs}}
    109108
  • doc/user/user.tex

    rce02877 r38e20a80  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Fri Jul 26 06:56:11 2024
    14 %% Update Count     : 6955
     13%% Last Modified On : Tue Jul  9 10:43:40 2024
     14%% Update Count     : 6887
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    15981598and implicitly opened \emph{after} a function-body open, to give them higher priority:
    15991599\begin{cfa}
    1600 void f( S & s, char ®c® ) with ( s ) ®with( §\emph{\R{params}}§ )® { // syntax disallowed, illustration only
     1600void f( S & s, char ®c® ) with ( s ) ®with( §\emph{\R{params}}§ )® { // syntax not allowed, illustration only
    16011601        s.c = ®c;®  i = 3;  d = 5.5;
    16021602}
     
    33133313for example, the following is incorrect:
    33143314\begin{cfa}
    3315 * [ int x ] f () fp; §\C{// routine name "f" is disallowed}§
    3316 \end{cfa}
    3317 
    3318 
    3319 \section{Default and Named Parameter}
    3320 
    3321 Default\index{default parameter}\index{parameter!default} and named\index{named parameter}\index{parameter!named} parameters~\cite{Hardgrave76}\footnote{
     3315* [ int x ] f () fp; §\C{// routine name "f" is not allowed}§
     3316\end{cfa}
     3317
     3318
     3319\section{Named and Default Arguments}
     3320
     3321Named\index{named arguments}\index{arguments!named} and default\index{default arguments}\index{arguments!default} arguments~\cite{Hardgrave76}\footnote{
    33223322Francez~\cite{Francez77} proposed a further extension to the named-parameter passing style, which specifies what type of communication (by value, by reference, by name) the argument is passed to the routine.}
    33233323are two mechanisms to simplify routine call.
    3324 
    3325 
    3326 \subsection{Default}
    3327 
    3328 A default parameter associates a default value with a parameter so it can be optionally specified in the argument list.
    3329 For example, given the routine prototype:
    3330 \begin{cfa}
    3331 void f( int x ®= 1®, int y ®= 2®, int z ®= 3® );
    3332 \end{cfa}
    3333 allowable calls are:
    3334 \begin{cquote}
    3335 \setlength{\tabcolsep}{0.75in}
    3336 \begin{tabular}{@{}ll@{}}
    3337 \textbf{positional arguments} & \textbf{empty arguments} \\
    3338 \begin{cfa}
    3339 f();                    §\C[0.75in]{// rewrite \(\Rightarrow\) f( 1, 2, 3 )}§
    3340 f( 4 );                 §\C{// rewrite \(\Rightarrow\) f( 4, 2, 3 )}§
    3341 f( 4, 4 );              §\C{// rewrite \(\Rightarrow\) f( 4, 4, 3 )}§
    3342 f( 4, 4, 4 );   §\C{// rewrite \(\Rightarrow\) f( 4, 4, 4 )}\CRT§
    3343 
    3344 
    3345 
    3346 \end{cfa}
    3347 &
    3348 \begin{cfa}
    3349 f( ®?®, 4, 4 );         §\C[1.0in]{// rewrite \(\Rightarrow\) f( 1, 4, 4 )}§
    3350 f( 4, ®?®, 4 );         §\C{// rewrite \(\Rightarrow\) f( 4, 2, 4 )}§
    3351 f( 4, 4, ®?® );         §\C{// rewrite \(\Rightarrow\) f( 4, 4, 3 )}§
    3352 f( 4, ®?®, ®?® );       §\C{// rewrite \(\Rightarrow\) f( 4, 2, 3 )}§
    3353 f( ®?®, 4, ®?® );       §\C{// rewrite \(\Rightarrow\) f( 1, 4, 3 )}§
    3354 f( ®?®, ®?®, 4 );       §\C{// rewrite \(\Rightarrow\) f( 1, 2, 4 )}§
    3355 f( ®?®, ®?®, ®?® );     §\C{// rewrite \(\Rightarrow\) f( 1, 2, 3 )}\CRT§
    3356 \end{cfa}
    3357 \end{tabular}
    3358 \end{cquote}
    3359 where the ©?© selects the default value as the argument.
     3324Both mechanisms are discussed with respect to \CFA.
     3325\begin{description}
     3326\item[Named (or Keyword) Arguments:]
     3327provide the ability to specify an argument to a routine call using the parameter name rather than the position of the parameter.
     3328For example, given the routine:
     3329\begin{cfa}
     3330void p( int x, int y, int z ) {...}
     3331\end{cfa}
     3332a positional call is:
     3333\begin{cfa}
     3334p( 4, 7, 3 );
     3335\end{cfa}
     3336whereas a named (keyword) call may be:
     3337\begin{cfa}
     3338p( z : 3, x : 4, y : 7 );  §\C{// rewrite \(\Rightarrow\) p( 4, 7, 3 )}§
     3339\end{cfa}
     3340Here the order of the arguments is unimportant, and the names of the parameters are used to associate argument values with the corresponding parameters.
     3341The compiler rewrites a named call into a positional call.
     3342The advantages of named parameters are:
     3343\begin{itemize}
     3344\item
     3345Remembering the names of the parameters may be easier than the order in the routine definition.
     3346\item
     3347Parameter names provide documentation at the call site (assuming the names are descriptive).
     3348\item
     3349Changes can be made to the order or number of parameters without affecting the call (although the call must still be recompiled).
     3350\end{itemize}
     3351
     3352Unfortunately, named arguments do not work in C-style programming-languages because a routine prototype is not required to specify parameter names, nor do the names in the prototype have to match with the actual definition.
     3353For example, the following routine prototypes and definition are all valid.
     3354\begin{cfa}
     3355void p( int, int, int ); §\C{// equivalent prototypes}§
     3356void p( int x, int y, int z );
     3357void p( int y, int x, int z );
     3358void p( int z, int y, int x );
     3359void p( int q, int r, int s ) {} §\C{// match with this definition}§
     3360\end{cfa}
     3361Forcing matching parameter names in routine prototypes with corresponding routine definitions is possible, but goes against a strong tradition in C programming.
     3362Alternatively, prototype definitions can be eliminated by using a two-pass compilation, and implicitly creating header files for exports.
     3363The former is easy to do, while the latter is more complex.
     3364
     3365Furthermore, named arguments do not work well in a \CFA-style programming-languages because they potentially introduces a new criteria for type matching.
     3366For example, it is technically possible to disambiguate between these two overloaded definitions of ©f© based on named arguments at the call site:
     3367\begin{cfa}
     3368int f( int i, int j );
     3369int f( int x, double y );
     3370
     3371f( j : 3, i : 4 ); §\C{// 1st f}§
     3372f( x : 7, y : 8.1 ); §\C{// 2nd f}§
     3373f( 4, 5 );  §\C{// ambiguous call}§
     3374\end{cfa}
     3375However, named arguments compound routine resolution in conjunction with conversions:
     3376\begin{cfa}
     3377f( i : 3, 5.7 ); §\C{// ambiguous call ?}§
     3378\end{cfa}
     3379Depending on the cost associated with named arguments, this call could be resolvable or ambiguous.
     3380Adding named argument into the routine resolution algorithm does not seem worth the complexity.
     3381Therefore, \CFA does \emph{not} attempt to support named arguments.
     3382
     3383\item[Default Arguments]
     3384provide the ability to associate a default value with a parameter so it can be optionally specified in the argument list.
     3385For example, given the routine:
     3386\begin{cfa}
     3387void p( int x = 1, int y = 2, int z = 3 ) {...}
     3388\end{cfa}
     3389the allowable positional calls are:
     3390\begin{cfa}
     3391p(); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}§
     3392p( 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}§
     3393p( 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}§
     3394p( 4, 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 4 )}§
     3395// empty arguments
     3396p(  , 4, 4 ); §\C{// rewrite \(\Rightarrow\) p( 1, 4, 4 )}§
     3397p( 4,  , 4 ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 4 )}§
     3398p( 4, 4,   ); §\C{// rewrite \(\Rightarrow\) p( 4, 4, 3 )}§
     3399p( 4,  ,   ); §\C{// rewrite \(\Rightarrow\) p( 4, 2, 3 )}§
     3400p(  , 4,   ); §\C{// rewrite \(\Rightarrow\) p( 1, 4, 3 )}§
     3401p(  ,  , 4 ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 4 )}§
     3402p(  ,  ,   ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 3 )}§
     3403\end{cfa}
    33603404Here the missing arguments are inserted from the default values in the parameter list.
    33613405The compiler rewrites missing default values into explicit positional arguments.
     
    33643408\item
    33653409Routines with a large number of parameters are often very generalized, giving a programmer a number of different options on how a computation is performed.
    3366 For many of these routines, there are standard or default settings that work for the majority of computations.
     3410For many of these kinds of routines, there are standard or default settings that work for the majority of computations.
    33673411Without default values for parameters, a programmer is forced to specify these common values all the time, resulting in long argument lists that are error prone.
    33683412\item
     
    33783422Instead, a default value is used, which may not be the programmer's intent.
    33793423
    3380 Default parameters may only appear in a prototype versus definition context:
    3381 \begin{cfa}
    3382 void f( int x, int y = 2, int z = 3 );  §\C{// prototype: allowed}§
    3383 void f( int, int = 2, int = 3 );                §\C{// prototype: allowed}§
    3384 void f( int x, int y = 2, int z = 3 ) ®{}® §\C{// definition: disallowed}§
     3424Default values may only appear in a prototype versus definition context:
     3425\begin{cfa}
     3426void p( int x, int y = 2, int z = 3 ); §\C{// prototype: allowed}§
     3427void p( int, int = 2, int = 3 ); §\C{// prototype: allowed}§
     3428void p( int x, int y = 2, int z = 3 ) {} §\C{// definition: not allowed}§
    33853429\end{cfa}
    33863430The reason for this restriction is to allow separate compilation.
    3387 Multiple prototypes with different default values is undefined.
     3431Multiple prototypes with different default values is an error.
     3432\end{description}
     3433
     3434Ellipse (``...'') arguments present problems when used with default arguments.
     3435The conflict occurs because both named and ellipse arguments must appear after positional arguments, giving two possibilities:
     3436\begin{cfa}
     3437p( /* positional */, ... , /* named */ );
     3438p( /* positional */, /* named */, ... );
     3439\end{cfa}
     3440While it is possible to implement both approaches, the first possibly is more complex than the second, \eg:
     3441\begin{cfa}
     3442p( int x, int y, int z, ... );
     3443p( 1, 4, 5, 6, z : 3, y : 2 ); §\C{// assume p( /* positional */, ... , /* named */ );}§
     3444p( 1, z : 3, y : 2, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§
     3445\end{cfa}
     3446In the first call, it is necessary for the programmer to conceptually rewrite the call, changing named arguments into positional, before knowing where the ellipse arguments begin.
     3447Hence, this approach seems significantly more difficult, and hence, confusing and error prone.
     3448In the second call, the named arguments separate the positional and ellipse arguments, making it trivial to read the call.
     3449
     3450The problem is exacerbated with default arguments, \eg:
     3451\begin{cfa}
     3452void p( int x, int y = 2, int z = 3... );
     3453p( 1, 4, 5, 6, z : 3 ); §\C{// assume p( /* positional */, ... , /* named */ );}§
     3454p( 1, z : 3, 4, 5, 6 ); §\C{// assume p( /* positional */, /* named */, ... );}§
     3455\end{cfa}
     3456The first call is an error because arguments 4 and 5 are actually positional not ellipse arguments;
     3457therefore, argument 5 subsequently conflicts with the named argument z : 3.
     3458In the second call, the default value for y is implicitly inserted after argument 1 and the named arguments separate the positional and ellipse arguments, making it trivial to read the call.
     3459For these reasons, \CFA requires named arguments before ellipse arguments.
     3460Finally, while ellipse arguments are needed for a small set of existing C routines, like ©printf©, the extended \CFA type system largely eliminates the need for ellipse arguments \see{\VRef{s:Overloading}}, making much of this discussion moot.
    33883461
    33893462Default arguments and overloading \see{\VRef{s:Overloading}} are complementary.
     
    33933466\multicolumn{1}{c@{\hspace{3em}}}{\textbf{default arguments}}   & \multicolumn{1}{c}{\textbf{overloading}}      \\
    33943467\begin{cfa}
    3395 void f( int x, int y = 2, int z = 3 ) {...}
     3468void p( int x, int y = 2, int z = 3 ) {...}
    33963469
    33973470
     
    33993472&
    34003473\begin{cfa}
    3401 void f( int x, int y, int z ) {...}
    3402 void f( int x ) { f( x, 2, 3 ); }
    3403 void f( int x, int y ) { f( x, y, 3 ); }
     3474void p( int x, int y, int z ) {...}
     3475void p( int x ) { p( x, 2, 3 ); }
     3476void p( int x, int y ) { p( x, y, 3 ); }
    34043477\end{cfa}
    34053478\end{tabular}
    34063479\end{cquote}
    34073480the number of required overloaded routines is linear in the number of default values, which is unacceptable growth.
    3408 In general, overloading is used over default parameters, if the body of the routine is significantly different.
    3409 Furthermore, overloading cannot handle accessing default arguments in the middle of a positional list.
    3410 \begin{cfa}
    3411 f( 1, ®?®, 5 );                                                 §\C{// rewrite \(\Rightarrow\) f( 1, 2, 5 )}§
    3412 \end{cfa}
    3413 
    3414 
    3415 \subsection{Named (or Keyword)}
    3416 
    3417 A named (keyword) parameter provides the ability to specify an argument to a routine call using the parameter name rather than the position of the parameter.
    3418 For example, given the routine prototype:
    3419 \begin{cfa}
    3420 void f( int ®?®x, int ®?®y, int ®?®z );
    3421 \end{cfa}
    3422 allowable calls are:
    3423 \begin{cfa}
    3424 f( ?x = 3, ?y = 4, ?z = 5 );                    §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
    3425 f( ?y = 4, ?z = 5, ?x = 3 );                    §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
    3426 f( ?z = 5, ?x = 3, ?y = 4 );                    §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
    3427 f( ?x = 3, ?z = 5, ?y = 4 );                    §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
    3428 \end{cfa}
    3429 Here the ordering of the the parameters and arguments is unimportant, and the names of the parameters are used to associate argument values with the corresponding parameters.
    3430 The compiler rewrites a named call into a positional call.
    3431 Note, the syntax ©?x = 3© is necessary for the argument, because ©x = 3© has an existing meaning, \ie assign ©3© to ©x© and pass the value of ©x©.
    3432 The advantages of named parameters are:
    3433 \begin{itemize}
    3434 \item
    3435 Remembering the names of the parameters may be easier than the order in the routine definition.
    3436 \item
    3437 Parameter names provide documentation at the call site (assuming the names are descriptive).
    3438 \item
    3439 Changes can be made to the order or number of parameters without affecting the call (although the call must still be recompiled).
    3440 \end{itemize}
    3441 
    3442 Named parameters may only appear in a prototype versus definition context:
    3443 \begin{cfa}
    3444 void f( int  x, int ?y, int ?z );               §\C{// prototype: allowed}§
    3445 void f( int ?x, int , int ?z );                 §\C{// prototype: allowed}§
    3446 void f( int x, int ?y, int ?z ) ®{}®    §\C{// definition: disallowed}§
    3447 \end{cfa}
    3448 The reason for this restriction is to allow separate compilation.
    3449 Multiple prototypes with different positional parameter names is an error.
    3450 
    3451 The named parameter is not part of type resolution;
    3452 only the type of the expression assigned to the named parameter affects type resolution.
    3453 \begin{cfa}
    3454 int f( int ?i, int ?j );
    3455 int f( int ?i, double ?j );
    3456 f( ?j = 3, ?i = 4 );                                    §\C{// 1st f}§
    3457 f( ?i = 7, ?j = 8.1 );                                  §\C{// 2nd f}§
    3458 \end{cfa}
    3459 
    3460 
    3461 \subsection{Mixed Default/Named}
    3462 
    3463 Default and named parameters can be intermixed and named parameters can have a default value.
    3464 For example, given the routine prototype:
    3465 \begin{cfa}
    3466 void f( int x, int y ®= 1®, int ®?®z ®= 2® );
    3467 \end{cfa}
    3468 allowable calls are:
    3469 \begin{cfa}
    3470 f( 3 );                                                                 §\C{// rewrite \(\Rightarrow\) f( 3, 1, 2 )}§
    3471 f( 3, 4 );                                                              §\C{// rewrite \(\Rightarrow\) f( 3, 4, 2 )}§
    3472 f( 3, ?z = 5 );                                                 §\C{// rewrite \(\Rightarrow\) f( 3, 1, 5 )}§
    3473 f( 3, 4, ?z = 5 );                                              §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
    3474 f( ?z = 5, 3 );                                                 §\C{// rewrite \(\Rightarrow\) f( 3, 1, 5 )}§
    3475 f( 3, ?z = 5, 4 );                                              §\C{// rewrite \(\Rightarrow\) f( 3, 4, 5 )}§
    3476 \end{cfa}
    3477 Finally, the ellipse (``...'') parameter must appear after positional and named parameters in a routine prototype.
    3478 \begin{cfa}
    3479 void f( int i = 1, int ?j = 2, ®...® );
    3480 \end{cfa}
    3481 
    3482 \CFA named and default arguments are backwards compatible with C.
    3483 \Index*[C++]{\CC{}} only supports default parameters;
    3484 \Index*{Ada} supports both named and default parameters.
     3481In general, overloading should only be used over default arguments if the body of the routine is significantly different.
     3482Furthermore, overloading cannot handle accessing default arguments in the middle of a positional list, via a missing argument, such as:
     3483\begin{cfa}
     3484p( 1, /* default */, 5 ); §\C{// rewrite \(\Rightarrow\) p( 1, 2, 5 )}§
     3485\end{cfa}
     3486
     3487Given the \CFA restrictions above, both named and default arguments are backwards compatible.
     3488\Index*[C++]{\CC{}} only supports default arguments;
     3489\Index*{Ada} supports both named and default arguments.
    34853490
    34863491
  • libcfa/src/collections/array.hfa

    rce02877 r38e20a80  
    11#pragma once
    22
    3 //#include <assert.h>
     3#include <assert.h>
    44
    55
     
    88#define ztag(n) ttag(n)
    99
    10 #ifdef __CFA_DEBUG__
    11 #define subcheck( arr, sub, lb, ub ) \
    12         if ( (sub) < (lb) || (sub) >= (ub) ) \
    13                 abort( "subscript %ld exceeds dimension range [%d,%zd) for array %p.\n", \
    14                            (sub), (lb), (ub), (arr) )
    15 #else
    16 #define subcheck( arr, sub, lb, ub ) do {} while (0)
    17 #endif
    1810
    1911//
     
    4436//
    4537forall( [N], S & | sized(S), Timmed &, Tbase & ) {
    46         //
    47         // Single-dim array struct (with explicit packing and atom)
    48         //
    49         struct arpk {
    50                 S strides[N];
    51         };
    52 
    53         // About the choice of integral types offered as subscript overloads:
    54         // Intent is to cover these use cases:
    55         //    a[0]                                                // i : zero_t
    56         //    a[1]                                                // i : one_t
    57         //    a[2]                                                // i : int
    58         //    float foo( ptrdiff_t i ) { return a[i]; }           // i : ptrdiff_t
    59         //    float foo( size_t i ) { return a[i]; }              // i : size_t
    60         //    forall( [N] ) ... for( i; N ) { total += a[i]; }    // i : typeof( sizeof(42) )
    61         //    for( i; 5 ) { total += a[i]; }                      // i : int
    62         //
    63         // It gets complicated by:
    64         // -  CFA does overloading on concrete types, like int and unsigned int, not on typedefed
    65         //    types like size_t.  So trying to overload on ptrdiff_t vs int works in 64-bit mode
    66         //    but not in 32-bit mode.
    67         // -  Given bug of Trac #247, CFA gives sizeof expressions type unsigned long int, when it
    68         //    should give them type size_t.
    69         //
    70         //                          gcc -m32         cfa -m32 given bug         gcc -m64 (and cfa)
    71         // ptrdiff_t                int              int                        long int
    72         // size_t                   unsigned int     unsigned int               unsigned long int
    73         // typeof( sizeof(42) )     unsigned int     unsigned long int          unsigned long int
    74         // int                      int              int                        int
    75         //
    76         // So the solution must support types {zero_t, one_t, int, unsigned int, long int, unsigned long int}
    77         //
    78         // The solution cannot rely on implicit conversions (e.g. just have one overload for ptrdiff_t)
    79         // because assertion satisfaction requires types to match exacly.  Both higher-dimensional
    80         // subscripting and operations on slices use asserted subscript operators.  The test case
    81         // array-container/array-sbscr-cases covers the combinations.  Mike beleives that commenting out
    82         // any of the current overloads leads to one of those cases failing, either on 64- or 32-bit.
    83         // Mike is open to being shown a smaller set of overloads that still passes the test.
    84 
    85         static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, zero_t ) {
    86                 //assert( 0 < N );
    87                 subcheck( a, 0L, 0, N );
    88                 return (Timmed &)a.strides[0];
    89         }
    90 
    91         static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, one_t ) {
    92                 //assert( 1 < N );
    93                 subcheck( a, 1L, 0, N );
    94                 return (Timmed &)a.strides[1];
    95         }
    96 
    97         static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, int i ) {
    98                 //assert( i < N );
    99                 subcheck( a, (long int)i, 0, N );
    100                 return (Timmed &)a.strides[i];
    101         }
    102 
    103         static inline const Timmed & ?[?]( const arpk( N, S, Timmed, Tbase ) & a, int i ) {
    104                 //assert( i < N );
    105                 subcheck( a, (long int)i, 0, N );
    106                 return (Timmed &)a.strides[i];
    107         }
    108 
    109         static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, unsigned int i ) {
    110                 //assert( i < N );
    111                 subcheck( a, (long int)i, 0, N );
    112                 return (Timmed &)a.strides[i];
    113         }
    114 
    115         static inline const Timmed & ?[?]( const arpk( N, S, Timmed, Tbase ) & a, unsigned int i ) {
    116                 //assert( i < N );
    117                 subcheck( a, (unsigned long int)i, 0, N );
    118                 return (Timmed &)a.strides[i];
    119         }
    120 
    121         static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, long int i ) {
    122                 //assert( i < N );
    123                 subcheck( a, i, 0, N );
    124                 return (Timmed &)a.strides[i];
    125         }
    126 
    127         static inline const Timmed & ?[?]( const arpk( N, S, Timmed, Tbase ) & a, long int i ) {
    128                 //assert( i < N );
    129                 subcheck( a, i, 0, N );
    130                 return (Timmed &)a.strides[i];
    131         }
    132 
    133         static inline Timmed & ?[?]( arpk( N, S, Timmed, Tbase ) & a, unsigned long int i ) {
    134                 //assert( i < N );
    135                 subcheck( a, i, 0, N );
    136                 return (Timmed &)a.strides[i];
    137         }
    138 
    139         static inline const Timmed & ?[?]( const arpk( N, S, Timmed, Tbase ) & a, unsigned long int i ) {
    140                 //assert( i < N );
    141                 subcheck( a, i, 0, N );
    142                 return (Timmed &)a.strides[i];
    143         }
    144 
    145         static inline size_t ?`len( arpk( N, S, Timmed, Tbase ) & a ) {
    146                 return N;
    147         }
    148 
    149         static inline void __taglen( tag(arpk( N, S, Timmed, Tbase )), tag(N) ) {}
     38
     39    //
     40    // Single-dim array sruct (with explicit packing and atom)
     41    //
     42    struct arpk {
     43        S strides[N];
     44    };
     45
     46    // About the choice of integral types offered as subscript overloads:
     47    // Intent is to cover these use cases:
     48    //    a[0]                                                // i : zero_t
     49    //    a[1]                                                // i : one_t
     50    //    a[2]                                                // i : int
     51    //    float foo( ptrdiff_t i ) { return a[i]; }           // i : ptrdiff_t
     52    //    float foo( size_t i ) { return a[i]; }              // i : size_t
     53    //    forall( [N] ) ... for( i; N ) { total += a[i]; }    // i : typeof( sizeof(42) )
     54    //    for( i; 5 ) { total += a[i]; }                      // i : int
     55    //
     56    // It gets complicated by:
     57    // -  CFA does overloading on concrete types, like int and unsigned int, not on typedefed
     58    //    types like size_t.  So trying to overload on ptrdiff_t vs int works in 64-bit mode
     59    //    but not in 32-bit mode.
     60    // -  Given bug of Trac #247, CFA gives sizeof expressions type unsigned long int, when it
     61    //    should give them type size_t.
     62    //
     63    //                          gcc -m32         cfa -m32 given bug         gcc -m64 (and cfa)
     64    // ptrdiff_t                int              int                        long int
     65    // size_t                   unsigned int     unsigned int               unsigned long int
     66    // typeof( sizeof(42) )     unsigned int     unsigned long int          unsigned long int
     67    // int                      int              int                        int
     68    //
     69    // So the solution must support types {zero_t, one_t, int, unsigned int, long int, unsigned long int}
     70    //
     71    // The solution cannot rely on implicit conversions (e.g. just have one overload for ptrdiff_t)
     72    // because assertion satisfaction requires types to match exacly.  Both higher-dimensional
     73    // subscripting and operations on slices use asserted subscript operators.  The test case
     74    // array-container/array-sbscr-cases covers the combinations.  Mike beleives that commenting out
     75    // any of the current overloads leads to one of those cases failing, either on 64- or 32-bit.
     76    // Mike is open to being shown a smaller set of overloads that still passes the test.
     77
     78    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, zero_t ) {
     79        assert( 0 < N );
     80        return (Timmed &) a.strides[0];
     81    }
     82
     83    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, one_t ) {
     84        assert( 1 < N );
     85        return (Timmed &) a.strides[1];
     86    }
     87
     88    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, int i ) {
     89        assert( i < N );
     90        return (Timmed &) a.strides[i];
     91    }
     92
     93    static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, int i ) {
     94        assert( i < N );
     95        return (Timmed &) a.strides[i];
     96    }
     97
     98    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned int i ) {
     99        assert( i < N );
     100        return (Timmed &) a.strides[i];
     101    }
     102
     103    static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, unsigned int i ) {
     104        assert( i < N );
     105        return (Timmed &) a.strides[i];
     106    }
     107
     108    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, long int i ) {
     109        assert( i < N );
     110        return (Timmed &) a.strides[i];
     111    }
     112
     113    static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, long int i ) {
     114        assert( i < N );
     115        return (Timmed &) a.strides[i];
     116    }
     117
     118    static inline Timmed & ?[?]( arpk(N, S, Timmed, Tbase) & a, unsigned long int i ) {
     119        assert( i < N );
     120        return (Timmed &) a.strides[i];
     121    }
     122
     123    static inline const Timmed & ?[?]( const arpk(N, S, Timmed, Tbase) & a, unsigned long int i ) {
     124        assert( i < N );
     125        return (Timmed &) a.strides[i];
     126    }
     127
     128    static inline size_t ?`len( arpk(N, S, Timmed, Tbase) & a ) {
     129        return N;
     130    }
     131
     132    static inline void __taglen( tag(arpk(N, S, Timmed, Tbase)), tag(N) ) {}
    150133}
    151134
    152135// RAII pattern has workarounds for
    153136//  - Trac 226:  Simplest handling would be, require immediate element to be otype, let autogen
    154 //      raii happen.  Performance on even a couple dimensions is unacceptable because of exponential
    155 //      thunk creation: ?{}() needs all four otype funcs from next level, so does ^?{}(), so do the
    156 //      other two.  This solution offers ?{}() that needs only ?{}(), and similar for ^?{}.
     137//    raii happen.  Performance on even a couple dimensions is unacceptable because of exponential
     138//    thunk creation: ?{}() needs all four otype funcs from next level, so does ^?{}(), so do the
     139//    other two.  This solution offers ?{}() that needs only ?{}(), and similar for ^?{}.
    157140
    158141forall( [N], S & | sized(S), Timmed &, Tbase & | { void ?{}( Timmed & ); } )
    159 static inline void ?{}( arpk( N, S, Timmed, Tbase ) & this ) { 
    160         void ?{}( S (&)[N] ) {}
    161         ?{}(this.strides);
    162 
    163         for (i; N) ?{}( (Timmed &)this.strides[i] );
     142static inline void ?{}( arpk(N, S, Timmed, Tbase) & this ) {   
     143    void ?{}( S (&)[N] ) {}
     144    ?{}(this.strides);
     145
     146    for (i; N) ?{}( (Timmed &) this.strides[i] );
    164147}
    165148
    166149forall( [N], S & | sized(S), Timmed &, Tbase & | { void ^?{}( Timmed & ); } )
    167 static inline void ^?{}( arpk( N, S, Timmed, Tbase ) & this ) {
    168         void ^?{}( S (&)[N] ) {}
    169         ^?{}(this.strides);
    170 
    171         for (i; N ) {
    172                 ^?{}( (Timmed &)this.strides[N-i-1] );
    173         }
     150static inline void ^?{}( arpk(N, S, Timmed, Tbase) & this ) {
     151    void ^?{}( S (&)[N] ) {}
     152    ^?{}(this.strides);
     153
     154    for (i; N ) {
     155        ^?{}( (Timmed &) this.strides[N-i-1] );
     156    }
    174157}
    175158
     
    182165
    183166forall( [N], ZTags ... , Trslt &, Tatom & | { Trslt mkar_( tag(Tatom), ZTags ); } )
    184 static inline arpk( N, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(N), ZTags ) {}
     167static inline arpk(N, Trslt, Trslt, Tatom) mkar_( tag(Tatom), tag(N), ZTags ) {}
    185168
    186169// based on https://stackoverflow.com/questions/1872220/is-it-possible-to-iterate-over-arguments-in-variadic-macros
    187170
    188         // Make a FOREACH macro
    189         #define FE_0(WHAT)
    190         #define FE_1(WHAT, X) WHAT(X)
    191         #define FE_2(WHAT, X, ...) WHAT(X)FE_1(WHAT, __VA_ARGS__)
    192         #define FE_3(WHAT, X, ...) WHAT(X)FE_2(WHAT, __VA_ARGS__)
    193         #define FE_4(WHAT, X, ...) WHAT(X)FE_3(WHAT, __VA_ARGS__)
    194         #define FE_5(WHAT, X, ...) WHAT(X)FE_4(WHAT, __VA_ARGS__)
    195         //... repeat as needed
    196 
    197         #define GET_MACRO(_0,_1,_2,_3,_4,_5,NAME,...) NAME
    198         #define FOR_EACH(action,...) \
    199         GET_MACRO(_0,__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action,__VA_ARGS__)
     171    // Make a FOREACH macro
     172    #define FE_0(WHAT)
     173    #define FE_1(WHAT, X) WHAT(X)
     174    #define FE_2(WHAT, X, ...) WHAT(X)FE_1(WHAT, __VA_ARGS__)
     175    #define FE_3(WHAT, X, ...) WHAT(X)FE_2(WHAT, __VA_ARGS__)
     176    #define FE_4(WHAT, X, ...) WHAT(X)FE_3(WHAT, __VA_ARGS__)
     177    #define FE_5(WHAT, X, ...) WHAT(X)FE_4(WHAT, __VA_ARGS__)
     178    //... repeat as needed
     179
     180    #define GET_MACRO(_0,_1,_2,_3,_4,_5,NAME,...) NAME
     181    #define FOR_EACH(action,...) \
     182    GET_MACRO(_0,__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action,__VA_ARGS__)
    200183
    201184#define COMMA_ttag(X) , ttag(X)
     
    217200forall( TA &, TB &, TC &, IxAB, IxBC ... | { TB & ?[?]( TA &, IxAB ); TC & ?[?]( TB &, IxBC ); } )
    218201static inline TC & ?[?]( TA & this, IxAB ab, IxBC bc ) {
    219         return this[ab][bc];
     202    return this[ab][bc];
    220203}
    221204
     
    226209forall( TA &, TB &, TC &, IxAB_0, IxBC | { TB & ?[?]( TA &, IxAB_0 ); TC & ?[?]( TB &, IxBC ); } )
    227210static inline TC & ?[?]( TA & this, IxAB_0 ab, IxBC bc ) {
    228         return this[ab][bc];
     211    return this[ab][bc];
    229212}
    230213
    231214forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1 ); TC & ?[?]( TB &, IxBC ); } )
    232215static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxBC bc ) {
    233         return this[[ab0,ab1]][bc];
     216    return this[[ab0,ab1]][bc];
    234217}
    235218
    236219forall( TA &, TB &, TC &, IxAB_0, IxAB_1, IxAB_2, IxBC | { TB & ?[?]( TA &, IxAB_0, IxAB_1, IxAB_2 ); TC & ?[?]( TB &, IxBC ); } )
    237220static inline TC & ?[?]( TA & this, IxAB_0 ab0, IxAB_1 ab1, IxAB_2 ab2, IxBC bc ) {
    238         return this[[ab0,ab1,ab2]][bc];
     221    return this[[ab0,ab1,ab2]][bc];
    239222}
    240223
     
    254237// Base
    255238forall( [Nq], Sq & | sized(Sq), Tbase & )
    256 static inline tag(arpk( Nq, Sq, Tbase, Tbase )) enq_( tag(Tbase ), tag(Nq), tag(Sq), tag(Tbase ) ) {
    257         tag(arpk( Nq, Sq, Tbase, Tbase )) ret;
    258         return ret;
     239static inline tag(arpk(Nq, Sq, Tbase, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(Tbase) ) {
     240    tag(arpk(Nq, Sq, Tbase, Tbase)) ret;
     241    return ret;
    259242}
    260243
    261244// Rec
    262245forall( [Nq], Sq & | sized(Sq), [N], S & | sized(S), recq &, recr &, Tbase & | { tag(recr) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(recq) ); } )
    263 static inline tag(arpk( N, S, recr, Tbase )) enq_( tag(Tbase ), tag(Nq), tag(Sq), tag(arpk( N, S, recq, Tbase )) ) {
    264         tag(arpk( N, S, recr, Tbase )) ret;
    265         return ret;
     246static inline tag(arpk(N, S, recr, Tbase)) enq_( tag(Tbase), tag(Nq), tag(Sq), tag(arpk(N, S, recq, Tbase)) ) {
     247    tag(arpk(N, S, recr, Tbase)) ret;
     248    return ret;
    266249}
    267250
     
    269252extern struct all_t {} all;
    270253forall( [N], S & | sized(S), Te &, result &, Tbase & | { tag(result) enq_( tag(Tbase), tag(N), tag(S), tag(Te) ); } )
    271 static inline result & ?[?]( arpk( N, S, Te, Tbase ) & this, all_t ) {
    272         return (result&) this;
     254static inline result & ?[?]( arpk(N, S, Te, Tbase) & this, all_t ) {
     255    return (result&) this;
    273256}
    274257
     
    280263// forall(A &, Tv &, [N])
    281264// trait ar {
    282 //      Tv& ?[?]( A&, zero_t );
    283 //      Tv& ?[?]( A&, one_t  );
    284 //       Tv& ?[?]( A&, int      );
    285 //                                 ...
    286 //      size_t ?`len( A& );
    287 //      void __taglen( tag(C), tag(N) );
     265//    Tv& ?[?]( A&, zero_t );
     266//    Tv& ?[?]( A&, one_t  );
     267//     Tv& ?[?]( A&, int    );
     268//                   ...
     269//    size_t ?`len( A& );
     270//    void __taglen( tag(C), tag(N) );
    288271// };
    289272
    290273// working around N's not being accepted as arguments to traits
    291274
    292 #define ar( A, Tv, N ) {                                \
    293         Tv& ?[?]( A&, zero_t );                         \
    294         Tv& ?[?]( A&, one_t );                          \
    295         Tv& ?[?]( A&, int );                            \
    296         Tv& ?[?]( A&, unsigned int );           \
    297         Tv& ?[?]( A&, long int );                       \
    298         Tv& ?[?]( A&, unsigned long int );      \
    299         size_t ?`len( A& );                                     \
    300         void __taglen( tag(A), tag(N) );        \
    301 }
     275#define ar(A, Tv, N) {                 \
     276    Tv& ?[?]( A&, zero_t );            \
     277    Tv& ?[?]( A&, one_t );             \
     278    Tv& ?[?]( A&, int );               \
     279    Tv& ?[?]( A&, unsigned int );      \
     280    Tv& ?[?]( A&, long int );          \
     281    Tv& ?[?]( A&, unsigned long int ); \
     282    size_t ?`len( A& );                \
     283    void __taglen( tag(A), tag(N) );   \
     284}
  • libcfa/src/enum.cfa

    rce02877 r38e20a80  
    2525        E pred( E e ) {
    2626                E lower = lowerBound();
    27                 if ( fromInstance( e ) <= fromInstance(lower ) )
     27                if ( fromInstance(e) <= fromInstance(lower ) )
    2828                        abort( "call to pred() exceeds enumeration lower bound of %d", fromInstance( lower ) );
    29                 return pred_unsafe( e );
     29                return pred_unsafe(e);
    3030        }
    3131
  • src/GenPoly/Box.cpp

    rce02877 r38e20a80  
    673673                TypeVarMap const & typeVars,
    674674                ast::TypeSubstitution const * typeSubs ) {
    675         if ( auto name = expr->func.as<ast::NameExpr>() ) {
    676                 if ( "*?" == name->name ) {
    677                         // It's a deref.
    678                         // Must look under the * (and strip its ptr-ty) because expr's
    679                         // result could be ar/ptr-decayed.  If expr.inner:T(*)[n], then
    680                         // expr is a poly deref, even though expr:T*, which is not poly.
    681                         auto ptrExpr = expr->args.front();
    682                         auto ptrTy = ptrExpr->result.as<ast::PointerType>();
    683                         assert(ptrTy); // thing being deref'd must be pointer
    684                         auto referentTy = ptrTy->base;
    685                         assert(referentTy);
    686                         return isPolyType( referentTy, typeVars, typeSubs );
     675        if ( expr->result && isPolyType( expr->result, typeVars, typeSubs ) ) {
     676                if ( auto name = expr->func.as<ast::NameExpr>() ) {
     677                        if ( "*?" == name->name ) {
     678                                return true;
     679                        }
    687680                }
    688681        }
     
    11991192                assert( 2 == expr->args.size() );
    12001193
    1201                 ast::Type const * arg1Ty = expr->args.front()->result;
    1202                 ast::Type const * arg2Ty = expr->args.back()->result;
    1203 
    1204                 // two cases: a[i] with first arg poly ptr, i[a] with second arg poly ptr
    1205                 bool isPoly1 = isPolyPtr( arg1Ty, scopeTypeVars, typeSubs ) != nullptr;
    1206                 bool isPoly2 = isPolyPtr( arg2Ty, scopeTypeVars, typeSubs ) != nullptr;
    1207 
     1194                ast::Type const * baseType1 =
     1195                        isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
     1196                ast::Type const * baseType2 =
     1197                        isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
    12081198                // If neither argument is a polymorphic pointer, do nothing.
    1209                 if ( !isPoly1 && !isPoly2 ) {
     1199                if ( !baseType1 && !baseType2 ) {
    12101200                        return expr;
    12111201                }
    12121202                // The arguments cannot both be polymorphic pointers.
    1213                 assert( !isPoly1 || !isPoly2 );
     1203                assert( !baseType1 || !baseType2 );
    12141204                // (So exactly one of the arguments is a polymorphic pointer.)
    12151205
     
    12201210                ast::UntypedExpr * ret = new ast::UntypedExpr( location,
    12211211                                new ast::NameExpr( location, "?+?" ) );
    1222                 if ( isPoly1 ) {
    1223                         assert( arg1Ty );
    1224                         auto arg1TyPtr = dynamic_cast<ast::PointerType const * >( arg1Ty );
    1225                         assert( arg1TyPtr );
     1212                if ( baseType1 ) {
    12261213                        auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
    12271214                                expr->args.back(),
    1228                                 new ast::SizeofExpr( location1, deepCopy( arg1TyPtr->base ) ),
     1215                                new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
    12291216                        } );
    12301217                        ret->args.push_back( expr->args.front() );
    12311218                        ret->args.push_back( multiply );
    12321219                } else {
    1233                         assert( isPoly2 );
    1234                         assert( arg2Ty );
    1235                         auto arg2TyPtr = dynamic_cast<ast::PointerType const * >( arg2Ty );
    1236                         assert( arg2TyPtr );
     1220                        assert( baseType2 );
    12371221                        auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
    12381222                                expr->args.front(),
    1239                                 new ast::SizeofExpr( location2, deepCopy( arg2TyPtr->base ) ),
     1223                                new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
    12401224                        } );
    12411225                        ret->args.push_back( multiply );
     
    12501234                assert( 1 == expr->args.size() );
    12511235
    1252                 auto ptrExpr = expr->args.front();
    1253                 auto ptrTy = ptrExpr->result.as<ast::PointerType>();
    1254                 assert(ptrTy); // thing being deref'd must be pointer
    1255                 auto referentTy = ptrTy->base;
    1256                 assert(referentTy);
    1257 
    12581236                // If this isn't for a poly type, then do nothing.
    1259                 if ( !isPolyType( referentTy, scopeTypeVars, typeSubs ) ) {
     1237                if ( !isPolyType( expr->result, scopeTypeVars, typeSubs ) ) {
    12601238                        return expr;
    12611239                }
     
    12651243                // Fix expression type to remove pointer.
    12661244                ret->result = expr->result;
    1267                 // apply pointer decay
    1268                 if (auto retArTy = ret->result.as<ast::ArrayType>()) {
    1269                         ret->result = new ast::PointerType( retArTy->base );
    1270                 }
    12711245                ret->env = expr->env ? expr->env : ret->env;
    12721246                return ret;
     
    13171291                return makeIncrDecrExpr(
    13181292                        expr->location, expr, baseType, "++?" == varName );
    1319         // Addition and Subtraction Intrinsics:
     1293        // Addition and Subtration Intrinsics:
    13201294        } else if ( "?+?" == varName || "?-?" == varName ) {
    13211295                assert( expr->result );
    13221296                assert( 2 == expr->args.size() );
    13231297
    1324                 ast::Type const * arg1Ty = expr->args.front()->result;
    1325                 ast::Type const * arg2Ty = expr->args.back()->result;
    1326 
    1327                 bool isPoly1 = isPolyPtr( arg1Ty, scopeTypeVars, typeSubs ) != nullptr;
    1328                 bool isPoly2 = isPolyPtr( arg2Ty, scopeTypeVars, typeSubs ) != nullptr;
     1298                auto baseType1 =
     1299                        isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
     1300                auto baseType2 =
     1301                        isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
    13291302
    13301303                CodeLocation const & location = expr->location;
    13311304                CodeLocation const & location1 = expr->args.front()->location;
    13321305                CodeLocation const & location2 = expr->args.back()->location;
    1333                 // LHS minus RHS -> (LHS minus RHS) / sizeof(LHS)
    1334                 if ( isPoly1 && isPoly2 ) {
    1335                         assert( "?-?" == varName );
    1336                         assert( arg1Ty );
    1337                         auto arg1TyPtr = dynamic_cast<ast::PointerType const * >( arg1Ty );
    1338                         assert( arg1TyPtr );
     1306                // LHS op RHS -> (LHS op RHS) / sizeof(LHS)
     1307                if ( baseType1 && baseType2 ) {
    13391308                        auto divide = ast::UntypedExpr::createCall( location, "?/?", {
    13401309                                expr,
    1341                                 new ast::SizeofExpr( location, deepCopy( arg1TyPtr->base ) ),
     1310                                new ast::SizeofExpr( location, deepCopy( baseType1 ) ),
    13421311                        } );
    13431312                        if ( expr->env ) divide->env = expr->env;
    13441313                        return divide;
    13451314                // LHS op RHS -> LHS op (RHS * sizeof(LHS))
    1346                 } else if ( isPoly1 ) {
    1347                         assert( arg1Ty );
    1348                         auto arg1TyPtr = dynamic_cast<ast::PointerType const * >( arg1Ty );
    1349                         assert( arg1TyPtr );
     1315                } else if ( baseType1 ) {
    13501316                        auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
    13511317                                expr->args.back(),
    1352                                 new ast::SizeofExpr( location1, deepCopy( arg1TyPtr->base ) ),
     1318                                new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
    13531319                        } );
    13541320                        return ast::mutate_field_index(
    13551321                                expr, &ast::ApplicationExpr::args, 1, multiply );
    13561322                // LHS op RHS -> (LHS * sizeof(RHS)) op RHS
    1357                 } else if ( isPoly2 ) {
    1358                         assert( arg2Ty );
    1359                         auto arg2TyPtr = dynamic_cast<ast::PointerType const * >( arg2Ty );
    1360                         assert( arg2TyPtr );
     1323                } else if ( baseType2 ) {
    13611324                        auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
    13621325                                expr->args.front(),
    1363                                 new ast::SizeofExpr( location2, deepCopy( arg2TyPtr->base ) ),
     1326                                new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
    13641327                        } );
    13651328                        return ast::mutate_field_index(
     
    16251588        /// Change the type of generic aggregate members to char[].
    16261589        void mutateMembers( ast::AggregateDecl * aggr );
    1627         /// Returns the calculated sizeof/alignof expressions for type, or
    1628         /// nullptr for use C size/alignof().
     1590        /// Returns the calculated sizeof expression for type, or nullptr for use
     1591        /// C sizeof().
    16291592        ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
    1630         ast::Expr const * genAlignof( CodeLocation const &, ast::Type const * );
    16311593        /// Enters a new scope for type-variables,
    16321594        /// adding the type variables from the provided type.
     
    16511613{}
    16521614
    1653 static ast::Type * polyToMonoTypeRec( CodeLocation const & loc,
    1654                 ast::Type const * ty ) {
    1655         ast::Type * ret;
    1656         if ( auto aTy = dynamic_cast<ast::ArrayType const *>( ty ) ) {
    1657                 // recursive case
    1658                 auto monoBase = polyToMonoTypeRec( loc, aTy->base );
    1659                 ret = new ast::ArrayType( monoBase, aTy->dimension,
    1660                         aTy->isVarLen, aTy->isStatic, aTy->qualifiers );
    1661         } else {
    1662                 // base case
    1663                 auto charType = new ast::BasicType( ast::BasicKind::Char );
    1664                 auto size = new ast::NameExpr( loc,
    1665                         sizeofName( Mangle::mangleType( ty ) ) );
    1666                 ret = new ast::ArrayType( charType, size,
    1667                         ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
    1668         }
    1669         return ret;
    1670 }
    1671 
    16721615/// Converts polymorphic type into a suitable monomorphic representation.
    1673 /// Simple cases: T -> __attribute__(( aligned(8) )) char[sizeof_T];
    1674 /// Array cases: T[eOut][eIn] ->  __attribute__(( aligned(8) )) char[eOut][eIn][sizeof_T];
    1675 ast::Type * polyToMonoType( CodeLocation const & loc, ast::Type const * ty ) {
    1676         auto ret = polyToMonoTypeRec( loc, ty );
     1616/// Currently: __attribute__(( aligned(8) )) char[size_T];
     1617ast::Type * polyToMonoType( CodeLocation const & location,
     1618                ast::Type const * declType ) {
     1619        auto charType = new ast::BasicType( ast::BasicKind::Char );
     1620        auto size = new ast::NameExpr( location,
     1621                sizeofName( Mangle::mangleType( declType ) ) );
     1622        auto ret = new ast::ArrayType( charType, size,
     1623                ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
    16771624        ret->attributes.emplace_back( new ast::Attribute( "aligned",
    1678                 { ast::ConstantExpr::from_int( loc, 8 ) } ) );
     1625                { ast::ConstantExpr::from_int( location, 8 ) } ) );
    16791626        return ret;
    16801627}
     
    17691716        // Forally, side effects are not safe in this function. But it works.
    17701717        erase_if( mutDecl->attributes, matchAndMove );
    1771 
    1772         // Change the decl's type.
    1773         // Upon finishing the box pass, it shall be void*.
    1774         // At this middle-of-box-pass point, that type is T.
    1775 
    1776         // example 1
    1777         // before box:                                  T     t ;
    1778         // before here:  char _bufxx    [_sizeof_Y1T];  T     t = _bufxx;
    1779         // after here:   char _bufxx    [_sizeof_Y1T];  T     t = _bufxx;  (no change here - non array case)
    1780         // after box:    char _bufxx    [_sizeof_Y1T];  void *t = _bufxx;
    1781 
    1782         // example 2
    1783         // before box:                                  T     t[42] ;
    1784         // before here:  char _bufxx[42][_sizeof_Y1T];  T     t[42] = _bufxx;
    1785         // after here:   char _bufxx[42][_sizeof_Y1T];  T     t     = _bufxx;
    1786         // after box:    char _bufxx[42][_sizeof_Y1T];  void *t     = _bufxx;
    1787 
    1788         // Strip all "array of" wrappers
    1789         while ( auto arrayType = dynamic_cast<ast::ArrayType const *>( mutDecl->type.get() ) ) {
    1790                 mutDecl->type = arrayType->base;
    1791         }
    17921718
    17931719        mutDecl->init = new ast::SingleInit( decl->location,
     
    19431869                ast::AlignofExpr const * expr ) {
    19441870        ast::Type const * type = expr->type ? expr->type : expr->expr->result;
    1945         ast::Expr const * gen = genAlignof( expr->location, type );
    1946         return ( gen ) ? gen : expr;
     1871        if ( findGeneric( expr->location, type ) ) {
     1872                return new ast::NameExpr( expr->location,
     1873                        alignofName( Mangle::mangleType( type ) ) );
     1874        } else {
     1875                return expr;
     1876        }
    19471877}
    19481878
     
    21652095
    21662096                return true;
    2167 
    2168         } else if ( auto inst = dynamic_cast<ast::ArrayType const *>( type ) ) {
    2169                 return findGeneric( location, inst->base );
    21702097        }
    21712098        return false;
     
    22282155                return makeOp( location, "?*?", sizeofBase, dim );
    22292156        } else if ( findGeneric( location, type ) ) {
    2230                 // Generate reference to _sizeof parameter
     2157                // Generate calculated size for generic type.
    22312158                return new ast::NameExpr( location, sizeofName(
    2232                                 Mangle::mangleType( type ) ) );
    2233         } else {
    2234                 return nullptr;
    2235         }
    2236 }
    2237 
    2238 ast::Expr const * PolyGenericCalculator::genAlignof(
    2239                 CodeLocation const & location, ast::Type const * type ) {
    2240         if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
    2241                 // alignof array is alignof element
    2242                 return genAlignof( location, array->base );
    2243         } else if ( findGeneric( location, type ) ) {
    2244                 // Generate reference to _alignof parameter
    2245                 return new ast::NameExpr( location, alignofName(
    22462159                                Mangle::mangleType( type ) ) );
    22472160        } else {
  • src/Parser/parser.yy

    rce02877 r38e20a80  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 26 14:09:30 2024
    13 // Update Count     : 6733
     12// Last Modified On : Tue Jul  9 10:29:01 2024
     13// Update Count     : 6713
    1414//
    1515
     
    852852        ;
    853853
     854argument_expression_list_opt:
     855        // empty
     856                { $$ = nullptr; }
     857        | argument_expression_list
     858        ;
     859
     860argument_expression_list:
     861        argument_expression
     862        | argument_expression_list_opt ',' argument_expression
     863                { $$ = $1->set_last( $3 ); }
     864        ;
     865
     866argument_expression:
     867        '@'                                                                                                     // CFA, default parameter
     868                { SemanticError( yylloc, "Default parameter for argument is currently unimplemented." ); $$ = nullptr; }
     869                // { $$ = new ExpressionNode( build_constantInteger( *new string( "2" ) ) ); }
     870        | assignment_expression
     871        ;
     872
    854873field_name_list:                                                                                // CFA, tuple field selector
    855874        field
     
    10971116constant_expression:
    10981117        conditional_expression
    1099         ;
    1100 
    1101 argument_expression_list_opt:
    1102         // empty
    1103                 { $$ = nullptr; }
    1104         | argument_expression_list
    1105         ;
    1106 
    1107 argument_expression_list:
    1108         argument_expression
    1109         // | argument_expression_list_opt ',' argument_expression // CFA, allow empty argument
    1110         | argument_expression_list ',' argument_expression      // no empty argument
    1111                 { $$ = $1->set_last( $3 ); }
    1112         ;
    1113 
    1114 argument_expression:
    1115         '?'                                                                                                     // CFA, default parameter
    1116                 // { SemanticError( yylloc, "Argument to default parameter is currently unimplemented." ); $$ = nullptr; }
    1117                 { $$ = new ExpressionNode( build_constantInteger( yylloc, *new string( "2" ) ) ); }
    1118         | '?' identifier '=' assignment_expression                      // CFA, keyword argument
    1119                 // { SemanticError( yylloc, "keyword argument is currently unimplemented." ); $$ = nullptr; }
    1120                 { $$ = $4; }
    1121         | assignment_expression
    11221118        ;
    11231119
     
    35473543        identifier_at
    35483544                { $$ = DeclarationNode::newName( $1 ); }
    3549         | '?' identifier
    3550                 // { SemanticError( yylloc, "keyword parameter is currently unimplemented." ); $$ = nullptr; }
    3551                 { $$ = DeclarationNode::newName( $2 ); }
    35523545        | '(' paren_identifier ')'                                                      // redundant parenthesis
    35533546                { $$ = $2; }
  • tests/Makefile.am

    rce02877 r38e20a80  
    6969.PHONY : concurrency list .validate .test_makeflags
    7070.INTERMEDIATE : .validate .validate.cfa .test_makeflags
    71 EXTRA_PROGRAMS = array-collections/boxed avl_test linkonce linking/mangling/anon .dummy_hack # build but do not install
     71EXTRA_PROGRAMS = avl_test linkonce linking/mangling/anon .dummy_hack # build but do not install
    7272EXTRA_DIST = test.py \
    7373        pybin/__init__.py \
     
    7777        pybin/tools.py \
    7878        long_tests.hfa \
    79         array-collections/boxed.hfa \
    80         array-collections/boxed.cases.hfa \
    8179        avltree/avl-private.h \
    8280        avltree/avl.h \
     
    106104        done
    107105
    108 array_collections_boxed_SOURCES = array-collections/boxed.main.cfa array-collections/boxed.bookend.cfa
    109106avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa
    110107linkonce_SOURCES = link-once/main.cfa link-once/partner.cfa
  • tests/array-collections/array-sbscr-types.cfa

    rce02877 r38e20a80  
    2828// generally using ptrdiff_t-typed variables to convey numeric values.
    2929
    30 #include <assert.h>
    3130
    3231#define show( expr ) printf( "%.1f\n", expr )
Note: See TracChangeset for help on using the changeset viewer.