Changes in / [9d6f011:28bc8c8]


Ignore:
Files:
20 edited

Legend:

Unmodified
Added
Removed
  • doc/papers/general/Paper.tex

    r9d6f011 r28bc8c8  
    267267int m = max( max, -max );                                       $\C{// uses (3) and (1) twice, by matching return type}$
    268268\end{cfa}
    269 
    270269\CFA maximizes the ability to reuse names to aggressively address the naming problem.
    271270In some cases, hundreds of names can be reduced to tens, resulting in a significant cognitive reduction.
     
    286285
    287286
    288 \subsection{\texorpdfstring{\protect\lstinline{forall} Functions}{forall Functions}}
     287\subsection{\texorpdfstring{\LstKeywordStyle{forall} Functions}{forall Functions}}
    289288\label{sec:poly-fns}
    290289
     
    436435One approach is to write bespoke data-structures for each context in which they are needed.
    437436While this approach is flexible and supports integration with the C type-checker and tooling, it is also tedious and error-prone, especially for more complex data structures.
    438 A second approach is to use @void *@ based polymorphism, \eg the C standard-library functions @bsearch@ and @qsort@, which allow reuse of code with common functionality.
     437A second approach is to use @void *@--based polymorphism, \eg the C standard-library functions @bsearch@ and @qsort@, which allow reuse of code with common functionality.
    439438However, basing all polymorphism on @void *@ eliminates the type-checker's ability to ensure that argument types are properly matched, often requiring a number of extra function parameters, pointer indirection, and dynamic allocation that is not otherwise needed.
    440439A third approach to generic code is to use preprocessor macros, which does allow the generated code to be both generic and type-checked, but errors may be difficult to interpret.
     
    508507The offset arrays are statically generated where possible.
    509508If a dynamic generic-type is declared to be passed or returned by value from a polymorphic function, the translator can safely assume the generic type is complete (\ie has a known layout) at any call-site, and the offset array is passed from the caller;
    510 if the generic type is concrete at the call site, the elements of this offset array can even be statically generated using the C @offsetof@ macro.
    511 As an example, the body of the second @value@ function is implemented as:
    512 \begin{cfa}
    513 _assign_T( _retval, p + _offsetof_pair[1] ); $\C{// return *p.second}$
    514 \end{cfa}
    515 @_assign_T@ is passed in as an implicit parameter from @otype T@, and takes two @T *@ (@void *@ in the generated code), a destination and a source; @_retval@ is the pointer to a caller-allocated buffer for the return value, the usual \CFA method to handle dynamically-sized return types.
     509if the generic type is concrete at the call site, the elements of this offset array can even be statically generated using the C @offsetof@ macro. 
     510As an example, the body of the second @value@ function is implemented like this:
     511\begin{cfa}
     512_assign_T(_retval, p + _offsetof_pair[1]); $\C{// return *p.second}$
     513\end{cfa}
     514@_assign_T@ is passed in as an implicit parameter from @otype T@, and takes two @T*@ (@void*@ in the generated code), a destination and a source; @_retval@ is the pointer to a caller-allocated buffer for the return value, the usual \CFA method to handle dynamically-sized return types.
    516515@_offsetof_pair@ is the offset array passed into @value@; this array is generated at the call site as:
    517516\begin{cfa}
    518 size_t _offsetof_pair[] = { offsetof( _pair_conc0, first ), offsetof( _pair_conc0, second ) }
     517size_t _offsetof_pair[] = { offsetof(_pair_conc0, first), offsetof(_pair_conc0, second) }
    519518\end{cfa}
    520519
     
    540539The most important such pattern is using @forall(dtype T) T *@ as a type-checked replacement for @void *@, \eg creating a lexicographic comparison for pairs of pointers used by @bsearch@ or @qsort@:
    541540\begin{cfa}
    542 forall( dtype T ) int lexcmp( pair( T *, T * ) * a, pair( T *, T * ) * b, int (* cmp)( T *, T * ) ) {
     541forall(dtype T) int lexcmp( pair( T *, T * ) * a, pair( T *, T * ) * b, int (* cmp)( T *, T * ) ) {
    543542        return cmp( a->first, b->first ) ? : cmp( a->second, b->second );
    544543}
    545544\end{cfa}
    546 Since @pair( T *, T * )@ is a concrete type, there are no implicit parameters passed to @lexcmp@, so the generated code is identical to a function written in standard C using @void *@, yet the \CFA version is type-checked to ensure the fields of both pairs and the arguments to the comparison function match in type.
     545Since @pair(T *, T * )@ is a concrete type, there are no implicit parameters passed to @lexcmp@, so the generated code is identical to a function written in standard C using @void *@, yet the \CFA version is type-checked to ensure the fields of both pairs and the arguments to the comparison function match in type.
    547546
    548547Another useful pattern enabled by reused dtype-static type instantiations is zero-cost \newterm{tag-structures}.
    549548Sometimes information is only used for type-checking and can be omitted at runtime, \eg:
    550549\begin{cfa}
    551 forall( dtype Unit ) struct scalar { unsigned long value; };
     550forall(dtype Unit) struct scalar { unsigned long value; };
    552551struct metres {};
    553552struct litres {};
    554553
    555 forall( dtype U ) scalar(U) ?+?( scalar(U) a, scalar(U) b ) {
     554forall(dtype U) scalar(U) ?+?( scalar(U) a, scalar(U) b ) {
    556555        return (scalar(U)){ a.value + b.value };
    557556}
     
    808807Due to the implicit flattening and structuring conversions involved in argument passing, @otype@ and @dtype@ parameters are restricted to matching only with non-tuple types, \eg:
    809808\begin{cfa}
    810 forall( otype T, dtype U ) void f( T x, U * y );
     809forall(otype T, dtype U) void f( T x, U * y );
    811810f( [5, "hello"] );
    812811\end{cfa}
     
    815814For example, a plus operator can be written to add two triples together.
    816815\begin{cfa}
    817 forall( otype T | { T ?+?( T, T ); } ) [T, T, T] ?+?( [T, T, T] x, [T, T, T] y ) {
     816forall(otype T | { T ?+?( T, T ); }) [T, T, T] ?+?( [T, T, T] x, [T, T, T] y ) {
    818817        return [x.0 + y.0, x.1 + y.1, x.2 + y.2];
    819818}
     
    826825\begin{cfa}
    827826int f( [int, double], double );
    828 forall( otype T, otype U | { T f( T, U, U ); } ) void g( T, U );
     827forall(otype T, otype U | { T f( T, U, U ); }) void g( T, U );
    829828g( 5, 10.21 );
    830829\end{cfa}
    831830Hence, function parameter and return lists are flattened for the purposes of type unification allowing the example to pass expression resolution.
    832831This relaxation is possible by extending the thunk scheme described by Bilson~\cite{Bilson03}.
    833 % Whenever a candidate's parameter structure does not exactly match the formal parameter's structure, a thunk is generated to specialize calls to the actual function:
    834 % \begin{cfa}
    835 % int _thunk( int _p0, double _p1, double _p2 ) { return f( [_p0, _p1], _p2 ); }
    836 % \end{cfa}
    837 % so the thunk provides flattening and structuring conversions to inferred functions, improving the compatibility of tuples and polymorphism.
    838 % These thunks are generated locally using gcc nested-functions, rather hositing them to the external scope, so they can easily access local state.
     832Whenever a candidate's parameter structure does not exactly match the formal parameter's structure, a thunk is generated to specialize calls to the actual function:
     833\begin{cfa}
     834int _thunk( int _p0, double _p1, double _p2 ) { return f( [_p0, _p1], _p2 ); }
     835\end{cfa}
     836so the thunk provides flattening and structuring conversions to inferred functions, improving the compatibility of tuples and polymorphism.
     837These thunks take advantage of gcc C nested-functions to produce closures that have the usual function-pointer signature WHAT DOES THIS MEAN???.
    839838
    840839
     
    853852\begin{cfa}
    854853int sum$\(_0\)$() { return 0; }
    855 forall( ttype Params | { int sum( Params ); } ) int sum$\(_1\)$( int x, Params rest ) {
     854forall(ttype Params | { int sum( Params ); } ) int sum$\(_1\)$( int x, Params rest ) {
    856855        return x + sum( rest );
    857856}
     
    866865\begin{cfa}
    867866int sum( int x, int y ) { return x + y; }
    868 forall( ttype Params | { int sum( int, Params ); } ) int sum( int x, int y, Params rest ) {
     867forall(ttype Params | { int sum( int, Params ); } ) int sum( int x, int y, Params rest ) {
    869868        return sum( x + y, rest );
    870869}
     
    872871One more step permits the summation of any summable type with all arguments of the same type:
    873872\begin{cfa}
    874 trait summable( otype T ) {
     873trait summable(otype T) {
    875874        T ?+?( T, T );
    876875};
    877 forall( otype R | summable( R ) ) R sum( R x, R y ) {
     876forall(otype R | summable( R ) ) R sum( R x, R y ) {
    878877        return x + y;
    879878}
    880 forall( otype R, ttype Params | summable(R) | { R sum(R, Params); } ) R sum(R x, R y, Params rest) {
     879forall(otype R, ttype Params | summable(R) | { R sum(R, Params); } ) R sum(R x, R y, Params rest) {
    881880        return sum( x + y, rest );
    882881}
     
    889888\begin{cfa}
    890889struct S { int x, y; };
    891 forall( otype T, ttype Params | { void print(T); void print(Params); } ) void print(T arg, Params rest) {
     890forall(otype T, ttype Params | { void print(T); void print(Params); }) void print(T arg, Params rest) {
    892891        print(arg);  print(rest);
    893892}
     
    928927is transformed into:
    929928\begin{cfa}
    930 forall( dtype T0, dtype T1 | sized(T0) | sized(T1) ) struct _tuple2 {
     929forall(dtype T0, dtype T1 | sized(T0) | sized(T1)) struct _tuple2 {
    931930        T0 field_0;                                                             $\C{// generated before the first 2-tuple}$
    932931        T1 field_1;
     
    934933_tuple2(int, int) f() {
    935934        _tuple2(double, double) x;
    936         forall( dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2) ) struct _tuple3 {
     935        forall(dtype T0, dtype T1, dtype T2 | sized(T0) | sized(T1) | sized(T2)) struct _tuple3 {
    937936                T0 field_0;                                                     $\C{// generated before the first 3-tuple}$
    938937                T1 field_1;
     
    942941}
    943942\end{cfa}
    944 {\sloppy
     943\begin{sloppypar}
    945944Tuple expressions are then simply converted directly into compound literals, \eg @[5, 'x', 1.24]@ becomes @(_tuple3(int, char, double)){ 5, 'x', 1.24 }@.
    946 \par}%
     945\end{sloppypar}
    947946
    948947\begin{comment}
     
    10051004\section{Control Structures}
    10061005
    1007 \CFA identifies inconsistent, problematic, and missing control structures in C, and extends, modifies, and adds control structures to increase functionality and safety.
    1008 
    1009 
    1010 \subsection{\texorpdfstring{\protect\lstinline{if} Statement}{if Statement}}
     1006\CFA identifies inconsistent, problematic, and missing control structures in C, and extends, modifies, and adds to control structures to increase functionality and safety.
     1007
     1008
     1009\subsection{\texorpdfstring{\LstKeywordStyle{if} Statement}{if Statement}}
    10111010
    10121011The @if@ expression allows declarations, similar to @for@ declaration expression:
     
    10201019
    10211020
    1022 \subsection{\texorpdfstring{\protect\lstinline{switch} Statement}{switch Statement}}
     1021\subsection{\texorpdfstring{\LstKeywordStyle{switch} Statement}{switch Statement}}
    10231022
    10241023There are a number of deficiencies with the C @switch@ statements: enumerating @case@ lists, placement of @case@ clauses, scope of the switch body, and fall through between case clauses.
     
    10401039\lstMakeShortInline@%
    10411040\end{cquote}
    1042 for a contiguous list:\footnote{gcc has the same mechanism but awkward syntax, \lstinline@2 ...42@, because a space is required after a number, otherwise the period is a decimal point.}
     1041for a contiguous list:\footnote{gcc provides the same mechanism with awkward syntax, \lstinline@2 ... 42@, where spaces are required around the ellipse.}
    10431042\begin{cquote}
    10441043\lstDeleteShortInline@%
     
    10911090C @switch@ provides multiple entry points into the statement body, but once an entry point is selected, control continues across \emph{all} @case@ clauses until the end of the @switch@ body, called \newterm{fall through};
    10921091@case@ clauses are made disjoint by the @break@ statement.
    1093 While fall through \emph{is} a useful form of control flow, it does not match well with programmer intuition, resulting in errors from missing @break@ statements.
    1094 For backwards compatibility, \CFA provides a \emph{new} control structure, @choose@, which mimics @switch@, but reverses the meaning of fall through (see Figure~\ref{f:ChooseSwitchStatements}), similar to Go.
     1092While the ability to fall through \emph{is} a useful form of control flow, it does not match well with programmer intuition, resulting in many errors from missing @break@ statements.
     1093For backwards compatibility, \CFA provides a \emph{new} control structure, @choose@, which mimics @switch@, but reverses the meaning of fall through (see Figure~\ref{f:ChooseSwitchStatements}).
     1094
     1095Collectively, these enhancements reduce programmer burden and increase readability and safety.
    10951096
    10961097\begin{figure}
     
    11361137\end{figure}
    11371138
    1138 Finally, @fallthrough@ may appear in contexts other than terminating a @case@ clause, and have an explicit transfer label allowing separate cases but common final-code for a set of cases:
    1139 \begin{cquote}
    1140 \lstDeleteShortInline@%
    1141 \begin{tabular}{@{}l@{\hspace{2\parindentlnth}}l@{}}
    1142 \multicolumn{1}{c@{\hspace{2\parindentlnth}}}{\textbf{non-terminator}}  & \multicolumn{1}{c}{\textbf{target label}}     \\
    1143 \begin{cfa}
    1144 choose ( ... ) {
    1145   case 3:
    1146         if ( ... ) {
    1147                 ... `fallthrough;`  // goto case 4
    1148         } else {
    1149                 ...
    1150         }
    1151         // implicit break
    1152   case 4:
    1153 \end{cfa}
    1154 &
    1155 \begin{cfa}
    1156 choose ( ... ) {
    1157   case 3:
    1158         ... `fallthrough common;`
    1159   case 4:
    1160         ... `fallthrough common;`
    1161   common:
    1162         ...      // common code for cases 3 and 4
    1163         // implicit break
    1164   case 4:
    1165 \end{cfa}
    1166 \end{tabular}
    1167 \lstMakeShortInline@%
    1168 \end{cquote}
    1169 The target label may be case @default@.
    1170 
    1171 Collectively, these control-structure enhancements reduce programmer burden and increase readability and safety.
    1172 
    1173 
    1174 \subsection{\texorpdfstring{Labelled \protect\lstinline{continue} / \protect\lstinline{break}}{Labelled continue / break}}
     1139\begin{comment}
     1140Forgotten @break@ statements at the end of @switch@ cases are a persistent sort of programmer error in C, and the @break@ statements themselves introduce visual clutter and an un-C-like keyword-based block delimiter.
     1141\CFA addresses this error by introducing a @choose@ statement, which works identically to a @switch@ except that its default end-of-case behaviour is to break rather than to fall through for all non-empty cases.
     1142Since empty cases like @case 7:@ in @case 7: case 11:@ still have fall-through semantics and explicit @break@ is still allowed at the end of a @choose@ case, many idiomatic uses of @switch@ in standard C can be converted to @choose@ statements by simply changing the keyword.
     1143Where fall-through is desired for a non-empty case, it can be specified with the new @fallthrough@ statement, making @choose@ equivalently powerful to @switch@, but more concise in the common case where most non-empty cases end with a @break@ statement, as in the example below:
     1144
     1145\begin{cfa}
     1146choose( i ) {
     1147        case 2:
     1148                printf("even ");
     1149                fallthrough;
     1150        case 3: case 5: case 7:
     1151                printf("small prime\n");
     1152        case 4,6,8,9:
     1153                printf("small composite\n");
     1154        case 13~19:
     1155                printf("teen\n");
     1156        default:
     1157                printf("something else\n");
     1158}
     1159\end{cfa}
     1160\end{comment}
     1161
     1162
     1163\subsection{\texorpdfstring{Labelled \LstKeywordStyle{continue} / \LstKeywordStyle{break}}{Labelled continue / break}}
    11751164
    11761165While C provides @continue@ and @break@ statements for altering control flow, both are restricted to one level of nesting for a particular control structure.
     
    12811270\subsection{Exception Handling}
    12821271
    1283 The following framework for \CFA exception handling is in place, excluding some runtime type-information and virtual functions.
     1272The following framework for \CFA exception handling is in place, excluding some run-time type-information and dynamic casts.
    12841273\CFA provides two forms of exception handling: \newterm{fix-up} and \newterm{recovery} (see Figure~\ref{f:CFAExceptionHandling})~\cite{Buhr92b,Buhr00a}.
    12851274Both mechanisms provide dynamic call to a handler using dynamic name-lookup, where fix-up has dynamic return and recovery has static return from the handler.
     
    13511340   catch ( IOError err ) { ... }                        $\C{// handler error from other files}$
    13521341\end{cfa}
    1353 where the throw inserts the failing file-handle into the I/O exception.
     1342where the throw inserts the failing file-handle in the I/O exception.
    13541343Conditional catch cannot be trivially mimicked by other mechanisms because once an exception is caught, handler clauses in that @try@ statement are no longer eligible..
    13551344
     
    13591348resume( $\emph{alternate-stack}$ )
    13601349\end{cfa}
    1361 These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another \CFA coroutine or task\footnote{\CFA coroutine and concurrency features are discussed in a separately submitted paper.}~\cite{Delisle18}.
    1362 Nonlocal raise is restricted to resumption to provide the exception handler the greatest flexibility because processing the exception does not unwind its stack, allowing it to continue after the handler returns.
    1363 
    1364 To facilitate nonlocal raise, \CFA provides dynamic enabling and disabling of nonlocal exception-propagation.
     1350These overloads of @resume@ raise the specified exception or the currently propagating exception (reresume) at another \CFA coroutine or task~\cite{Delisle18}.\footnote{\CFA coroutine and concurrency features are discussed in a separately submitted paper.}
     1351Nonlocal raise is restricted to resumption to provide the exception handler the greatest flexibility because processing the exception does not unwind its stack, allowing it to continue after the handle returns.
     1352
     1353To facilitate nonlocal exception, \CFA provides dynamic enabling and disabling of nonlocal exception-propagation.
    13651354The constructs for controlling propagation of nonlocal exceptions are the @enable@ and the @disable@ blocks:
    13661355\begin{cquote}
     
    13691358\begin{cfa}
    13701359enable $\emph{exception-type-list}$ {
    1371         // allow non-local raise
     1360        // allow non-local resumption
    13721361}
    13731362\end{cfa}
     
    13751364\begin{cfa}
    13761365disable $\emph{exception-type-list}$ {
    1377         // disallow non-local raise
     1366        // disallow non-local resumption
    13781367}
    13791368\end{cfa}
     
    13861375Coroutines and tasks start with non-local exceptions disabled, allowing handlers to be put in place, before non-local exceptions are explicitly enabled.
    13871376\begin{cfa}
    1388 void main( mytask & t ) {                                       $\C{// thread starts here}$
    1389         // non-local exceptions disabled
    1390         try {                                                                   $\C{// establish handles for non-local exceptions}$
    1391                 enable {                                                        $\C{// allow non-local exception delivery}$
     1377void main( mytask & c ) {
     1378        try {
     1379                enable {                        $\C{// now allow non-local exception delivery}$
    13921380                        // task body
    13931381                }
    1394         // appropriate catchResume/catch handlers
     1382        // appropriate catchResume/catch
    13951383        }
    13961384}
     
    14121400
    14131401
    1414 \subsection{\texorpdfstring{\protect\lstinline{with} Clause / Statement}{with Clause / Statement}}
     1402\subsection{\texorpdfstring{\LstKeywordStyle{with} Clause / Statement}{with Clause / Statement}}
    14151403\label{s:WithClauseStatement}
    14161404
     
    18121800int & r = *new( int );
    18131801...                                                                                     $\C{// non-null reference}$
    1814 delete &r;                                                                      $\C{// unmanaged (programmer) memory-management}$
     1802delete &r;
    18151803r += 1;                                                                         $\C{// undefined reference}$
    18161804\end{cfa}
     
    19591947Constructor calls seamlessly integrate with existing C initialization syntax, providing a simple and familiar syntax to C programmers and allowing constructor calls to be inserted into legacy C code with minimal code changes.
    19601948
    1961 In \CFA, a constructor is named @?{}@ and a destructor is named @^?{}@\footnote{%
     1949In \CFA, a constructor is named @?{}@ and a destructor is named @^?{}@.
     1950The name @{}@ comes from the syntax for the initializer: @struct S { int i, j; } s = `{` 2, 3 `}`@\footnote{%
    19621951The symbol \lstinline+^+ is used for the destructor name because it was the last binary operator that could be used in a unary context.}.
    1963 The name @{}@ comes from the syntax for the initializer: @struct S { int i, j; } s = `{` 2, 3 `}`@.
    19641952Like other \CFA operators, these names represent the syntax used to call the constructor or destructor, \eg @?{}(x, ...)@ or @^{}(x, ...)@.
    19651953The constructor and destructor have return type @void@, and the first parameter is a reference to the object type to be constructed or destructed.
     
    20832071\subsection{0/1}
    20842072
    2085 In C, @0@ has the special property that it is the only ``false'' value;
    2086 from the standard, any value that compares equal to @0@ is false, while any value that compares unequal to @0@ is true.
    2087 As such, an expression @x@ in any boolean context (such as the condition of an @if@ or @while@ statement, or the arguments to @&&@, @||@, or @?:@\,) can be rewritten as @x != 0@ without changing its semantics.
    2088 Operator overloading in \CFA provides a natural means to implement this truth-value comparison for arbitrary types, but the C type system is not precise enough to distinguish an equality comparison with @0@ from an equality comparison with an arbitrary integer or pointer.
    2089 To provide this precision, \CFA introduces a new type @zero_t@ as the type of literal @0@ (somewhat analagous to @nullptr_t@ and @nullptr@ in \CCeleven);
    2090 @zero_t@ can only take the value @0@, but has implicit conversions to the integer and pointer types so that C code involving @0@ continues to work.
    2091 With this addition, \CFA rewrites @if (x)@ and similar expressions to @if ((x) != 0)@ or the appropriate analogue, and any type @T@ is ``truthy'' by defining an operator overload @int ?!=?(T, zero_t)@.
    2092 \CC makes types truthy by adding a conversion to @bool@;
    2093 prior to the addition of explicit cast operators in \CCeleven, this approach had the pitfall of making truthy types transitively convertable to any numeric type;
    2094 \CFA avoids this issue.
    2095 
    2096 Similarly, \CFA also has a special type for @1@, @one_t@;
    2097 like @zero_t@, @one_t@ has built-in implicit conversions to the various integral types so that @1@ maintains its expected semantics in legacy code for operations @++@ and @--@.
    2098 The addition of @one_t@ allows generic algorithms to handle the unit value uniformly for types where it is meaningful.
    2099 \TODO{Make this sentence true}
    2100 In particular, polymorphic functions in the \CFA prelude define @++x@ and @x++@ in terms of @x += 1@, allowing users to idiomatically define all forms of increment for a type @T@ by defining the single function @T & ?+=(T &, one_t)@;
    2101 analogous overloads for the decrement operators are present as well.
     2073In C, @0@ has the special property that it is the only ``false'' value; by the standard, any value which compares equal to @0@ is false, while any value that compares unequal to @0@ is true.
     2074As such, an expression @x@ in any boolean context (such as the condition of an @if@ or @while@ statement, or the arguments to @&&@, @||@, or @?:@) can be rewritten as @x != 0@ without changing its semantics.
     2075The operator overloading feature of \CFA provides a natural means to implement this truth value comparison for arbitrary types, but the C type system is not precise enough to distinguish an equality comparison with @0@ from an equality comparison with an arbitrary integer or pointer.
     2076To provide this precision, \CFA introduces a new type @zero_t@ as type type of literal @0@ (somewhat analagous to @nullptr_t@ and @nullptr@ in \CCeleven); @zero_t@ can only take the value @0@, but has implicit conversions to the integer and pointer types so that C code involving @0@ continues to work properly.
     2077With this addition, the \CFA compiler rewrites @if (x)@ and similar expressions to @if ((x) != 0)@ or the appropriate analogue, and any type @T@ can be made ``truthy'' by defining an operator overload @int ?!=?(T, zero_t)@.
     2078\CC makes types truthy by adding a conversion to @bool@; prior to the addition of explicit cast operators in \CCeleven this approach had the pitfall of making truthy types transitively convertable to any numeric type; our design for \CFA avoids this issue.
     2079
     2080\CFA also includes a special type for @1@, @one_t@; like @zero_t@, @one_t@ has built-in implicit conversions to the various integral types so that @1@ maintains its expected semantics in legacy code.
     2081The addition of @one_t@ allows generic algorithms to handle the unit value uniformly for types where that is meaningful.
     2082\TODO{Make this sentence true} In particular, polymorphic functions in the \CFA prelude define @++x@ and @x++@ in terms of @x += 1@, allowing users to idiomatically define all forms of increment for a type @T@ by defining the single function @T & ?+=(T &, one_t)@; analogous overloads for the decrement operators are present as well.
    21022083
    21032084
     
    21072088The left of Figure~\ref{f:UserLiteral} shows the \CFA alternative call-syntax (literal argument before function name), using the backquote, to convert basic literals into user literals.
    21082089The backquote is a small character, making the unit (function name) predominate.
    2109 For examples, the multi-precision integer-type in Section~\ref{s:MultiPrecisionIntegers} has user literals:
     2090For examples, the multi-precision integers in Section~\ref{s:MultiPrecisionIntegers} make use of user literals:
    21102091{\lstset{language=CFA,moredelim=**[is][\color{red}]{|}{|},deletedelim=**[is][]{`}{`}}
    21112092\begin{cfa}
     
    23272308\lstMakeShortInline@%
    23282309\end{cquote}
    2329 In additon, there are polymorphic functions, like @min@ and @max@, that work on any type with operators @?<?@ or @?>?@.
     2310In additon, there are polymorphic functions, like @min@ and @max@, which work on any type with operators @?<?@ or @?>?@.
    23302311
    23312312The following shows one example where \CFA \emph{extends} an existing standard C interface to reduce complexity and provide safety.
     
    23382319In either case, new storage may or may not be allocated and, if there is a new allocation, as much data from the existing allocation is copied.
    23392320For an increase in storage size, new storage after the copied data may be filled.
    2340 \item[align]
     2321\item[alignment]
    23412322an allocation on a specified memory boundary, \eg, an address multiple of 64 or 128 for cache-line purposes.
    23422323\item[array]
    2343 allocation with a specified number of elements.
     2324allocation of the specified number of elements.
    23442325An array may be filled, resized, or aligned.
    23452326\end{description}
     
    23532334\lstMakeShortInline~%
    23542335\begin{tabular}{@{}r|r|l|l|l|l@{}}
    2355 \multicolumn{1}{c}{}&           & \multicolumn{1}{c|}{fill}     & resize        & align & array \\
     2336\multicolumn{1}{c}{}&           & \multicolumn{1}{c|}{fill}     & resize        & alignment     & array \\
    23562337\hline
    23572338C               & ~malloc~                      & no                    & no            & no            & no    \\
     
    25812562        TIMED( "copy_int", ti{ si }; )
    25822563        TIMED( "clear_int", clear( si ); )
    2583         REPEAT_TIMED( "pop_int", N, int x = pop( ti ); if ( x > max ) max = x; )
     2564        REPEAT_TIMED( "pop_int", N,
     2565                int x = pop( ti ); if ( x > max ) max = x; )
    25842566
    25852567        pair( short, char ) max = { 0h, '\0' }, val = { 42h, 'a' };
     
    25892571        TIMED( "copy_pair", tp{ sp }; )
    25902572        TIMED( "clear_pair", clear( sp ); )
    2591         REPEAT_TIMED( "pop_pair", N, pair(short, char) x = pop( tp ); if ( x > max ) max = x; )
     2573        REPEAT_TIMED( "pop_pair", N,
     2574                pair(short, char) x = pop( tp ); if ( x > max ) max = x; )
    25922575}
    25932576\end{cfa}
     
    26222605                                                                        & \CT{C}        & \CT{\CFA}     & \CT{\CC}      & \CT{\CCV}             \\ \hline
    26232606maximum memory usage (MB)                       & 10001         & 2502          & 2503          & 11253                 \\
    2624 source code size (lines)                        & 187           & 186           & 133           & 303                   \\
     2607source code size (lines)                        & 187           & 188           & 133           & 303                   \\
    26252608redundant type annotations (lines)      & 25            & 0                     & 2                     & 16                    \\
    26262609binary size (KB)                                        & 14            & 257           & 14            & 37                    \\
     
    26362619Finally, the binary size for \CFA is larger because of static linking with the \CFA libraries.
    26372620
    2638 \CFA is also competitive in terms of source code size, measured as a proxy for programmer effort. The line counts in Table~\ref{tab:eval} include implementations of @pair@ and @stack@ types for all four languages for purposes of direct comparison, though it should be noted that \CFA and \CC have pre-written data structures in their standard libraries that programmers would generally use instead. Use of these standard library types has minimal impact on the performance benchmarks, but shrinks the \CFA and \CC benchmarks to 39 and 42 lines, respectively.
     2621\CFA is also competitive in terms of source code size, measured as a proxy for programmer effort. The line counts in Table~\ref{tab:eval} include implementations of @pair@ and @stack@ types for all four languages for purposes of direct comparison, though it should be noted that \CFA and \CC have pre-written data structures in their standard libraries that programmers would generally use instead. Use of these standard library types has minimal impact on the performance benchmarks, but shrinks the \CFA and \CC benchmarks to 41 and 42 lines, respectively.
    26392622On the other hand, C does not have a generic collections-library in its standard distribution, resulting in frequent reimplementation of such collection types by C programmers.
    26402623\CCV does not use the \CC standard template library by construction, and in fact includes the definition of @object@ and wrapper classes for @char@, @short@, and @int@ in its line count, which inflates this count somewhat, as an actual object-oriented language would include these in the standard library;
     
    27422725Finally, we demonstrate that \CFA performance for some idiomatic cases is better than C and close to \CC, showing the design is practically applicable.
    27432726
    2744 There is ongoing work on a wide range of \CFA feature extensions, including arrays with size, runtime type-information, virtual functions, user-defined conversions, concurrent primitives, and modules.
     2727There is ongoing work on a wide range of \CFA feature extensions, including arrays with size, user-defined conversions, concurrent primitives, and modules.
    27452728(While all examples in the paper compile and run, a public beta-release of \CFA will take another 8--12 months to finalize these additional extensions.)
    27462729In addition, there are interesting future directions for the polymorphism design.
     
    27772760\CFA
    27782761\begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt]
    2779 forall( otype T ) struct stack_node {
     2762forall(otype T) struct stack_node {
    27802763        T value;
    27812764        stack_node(T) * next;
    27822765};
    2783 forall( otype T ) struct stack { stack_node(T) * head; };
    2784 forall( otype T ) void ?{}( stack(T) & s ) { (s.head){ 0 }; }
    2785 forall( otype T ) void ?{}( stack(T) & s, stack(T) t ) {
     2766forall(otype T) struct stack { stack_node(T) * head; };
     2767forall(otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; }
     2768forall(otype T) void ?{}( stack(T) & s, stack(T) t ) {
    27862769        stack_node(T) ** crnt = &s.head;
    27872770        for ( stack_node(T) * next = t.head; next; next = next->next ) {
     
    27922775        *crnt = 0;
    27932776}
    2794 forall( otype T ) stack(T) ?=?( stack(T) & s, stack(T) t ) {
     2777forall(otype T) stack(T) ?=?( stack(T) & s, stack(T) t ) {
    27952778        if ( s.head == t.head ) return s;
    27962779        clear( s );
     
    27982781        return s;
    27992782}
    2800 forall( otype T ) void ^?{}( stack(T) & s) { clear( s ); }
    2801 forall( otype T ) _Bool empty( const stack(T) & s ) { return s.head == 0; }
    2802 forall( otype T ) void push( stack(T) & s, T value ) with( s ) {
     2783forall(otype T) void ^?{}( stack(T) & s) { clear( s ); }
     2784forall(otype T) _Bool empty( const stack(T) & s ) { return s.head == 0; }
     2785forall(otype T) void push( stack(T) & s, T value ) {
    28032786        stack_node(T) * n = alloc();
    28042787        (*n){ value, head };
    28052788        head = n;
    28062789}
    2807 forall( otype T ) T pop( stack(T) & s ) with( s ) {
     2790forall(otype T) T pop( stack(T) & s ) {
    28082791        stack_node(T) * n = head;
    28092792        head = n->next;
     
    28132796        return x;
    28142797}
    2815 forall( otype T ) void clear( stack(T) & s ) with( s ) {
     2798forall(otype T) void clear( stack(T) & s ) {
    28162799        for ( stack_node(T) * next = head; next; ) {
    28172800                stack_node(T) * crnt = next;
  • doc/papers/general/evaluation/cfa-bench.c

    r9d6f011 r28bc8c8  
    1010        TIMED( "copy_int", ti{ si }; )
    1111        TIMED( "clear_int", clear( si ); )
    12         REPEAT_TIMED( "pop_int", N, int x = pop( ti ); if ( x > max ) max = x; )
     12        REPEAT_TIMED( "pop_int", N,
     13                int x = pop( ti ); if ( x > max ) max = x; )
    1314
    1415        pair( short, char ) max = { 0h, '\0' }, val = { 42h, 'a' };
     
    1819        TIMED( "copy_pair", tp{ sp }; )
    1920        TIMED( "clear_pair", clear( sp ); )
    20         REPEAT_TIMED( "pop_pair", N, pair(short, char) x = pop( tp ); if ( x > max ) max = x; )
     21        REPEAT_TIMED( "pop_pair", N,
     22                pair(short, char) x = pop( tp ); if ( x > max ) max = x; )
    2123}
  • src/GenPoly/Box.cc

    r9d6f011 r28bc8c8  
    163163                        void premutate( DeclStmt *declStmt );
    164164                        Expression *postmutate( MemberExpr *memberExpr );
    165                         void premutate( AddressExpr *addrExpr );
    166                         Expression *postmutate( AddressExpr *addrExpr );
    167165                        Expression *postmutate( SizeofExpr *sizeofExpr );
    168166                        Expression *postmutate( AlignofExpr *alignofExpr );
     
    195193                        ScopedSet< std::string > knownOffsets;          ///< Set of non-generic types for which the offset array exists in the current scope, indexed by offsetofName
    196194                        UniqueName bufNamer;                           ///< Namer for VLA buffers
    197                         Expression * addrMember = nullptr;             ///< AddressExpr argument is MemberExpr?
    198195                };
    199196
     
    11771174                        if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) {
    11781175                                if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) {
    1179                                         if ( name->name == "*?" ) {
     1176                                        if ( name->get_name() == "*?" ) {
    11801177                                                Expression *ret = expr->args.front();
    11811178                                                expr->args.clear();
     
    11901187                void Pass1::premutate( AddressExpr * ) { visit_children = false; }
    11911188                Expression * Pass1::postmutate( AddressExpr * addrExpr ) {
    1192                         assert( addrExpr->arg->result && ! addrExpr->arg->result->isVoid() );
     1189                        assert( addrExpr->get_arg()->result && ! addrExpr->get_arg()->get_result()->isVoid() );
    11931190
    11941191                        bool needs = false;
    1195                         if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->arg ) ) {
    1196                                 if ( expr->result && isPolyType( expr->result, scopeTyVars, env ) ) {
    1197                                         if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->function ) ) {
    1198                                                 if ( name->name == "*?" ) {
    1199                                                         if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->args.front() ) ) {
    1200                                                                 assert( appExpr->function->result );
    1201                                                                 FunctionType *function = getFunctionType( appExpr->function->result );
     1192                        if ( UntypedExpr *expr = dynamic_cast< UntypedExpr *>( addrExpr->get_arg() ) ) {
     1193                                if ( expr->result && isPolyType( expr->get_result(), scopeTyVars, env ) ) {
     1194                                        if ( NameExpr *name = dynamic_cast< NameExpr *>( expr->get_function() ) ) {
     1195                                                if ( name->get_name() == "*?" ) {
     1196                                                        if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * >( expr->get_args().front() ) ) {
     1197                                                                assert( appExpr->get_function()->result );
     1198                                                                FunctionType *function = getFunctionType( appExpr->get_function()->get_result() );
    12021199                                                                assert( function );
    12031200                                                                needs = needsAdapter( function, scopeTyVars );
     
    12091206                        // isPolyType check needs to happen before mutating addrExpr arg, so pull it forward
    12101207                        // out of the if condition.
    1211                         addrExpr->arg = addrExpr->arg->acceptMutator( *visitor );
     1208                        addrExpr->arg = addrExpr->get_arg()->acceptMutator( *visitor );
    12121209                        // ... but must happen after mutate, since argument might change (e.g. intrinsic *?, ?[?]) - re-evaluate above comment
    1213                         bool polytype = isPolyType( addrExpr->arg->result, scopeTyVars, env );
     1210                        bool polytype = isPolyType( addrExpr->get_arg()->get_result(), scopeTyVars, env );
    12141211                        if ( polytype || needs ) {
    1215                                 Expression *ret = addrExpr->arg;
    1216                                 delete ret->result;
    1217                                 ret->result = addrExpr->result->clone();
    1218                                 addrExpr->arg = nullptr;
     1212                                Expression *ret = addrExpr->get_arg();
     1213                                delete ret->get_result();
     1214                                ret->set_result( addrExpr->get_result()->clone() );
     1215                                addrExpr->set_arg( 0 );
    12191216                                delete addrExpr;
    12201217                                return ret;
     
    12531250
    12541251                void Pass2::addAdapters( FunctionType *functionType ) {
    1255                         std::list< DeclarationWithType *> &paramList = functionType->parameters;
     1252                        std::list< DeclarationWithType *> &paramList = functionType->get_parameters();
    12561253                        std::list< FunctionType *> functions;
    12571254                        for ( std::list< DeclarationWithType *>::iterator arg = paramList.begin(); arg != paramList.end(); ++arg ) {
     
    12741271
    12751272                DeclarationWithType * Pass2::postmutate( FunctionDecl *functionDecl ) {
    1276                         FunctionType * ftype = functionDecl->type;
    1277                         if ( ! ftype->returnVals.empty() && functionDecl->statements ) {
    1278                                 if ( ! isPrefix( functionDecl->name, "_thunk" ) && ! isPrefix( functionDecl->name, "_adapter" ) ) { // xxx - remove check for prefix once thunks properly use ctor/dtors
    1279                                         assert( ftype->returnVals.size() == 1 );
    1280                                         DeclarationWithType * retval = ftype->returnVals.front();
    1281                                         if ( retval->name == "" ) {
    1282                                                 retval->name = "_retval";
     1273                        FunctionType * ftype = functionDecl->get_functionType();
     1274                        if ( ! ftype->get_returnVals().empty() && functionDecl->get_statements() ) {
     1275                                if ( ! isPrefix( functionDecl->get_name(), "_thunk" ) && ! isPrefix( functionDecl->get_name(), "_adapter" ) ) { // xxx - remove check for prefix once thunks properly use ctor/dtors
     1276                                        assert( ftype->get_returnVals().size() == 1 );
     1277                                        DeclarationWithType * retval = ftype->get_returnVals().front();
     1278                                        if ( retval->get_name() == "" ) {
     1279                                                retval->set_name( "_retval" );
    12831280                                        }
    1284                                         functionDecl->statements->kids.push_front( new DeclStmt( retval ) );
     1281                                        functionDecl->get_statements()->get_kids().push_front( new DeclStmt( retval ) );
    12851282                                        DeclarationWithType * newRet = retval->clone(); // for ownership purposes
    1286                                         ftype->returnVals.front() = newRet;
     1283                                        ftype->get_returnVals().front() = newRet;
    12871284                                }
    12881285                        }
    12891286                        // errors should have been caught by this point, remove initializers from parameters to allow correct codegen of default arguments
    1290                         for ( Declaration * param : functionDecl->type->parameters ) {
     1287                        for ( Declaration * param : functionDecl->get_functionType()->get_parameters() ) {
    12911288                                if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( param ) ) {
    1292                                         delete obj->init;
    1293                                         obj->init = nullptr;
     1289                                        delete obj->get_init();
     1290                                        obj->set_init( nullptr );
    12941291                                }
    12951292                        }
     
    15871584                        assert( newMemberExpr );
    15881585
    1589                         // Must apply the generic substitution to the member type to handle cases where the member is a generic parameter substituted by a known concrete type, e.g.
    1590                         //   forall(otype T) struct Box { T x; }
    1591                         //   forall(otype T) f() {
    1592                         //     Box(T *) b; b.x;
    1593                         //   }
    1594                         // TODO: memberExpr->result should be exactly memberExpr->member->get_type() after substitution, so it doesn't seem like it should be necessary to apply the substitution manually. For some reason this is not currently the case. This requires more investigation.
    1595                         Type *memberType = memberExpr->member->get_type()->clone();
    1596                         TypeSubstitution sub = objectType->genericSubstitution();
    1597                         sub.apply( memberType );
     1586                        Type *memberType = memberExpr->member->get_type();
    15981587                        if ( ! isPolyType( memberType, scopeTyVars ) ) {
    15991588                                // Not all members of a polymorphic type are themselves of polymorphic type; in this case the member expression should be wrapped and dereferenced to form an lvalue
     
    16031592                        }
    16041593
    1605                         delete memberType;
    16061594                        delete memberExpr;
    16071595                        return newMemberExpr;
    1608                 }
    1609 
    1610                 void PolyGenericCalculator::premutate( AddressExpr * addrExpr ) {
    1611                         GuardValue( addrMember );
    1612                         // is the argument a MemberExpr before mutating?
    1613                         addrMember = dynamic_cast< MemberExpr * >( addrExpr->arg );
    1614                 }
    1615 
    1616                 Expression * PolyGenericCalculator::postmutate( AddressExpr * addrExpr ) {
    1617                         if ( addrMember && addrMember != addrExpr->arg ) {
    1618                                 // arg was a MemberExpr and has been mutated
    1619                                 if ( UntypedExpr * untyped = dynamic_cast< UntypedExpr * >( addrExpr->arg ) ) {
    1620                                         if ( InitTweak::getFunctionName( untyped ) == "?+?" ) {
    1621                                                 // MemberExpr was converted to pointer+offset, and it is not valid C to take the address of an addition, so strip the address-of
    1622                                                 // TODO: should  addrExpr->arg->result be changed to addrExpr->result?
    1623                                                 Expression * ret = addrExpr->arg;
    1624                                                 addrExpr->arg = nullptr;
    1625                                                 std::swap( addrExpr->env, ret->env );
    1626                                                 delete addrExpr;
    1627                                                 return ret;
    1628                                         }
    1629                                 }
    1630                         }
    1631                         return addrExpr;
    16321596                }
    16331597
  • src/SynTree/Expression.cc

    r9d6f011 r28bc8c8  
    345345}
    346346
     347namespace {
     348        TypeSubstitution makeSub( Type * t ) {
     349                if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( t ) ) {
     350                        return makeSub( refType->get_base() );
     351                } else if ( StructInstType * aggInst = dynamic_cast< StructInstType * >( t ) ) {
     352                        return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->parameters.begin() );
     353                } else if ( UnionInstType * aggInst = dynamic_cast< UnionInstType * >( t ) ) {
     354                        return TypeSubstitution( aggInst->get_baseParameters()->begin(), aggInst->get_baseParameters()->end(), aggInst->parameters.begin() );
     355                } else {
     356                        assertf( false, "makeSub expects struct or union type for aggregate, but got: %s", toString( t ).c_str() );
     357                }
     358        }
     359}
     360
     361
    347362MemberExpr::MemberExpr( DeclarationWithType *member, Expression *aggregate ) :
    348363                Expression(), member(member), aggregate(aggregate) {
    349364        assert( member );
    350365        assert( aggregate );
    351         assert( aggregate->result );
    352 
    353         TypeSubstitution sub = aggregate->result->genericSubstitution();
     366
     367        TypeSubstitution sub( makeSub( aggregate->get_result() ) );
    354368        Type * res = member->get_type()->clone();
    355369        sub.apply( res );
  • src/SynTree/ReferenceToType.cc

    r9d6f011 r28bc8c8  
    1414//
    1515
    16 #include <cassert>            // for assert
    17 #include <list>               // for list, _List_const_iterator, list<>::cons...
    18 #include <ostream>            // for operator<<, basic_ostream, ostream, endl
    19 #include <string>             // for string, operator<<, char_traits, operator==
     16#include <cassert>           // for assert
     17#include <list>              // for list, _List_const_iterator, list<>::cons...
     18#include <ostream>           // for operator<<, basic_ostream, ostream, endl
     19#include <string>            // for string, operator<<, char_traits, operator==
    2020
    21 #include "Common/utility.h"   // for printAll, cloneAll, deleteAll
    22 #include "Declaration.h"      // for StructDecl, UnionDecl, EnumDecl, Declara...
    23 #include "Expression.h"       // for Expression
    24 #include "Type.h"             // for TypeInstType, StructInstType, UnionInstType
    25 #include "TypeSubstitution.h" // for TypeSubstitution
     21#include "Common/utility.h"  // for printAll, cloneAll, deleteAll
     22#include "Declaration.h"     // for StructDecl, UnionDecl, EnumDecl, Declara...
     23#include "Expression.h"      // for Expression
     24#include "Type.h"            // for TypeInstType, StructInstType, UnionInstType
    2625
    2726class Attribute;
     
    6463std::string StructInstType::typeString() const { return "struct"; }
    6564
    66 const std::list<TypeDecl*>* StructInstType::get_baseParameters() const {
    67         if ( ! baseStruct ) return nullptr;
    68         return &baseStruct->get_parameters();
    69 }
    70 
    7165std::list<TypeDecl*>* StructInstType::get_baseParameters() {
    7266        if ( ! baseStruct ) return nullptr;
     
    7771
    7872AggregateDecl * StructInstType::getAggr() { return baseStruct; }
    79 
    80 TypeSubstitution StructInstType::genericSubstitution() const {
    81         return TypeSubstitution( get_baseParameters()->begin(), get_baseParameters()->end(), parameters.begin() );
    82 }
    8373
    8474void StructInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const {
     
    112102}
    113103
    114 const std::list< TypeDecl * > * UnionInstType::get_baseParameters() const {
    115         if ( ! baseUnion ) return nullptr;
    116         return &baseUnion->get_parameters();
    117 }
    118 
    119104bool UnionInstType::isComplete() const { return baseUnion ? baseUnion->has_body() : false; }
    120105
    121106AggregateDecl * UnionInstType::getAggr() { return baseUnion; }
    122 
    123 TypeSubstitution UnionInstType::genericSubstitution() const {
    124         return TypeSubstitution( get_baseParameters()->begin(), get_baseParameters()->end(), parameters.begin() );
    125 }
    126107
    127108void UnionInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const {
  • src/SynTree/ReferenceType.cc

    r9d6f011 r28bc8c8  
    1616#include "Type.h"
    1717#include "Expression.h"
    18 #include "TypeSubstitution.h"
    1918#include "Common/utility.h"
    2019
     
    3635}
    3736
    38 TypeSubstitution ReferenceType::genericSubstitution() const { return base->genericSubstitution(); }
    39 
    4037void ReferenceType::print( std::ostream &os, Indenter indent ) const {
    4138        Type::print( os, indent );
  • src/SynTree/Type.cc

    r9d6f011 r28bc8c8  
    1515#include "Type.h"
    1616
    17 #include "Attribute.h"                // for Attribute
    18 #include "Common/utility.h"           // for cloneAll, deleteAll, printAll
    19 #include "InitTweak/InitTweak.h"      // for getPointerBase
    20 #include "SynTree/BaseSyntaxNode.h"   // for BaseSyntaxNode
    21 #include "SynTree/Declaration.h"      // for TypeDecl
    22 #include "SynTree/TypeSubstitution.h" // for TypeSubstitution
     17#include "Attribute.h"               // for Attribute
     18#include "Common/utility.h"          // for cloneAll, deleteAll, printAll
     19#include "InitTweak/InitTweak.h"     // for getPointerBase
     20#include "SynTree/BaseSyntaxNode.h"  // for BaseSyntaxNode
     21#include "SynTree/Declaration.h"     // for TypeDecl
    2322
    2423using namespace std;
     
    8281int Type::referenceDepth() const { return 0; }
    8382
    84 TypeSubstitution Type::genericSubstitution() const { assertf( false, "Non-aggregate type: %s", toCString( this ) ); }
    85 
    8683void Type::print( std::ostream &os, Indenter indent ) const {
    8784        if ( ! forall.empty() ) {
  • src/SynTree/Type.h

    r9d6f011 r28bc8c8  
    178178        virtual bool isComplete() const { return true; }
    179179
    180         virtual AggregateDecl * getAggr() { assertf( false, "Non-aggregate type: %s", toCString( this ) ); }
    181 
    182         virtual TypeSubstitution genericSubstitution() const;
     180        virtual AggregateDecl * getAggr() {     assertf( false, "Non-aggregate type: %s", toString( this ).c_str() ); }
    183181
    184182        virtual Type *clone() const = 0;
     
    331329        virtual unsigned size() const override { return base->size(); }
    332330
    333         virtual TypeSubstitution genericSubstitution() const override;
    334 
    335331        virtual ReferenceType *clone() const override { return new ReferenceType( *this ); }
    336332        virtual void accept( Visitor & v ) override { v.visit( this ); }
     
    410406        /// Accesses generic parameters of base struct (NULL if none such)
    411407        std::list<TypeDecl*> * get_baseParameters();
    412         const std::list<TypeDecl*> * get_baseParameters() const;
    413408
    414409        virtual bool isComplete() const override;
    415410
    416411        virtual AggregateDecl * getAggr() override;
    417 
    418         virtual TypeSubstitution genericSubstitution() const override;
    419412
    420413        /// Looks up the members of this struct named "name" and places them into "foundDecls".
     
    446439
    447440        /// Accesses generic parameters of base union (NULL if none such)
    448         std::list<TypeDecl*> * get_baseParameters();
    449         const std::list<TypeDecl*> * get_baseParameters() const;
     441        std::list< TypeDecl * > * get_baseParameters();
    450442
    451443        virtual bool isComplete() const override;
    452444
    453445        virtual AggregateDecl * getAggr() override;
    454 
    455         virtual TypeSubstitution genericSubstitution() const override;
    456446
    457447        /// looks up the members of this union named "name" and places them into "foundDecls"
  • src/tests/.expect/literals.x86.txt

    r9d6f011 r28bc8c8  
    522522signed int __main__Fi___1(){
    523523    __attribute__ ((unused)) signed int ___retval_main__i_1;
    524     ((void)0b01101011);
    525     ((void)0b01101011u);
    526     ((void)0b01101011l);
    527     ((void)0b01101011ll);
    528     ((void)0b01101011ul);
    529     ((void)0b01101011lu);
    530     ((void)0b01101011ull);
    531     ((void)0b01101011llu);
    532     ((void)(+0b01101011));
    533     ((void)(+0b01101011u));
    534     ((void)(+0b01101011l));
    535     ((void)(+0b01101011ll));
    536     ((void)(+0b01101011ul));
    537     ((void)(+0b01101011lu));
    538     ((void)(+0b01101011ull));
    539     ((void)(+0b01101011llu));
    540     ((void)(-0b01101011));
    541     ((void)(-0b01101011u));
    542     ((void)(-0b01101011l));
    543     ((void)(-0b01101011ll));
    544     ((void)(-0b01101011ul));
    545     ((void)(-0b01101011lu));
    546     ((void)(-0b01101011ull));
    547     ((void)(-0b01101011llu));
    548524    ((void)01234567);
    549525    ((void)01234567u);
     
    10411017    ((void)(-0X0123456789.0123456789P-09F));
    10421018    ((void)(-0X0123456789.0123456789P-09L));
    1043     ((void)((signed char )0b01101011));
    1044     ((void)((signed short int )0b01101011));
    1045     ((void)((signed int )0b01101011));
    1046     ((void)((signed long long int )0b01101011));
    1047     ((void)((__int128 )0b01101011));
    1048     ((void)((unsigned char )0b01101011u));
    1049     ((void)((signed short int )0b01101011u));
    1050     ((void)((unsigned int )0b01101011u));
    1051     ((void)((signed long long int )0b01101011u));
    1052     ((void)((__int128 )0b01101011u));
    1053     ((void)(+((signed int )((signed char )0b01101011))));
    1054     ((void)(+((signed int )((signed short int )0b01101011))));
    1055     ((void)(+((signed int )0b01101011)));
    1056     ((void)(+((signed long long int )0b01101011)));
    1057     ((void)(+((float )((__int128 )0b01101011))));
    1058     ((void)(+((signed int )((unsigned char )0b01101011u))));
    1059     ((void)(+((signed int )((signed short int )0b01101011u))));
    1060     ((void)(+((unsigned int )0b01101011u)));
    1061     ((void)(+((signed long long int )0b01101011u)));
    1062     ((void)(+((float )((__int128 )0b01101011u))));
    1063     ((void)(-((signed int )((signed char )0b01101011))));
    1064     ((void)(-((signed int )((signed short int )0b01101011))));
    1065     ((void)(-((signed int )0b01101011)));
    1066     ((void)(-((signed long long int )0b01101011)));
    1067     ((void)(-((float )((__int128 )0b01101011))));
    1068     ((void)(-((signed int )((unsigned char )0b01101011u))));
    1069     ((void)(-((signed int )((signed short int )0b01101011u))));
    1070     ((void)(-((unsigned int )0b01101011u)));
    1071     ((void)(-((signed long long int )0b01101011u)));
    1072     ((void)(-((float )((__int128 )0b01101011u))));
    10731019    ((void)((signed char )01234567));
    10741020    ((void)((signed short int )01234567));
  • src/tests/concurrent/coroutineYield.c

    r9d6f011 r28bc8c8  
    33#include <stdlib>
    44#include <thread>
    5 
    6 #ifdef LONG_TEST
    7 static const unsigned long N = 600_000ul;
    8 #else
    9 static const unsigned long N = 1_000ul;
    10 #endif
    115
    126coroutine Coroutine {};
     
    2418int main(int argc, char* argv[]) {
    2519        Coroutine c;
    26         for(int i = 0; i < N; i++) {
     20        for(int i = 0; i < 1_000; i++) {
    2721                sout | "Thread 1" | endl;
    2822                resume(c);
  • src/tests/concurrent/signal/block.c

    r9d6f011 r28bc8c8  
    1515#include <time.h>
    1616
    17 #ifdef LONG_TEST
    18 static const unsigned long N = 150_000ul;
    19 #else
    2017static const unsigned long N = 5_000ul;
    21 #endif
    2218
    2319#ifndef PREEMPTION_RATE
  • src/tests/concurrent/signal/disjoint.c

    r9d6f011 r28bc8c8  
    66#include <time.h>
    77
    8 #ifdef LONG_TEST
    9 static const unsigned long N = 300_000ul;
    10 #else
    118static const unsigned long N = 10_000ul;
    12 #endif
    139
    1410#ifndef PREEMPTION_RATE
  • src/tests/concurrent/signal/wait.c

    r9d6f011 r28bc8c8  
    1313#include <time.h>
    1414
    15 #ifdef LONG_TEST
    16 static const unsigned long N = 375_000ul;
    17 #else
    1815static const unsigned long N = 2_500ul;
    19 #endif
    2016
    2117#ifndef PREEMPTION_RATE
  • src/tests/preempt_longrun/Makefile.am

    r9d6f011 r28bc8c8  
    2323TIME = /usr/bin/time -f "%E"
    2424
    25 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} -DLONG_TEST
     25BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt}
    2626CFLAGS = ${BUILD_FLAGS}
    2727CC = @CFA_BINDIR@/@CFA_NAME@
  • src/tests/preempt_longrun/Makefile.in

    r9d6f011 r28bc8c8  
    454454REPEAT = ${abs_top_srcdir}/tools/repeat
    455455TIME = /usr/bin/time -f "%E"
    456 BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt} -DLONG_TEST
     456BUILD_FLAGS = -g -Wall -Wno-unused-function -quiet @CFA_FLAGS@ -O2 -DPREEMPTION_RATE=${preempt}
    457457TESTS = block coroutine create disjoint enter enter3 processor stack wait yield
    458458all: all-am
  • src/tests/preempt_longrun/create.c

    r9d6f011 r28bc8c8  
    22#include <thread>
    33
    4 static const unsigned long N = 60_000ul;
     4static const unsigned long N = 2_000ul;
    55
    66#ifndef PREEMPTION_RATE
  • src/tests/preempt_longrun/enter.c

    r9d6f011 r28bc8c8  
    33#include <thread>
    44
    5 static const unsigned long N  = 2_100_000ul;
     5static const unsigned long N  = 70_000ul;
    66
    77#ifndef PREEMPTION_RATE
  • src/tests/preempt_longrun/enter3.c

    r9d6f011 r28bc8c8  
    33#include <thread>
    44
    5 static const unsigned long N  = 500_000ul;
     5static const unsigned long N  = 50_000ul;
    66
    77#ifndef PREEMPTION_RATE
  • src/tests/preempt_longrun/processor.c

    r9d6f011 r28bc8c8  
    1212}
    1313
     14thread worker_t {};
     15
     16void main(worker_t & this) {}
     17
     18extern processor *   mainProcessor;
     19extern thread_desc * mainThread;
     20
    1421int main(int argc, char* argv[]) {
    15         processor * p[15];
    16         for ( int pi = 0; pi < 15; pi++ ) {
    17                 p[pi] = new();
    18         }
    19         for ( int i = 0; i < N; i++) {
    20                 int pi = i % 15;
    21                 delete( p[pi] );
    22                 p[pi] = new();
     22        for(int i = 0; i < N; i++) {
     23                assert(this_processor == mainProcessor);
     24                assert(this_thread == mainThread);
     25                processor p;
    2326        }
    2427}
  • src/tests/preempt_longrun/yield.c

    r9d6f011 r28bc8c8  
    22#include <thread>
    33
    4 #ifdef LONG_TEST
    5 static const unsigned long N = 9_750_000ul;
    6 #else
    74static const unsigned long N = 325_000ul;
    8 #endif
    95
    106#ifndef PREEMPTION_RATE
Note: See TracChangeset for help on using the changeset viewer.