Changes in / [436c0de:ade20d0]


Ignore:
Files:
7 added
21 deleted
64 edited

Legend:

Unmodified
Added
Removed
  • .gitignore

    r436c0de rade20d0  
    1313libcfa/Makefile
    1414src/Makefile
    15 /version
     15version
    1616
    1717# genereted by premake
  • configure

    r436c0de rade20d0  
    62516251
    62526252
    6253 ac_config_files="$ac_config_files Makefile src/driver/Makefile src/Makefile src/benchmark/Makefile src/examples/Makefile src/tests/Makefile src/tests/preempt_longrun/Makefile src/prelude/Makefile src/libcfa/Makefile"
     6253ac_config_files="$ac_config_files Makefile src/driver/Makefile src/Makefile src/benchmark/Makefile src/examples/Makefile src/tests/Makefile src/prelude/Makefile src/libcfa/Makefile"
    62546254
    62556255
     
    70197019    "src/examples/Makefile") CONFIG_FILES="$CONFIG_FILES src/examples/Makefile" ;;
    70207020    "src/tests/Makefile") CONFIG_FILES="$CONFIG_FILES src/tests/Makefile" ;;
    7021     "src/tests/preempt_longrun/Makefile") CONFIG_FILES="$CONFIG_FILES src/tests/preempt_longrun/Makefile" ;;
    70227021    "src/prelude/Makefile") CONFIG_FILES="$CONFIG_FILES src/prelude/Makefile" ;;
    70237022    "src/libcfa/Makefile") CONFIG_FILES="$CONFIG_FILES src/libcfa/Makefile" ;;
  • configure.ac

    r436c0de rade20d0  
    235235        src/examples/Makefile
    236236        src/tests/Makefile
    237         src/tests/preempt_longrun/Makefile
    238237        src/prelude/Makefile
    239238        src/libcfa/Makefile
  • doc/proposals/concurrency/Makefile

    r436c0de rade20d0  
    1313annex/glossary \
    1414text/intro \
    15 text/cforall \
    1615text/basics \
    1716text/concurrency \
  • doc/proposals/concurrency/build/bump_ver.sh

    r436c0de rade20d0  
    11#!/bin/bash
    2 if [ ! -f version ]; then
    3     echo "0.0.0" > version
     2if [ ! -f build/version ]; then
     3    echo "0.0.0" > build/version
    44fi
    55
    6 sed -r 's/([0-9]+\.[0-9]+.)([0-9]+)/echo "\1\$((\2+1))" > version/ge' version > /dev/null
     6sed -r 's/([0-9]+\.[0-9]+.)([0-9]+)/echo "\1\$((\2+1))" > version/ge' build/version > /dev/null
  • doc/proposals/concurrency/text/basics.tex

    r436c0de rade20d0  
    77
    88\section{Basics of concurrency}
    9 At its core, concurrency is based on having call-stacks and potentially multiple threads of execution for these stacks. Concurrency without parallelism only requires having multiple call stacks (or contexts) for a single thread of execution, and switching between these call stacks on a regular basis. A minimal concurrency product can be achieved by creating coroutines, which instead of context switching between each other, always ask an oracle where to context switch next. While coroutines do not technically require a stack, stackfull coroutines are the closest abstraction to a practical "naked"" call stack. When writing concurrency in terms of coroutines, the oracle effectively becomes a scheduler and the whole system now follows a cooperative threading-model \cit. The oracle/scheduler can either be a stackless or stackfull entity and correspondingly require one or two context switches to run a different coroutine. In any case, a subset of concurrency related challenges start to appear. For the complete set of concurrency challenges to occur, the only feature missing is preemption. Indeed, concurrency challenges appear with non-determinism. Guaranteeing mutual-exclusion or synchronisation are simply ways of limiting the lack of determinism in a system. A scheduler introduces order of execution uncertainty, while preemption introduces incertainty about where context-switches occur. Now it is important to understand that uncertainty is not necessarily undesireable; uncertainty can often be used by systems to significantly increase performance and is often the basis of giving a user the illusion that tasks are running in parallel. Optimal performance in concurrent applications is often obtained by having as much non-determinism as correctness allows\cit.
     9At its core, concurrency is based on having multiple call stacks and potentially multiple threads of execution for these stacks. Concurrency alone without parallelism only requires having multiple call stacks (or contexts) for a single thread of execution and switching between these call stacks on a regular basis. A minimal concurrency product can be achieved by creating coroutines which instead of context switching between each other, always ask an oracle where to context switch next. While coroutines do not technically require a stack, stackfull coroutines are the closest abstraction to a practical "naked"" call stack. When writing concurrency in terms of coroutines, the oracle effectively becomes a scheduler and the whole system now follows a cooperative threading model \cit. The oracle/scheduler can either be a stackless or stackfull entity and correspondingly require one or two context switches to run a different coroutine but in any case a subset of concurrency related challenges start to appear. For the complete set of concurrency challenges to be present, the only feature missing is preemption. Indeed, concurrency challenges appear with the lack of determinism. Guaranteeing mutual-exclusion or synchronisation are simply ways of limiting the lack of determinism in the system. A scheduler introduces order of execution uncertainty while preemption introduces incertainty about when context-switches occur. Now it is important to understand that uncertainty is not necessarily undesireable, uncertainty can often be used by systems to significantly increase performance and is often the basis of giving the user the illusion that hundred of tasks are running in parallel. Optimal performance in concurrent applications is often obtained by having as little determinism as correctness will allow\cit.
    1010
    1111\section{\protect\CFA 's Thread Building Blocks}
    12 One of the important features that is missing in C is threading. On modern architectures, a lack of threading is becoming less and less forgivable\cite{Sutter05, Sutter05b}, and therefore modern programming languages must have the proper tools to allow users to write performant concurrent and/or parallel programs. As an extension of C, \CFA needs to express these concepts in a way that is as natural as possible to programmers used to imperative languages. And being a system-level language means programmers expect to choose precisely which features they need and which cost they are willing to pay.
    13 
    14 \section{Coroutines: A stepping stone}\label{coroutine}
    15 While the main focus of this proposal is concurrency and parallelism, as mentionned above it is important to adress coroutines, which are actually a significant underlying aspect of a concurrency system. Indeed, while having nothing todo with parallelism and arguably little to do with concurrency, coroutines need to deal with context-switchs and and other context-management operations. Therefore, this proposal includes coroutines both as an intermediate step for the implementation of threads, and a first class feature of \CFA. Furthermore, many design challenges of threads are at least partially present in designing coroutines, which makes the design effort that much more relevant. The core API of coroutines revolve around two features: independent call stacks and \code{suspend}/\code{resume}.
     12% As a system-level language, \CFA should offer both performance and flexibilty as its primary goals, simplicity and user-friendliness being a secondary concern. Therefore, the core of parallelism in \CFA should prioritize power and efficiency. With this said, deconstructing popular paradigms in order to get simple building blocks yields \glspl{uthread} as the core parallelism block. \Glspl{pool} and other parallelism paradigms can then be built on top of the underlying threading model.
     13One of the important features that is missing to C is threading. On modern architectures, the lack of threading is becoming less and less forgivable\cite{Sutter05, Sutter05b} and therefore any modern programming language should have the proper tools to allow users to write performant concurrent and/or parallel programs. As an extension of C, \CFA needs to express these concepts an a way that is as natural as possible to programmers used to imperative languages. And being a system level language means programmers will expect to be able to choose precisely which features they need and which cost they are willing to pay.
     14
     15\section{Coroutines A stepping stone}\label{coroutine}
     16While the main focus of this proposal is concurrency and parallelism, as mentionned above it is important to adress coroutines which are actually a significant underlying aspect of the concurrency system. Indeed, while having nothing todo with parallelism and arguably little to do with concurrency, coroutines need to deal with context-switchs and and other context management operations. Therefore, this proposal includes coroutines both as an intermediate step for the implementation of threads and a first class feature of \CFA. Furthermore, many design challenges of threads are at least partially present in designing coroutines, which makes the design effort that much more relevant. The core API of coroutines revolve around two features independent call stacks and \code{suspend}/\code{resume}.
    1617
    1718Here is an example of a solution to the fibonnaci problem using \CFA coroutines:
     
    2526        }
    2627
    27         // main automacically called on first resume
    2828        void main(Fibonacci* this) {
    2929                int fn1, fn2;           // retained between resumes
     
    5959
    6060\subsection{Construction}
    61 One important design challenge for coroutines and threads (shown in section \ref{threads}) is that the runtime system needs to run code after the user-constructor runs. In the case of coroutines, this challenge is simpler since there is no non-determinism from preemption or scheduling. However, the underlying challenge remains the same for coroutines and threads.
    62 
    63 The runtime system needs to create the coroutine's stack and more importantly prepare it for the first resumption. The timing of the creation is non-trivial since users both expect to have fully constructed objects once execution enters the coroutine main and to be able to resume the coroutine from the constructor. Like for regular objects, constructors can still leak coroutines before they are ready. There are several solutions to this problem but the chosen options effectively forces the design of the coroutine.
    64 
    65 Furthermore, \CFA faces an extra challenge as polymorphic routines create invisible thunks when casted to non-polymorphic routines and these thunks have function scope. For example, the following code, while looking benign, can run into undefined behaviour because of thunks:
     61One important design challenge for coroutines and threads (shown in section \ref{threads}) is that the runtime system needs to run some code after the user-constructor runs. In the case of the coroutines this challenge is simpler since there is no loss of determinism brough by preemption or scheduling, however, the underlying challenge remains the same for coroutines and threads.
     62
     63The runtime system needs to create the coroutine's stack and more importantly prepare it for the first resumption. The timing of the creation is non trivial since users both expect to have fully constructed objects once execution enters the coroutine main and to be able to resume the coroutine from the constructor (Obviously we only solve cases where these two statements don't conflict). There are several solutions to this problem but the chosen options effectively forces the design of the coroutine.
     64
     65Furthermore, \CFA faces an extra challenge which is that polymorphique routines rely on invisible thunks when casted to non-polymorphic routines and these thunks have function scope. For example, the following code, while looking benign, can run into undefined behaviour because of thunks:
    6666
    6767\begin{cfacode}
     
    7878}
    7979\end{cfacode}
    80 The generated C code\footnote{Code trimmed down for brevity} creates a local thunk to hold type information:
     80Indeed, the generated C code\footnote{Code trimmed down for brevity} shows that a local thunk is created in order to hold type information:
    8181
    8282\begin{ccode}
     
    9595}
    9696\end{ccode}
    97 The problem in this example is a race condition between the start of the execution of \code{noop} on the other thread and the stack frame of \code{bar} being destroyed. This extra challenge limits which solutions are viable because storing the function pointer for too long only increases the chances that the race will end in undefined behavior; i.e. the stack based thunk being destroyed before it was used. This challenge is an extension of challenges that come with second-class routines. Indeed, GCC nested routines also have the limitation that the routines cannot be passed outside of the scope of the functions these were declared in. The case of coroutines and threads is simply an extension of this problem to multiple call-stacks.
     97The problem in the this example is that there is a race condition between the start of the execution of \code{noop} on the other thread and the stack frame of \code{bar} being destroyed. This extra challenge limits which solutions are viable because storing the function pointer for too long only increases the chances that the race will end in undefined behavior; i.e. the stack based thunk being destroyed before it was used.
    9898
    9999\subsection{Alternative: Composition}
    100 One solution to this challenge would be to use composition/containement,
     100One solution to this challenge would be to use inheritence,
    101101
    102102\begin{cfacode}
    103103        struct Fibonacci {
    104104              int fn; // used for communication
    105               coroutine c; //composition
     105              coroutine c;
    106106        };
    107107
     
    111111        }
    112112\end{cfacode}
    113 There are two downsides to this approach. The first, which is relatively minor, is that the base class needs to be made aware of the main routine pointer, regardless of whether a parameter or a virtual pointer is used, this means the coroutine data must be made larger to store a value that is actually a compile time constant (address of the main routine). The second problem, which is both subtle and significant, is that now users can get the initialisation order of there coroutines wrong. Indeed, every field of a \CFA struct is constructed but in declaration order, unless users explicitly write otherwise. This semantics means that users who forget to initialize a the coroutine may resume the coroutine with an uninitilized object. For coroutines, this is unlikely to be a problem, for threads however, this is a significant problem.
     113
     114There are two downsides to this approach. The first, which is relatively minor, is that the base class needs to be made aware of the main routine pointer, regardless of whether we use a parameter or a virtual pointer, this means the coroutine data must be made larger to store a value that is actually a compile time constant (The address of the main routine). The second problem which is both subtle but significant, is that now users can get the initialisation order of there coroutines wrong. Indeed, every field of a \CFA struct will be constructed but in the order of declaration, unless users explicitly write otherwise. This means that users who forget to initialize a the coroutine at the right time may resume the coroutine with an uninitilized object. For coroutines, this is unlikely to be a problem, for threads however, this is a significant problem.
    114115
    115116\subsection{Alternative: Reserved keyword}
     
    121122        };
    122123\end{cfacode}
     124
    123125This mean the compiler can solve problems by injecting code where needed. The downside of this approach is that it makes coroutine a special case in the language. Users who would want to extend coroutines or build their own for various reasons can only do so in ways offered by the language. Furthermore, implementing coroutines without language supports also displays the power of \CFA.
    124126While this is ultimately the option used for idiomatic \CFA code, coroutines and threads can both be constructed by users without using the language support. The reserved keywords are only present to improve ease of use for the common cases.
     
    126128\subsection{Alternative: Lamda Objects}
    127129
    128 For coroutines as for threads, many implementations are based on routine pointers or function objects\cit. For example, Boost implements coroutines in terms of four functor object types:
    129 \begin{cfacode}
    130 asymmetric_coroutine<>::pull_type
    131 asymmetric_coroutine<>::push_type
    132 symmetric_coroutine<>::call_type
    133 symmetric_coroutine<>::yield_type
    134 \end{cfacode}
    135 Often, the canonical threading paradigm in languages is based on function pointers, pthread being one of the most well known examples. The main problem of this approach is that the thread usage is limited to a generic handle that must otherwise be wrapped in a custom type. Since the custom type is simple to write in \CFA and solves several issues, added support for routine/lambda based coroutines adds very little.
    136 
    137 A variation of this would be to use an simple function pointer in the same way pthread does for threads :
    138 \begin{cfacode}
    139 void foo( coroutine_t cid, void * arg ) {
    140         int * value = (int *)arg;
    141         //Coroutine body
    142 }
    143 
    144 int main() {
    145         int value = 0;
    146         coroutine_t cid = coroutine_create( &foo, (void*)&value );
    147         coroutine_resume( &cid );
    148 }
    149 \end{cfacode}
    150 This semantic is more common for thread interfaces than coroutines but would work equally well. As discussed in section \ref{threads}, this approach is superseeded by static approaches in terms of expressivity.
    151 
    152 \subsection{Alternative: Trait-based coroutines}
    153 
    154 Finally the underlying approach, which is the one closest to \CFA idioms, is to use trait-based lazy coroutines. This approach defines a coroutine as anything that satisfies the trait \code{is_coroutine} and is used as a coroutine is a coroutine.
     130For coroutines as for threads, many implementations are based on routine pointers or function objects\cit. For example, Boost implements coroutines in terms of four functor object types \code{asymmetric_coroutine<>::pull_type}, \code{asymmetric_coroutine<>::push_type}, \code{symmetric_coroutine<>::call_type}, \code{symmetric_coroutine<>::yield_type}. Often, the canonical threading paradigm in languages is based on function pointers, pthread being one of the most well known example. The main problem of these approach is that the thread usage is limited to a generic handle that must otherwise be wrapped in a custom type. Since the custom type is simple to write and \CFA and solves several issues, added support for routine/lambda based coroutines adds very little.
     131
     132\subsection{Trait based coroutines}
     133
     134Finally the underlying approach, which is the one closest to \CFA idioms, is to use trait-based lazy coroutines. This approach defines a coroutine as \say{anything that \say{satisfies the trait \code{is_coroutine} and is used as a coroutine} is a coroutine}.
    155135
    156136\begin{cfacode}
     
    160140};
    161141\end{cfacode}
    162 This ensures an object is not a coroutine until \code{resume} (or \code{prime}) is called on the object. Correspondingly, any object that is passed to \code{resume} is a coroutine since it must satisfy the \code{is_coroutine} trait to compile. The advantage of this approach is that users can easily create different types of coroutines, for example, changing the memory foot print of a coroutine is trivial when implementing the \code{get_coroutine} routine. The \CFA keyword \code{coroutine} only has the effect of implementing the getter and forward declarations required for users to only have to implement the main routine.
    163 
    164 \begin{center}
    165 \begin{tabular}{c c c}
    166 \begin{cfacode}[tabsize=3]
    167 coroutine MyCoroutine {
    168         int someValue;
    169 };
    170 \end{cfacode} & == & \begin{cfacode}[tabsize=3]
    171 struct MyCoroutine {
    172         int someValue;
    173         coroutine_desc __cor;
    174 };
    175 
    176 static inline
    177 coroutine_desc * get_coroutine(
    178         struct MyCoroutine * this
    179 ) {
    180         return &this->__cor;
    181 }
    182 
    183 void main(struct MyCoroutine * this);
    184 \end{cfacode}
    185 \end{tabular}
    186 \end{center}
    187 
     142
     143This entails that an object is not a coroutine until \code{resume} (or \code{prime}) is called on the object. Correspondingly, any object that is passed to \code{resume} is a coroutine since it must satisfy the \code{is_coroutine} trait to compile. The advantage of this approach is that users can easily create different types of coroutines, for example, changing the memory foot print of a coroutine is trivial when implementing the \code{get_coroutine} routine. The \CFA keyword \code{coroutine} only has the effect of implementing the getter and forward declarations required for users to only have to implement the main routine.
    188144
    189145
    190146\section{Thread Interface}\label{threads}
    191 The basic building blocks of multi-threading in \CFA are \glspl{cfathread}. Both use and kernel threads are supported, where user threads are the concurrency mechanism and kernel threads are the parallel mechanism. User threads offer a flexible and lightweight interface. A thread can be declared using a struct declaration \code{thread} as follows:
     147The basic building blocks of multi-threading in \CFA are \glspl{cfathread}. By default these are implemented as \glspl{uthread}, and as such, offer a flexible and lightweight threading interface (lightweight compared to \glspl{kthread}). A thread can be declared using a SUE declaration \code{thread} as follows:
    192148
    193149\begin{cfacode}
     
    195151\end{cfacode}
    196152
    197 As for coroutines, the keyword is a thin wrapper arount a \CFA trait:
     153Like for coroutines, the keyword is a thin wrapper arount a \CFA trait:
    198154
    199155\begin{cfacode}
     
    214170\end{cfacode}
    215171
    216 In this example, threads of type \code{foo} start execution in the \code{void main(foo*)} routine which prints \code{"Hello World!"}. While this proposoal encourages this approach to enforce strongly-typed programming, users may prefer to use the routine based thread semantics for the sake of simplicity. With these semantics it is trivial to write a thread type that takes a function pointer as parameter and executes it on its stack asynchronously
     172In this example, threads of type \code{foo} will start there execution in the \code{void main(foo*)} routine which in this case prints \code{"Hello World!"}. While this proposoal encourages this approach which enforces strongly type programming, users may prefer to use the routine based thread semantics for the sake of simplicity. With these semantics it is trivial to write a thread type that takes a function pointer as parameter and executes it on its stack asynchronously
    217173\begin{cfacode}
    218174        typedef void (*voidFunc)(void);
     
    245201void main() {
    246202        World w;
    247         //Thread forks here
    248 
    249         //Printing "Hello " and "World!" are run concurrently
     203        //Thread run forks here
     204
     205        //Printing "Hello " and "World!" will be run concurrently
    250206        sout | "Hello " | endl;
    251207
     
    254210\end{cfacode}
    255211
    256 This semantic has several advantages over explicit semantics typesafety is guaranteed, a thread is always started and stopped exaclty once and users cannot make any progamming errors. Another advantage of this semantic is that it naturally scale to multiple threads meaning basic synchronisation is very simple
    257 
    258 \begin{cfacode}
    259         thread MyThread {
    260                 //...
    261         };
    262 
    263         //main
    264         void main(MyThread* this) {
    265                 //...
    266         }
    267 
    268         void foo() {
    269                 MyThread thrds[10];
    270                 //Start 10 threads at the beginning of the scope
    271 
    272                 DoStuff();
    273 
    274                 //Wait for the 10 threads to finish
    275         }
    276 \end{cfacode}
    277 
    278 However, one of the apparent drawbacks of this system is that threads now always form a lattice, that is they are always destroyed in opposite order of construction because of block structure. However, storage allocation os not limited to blocks; dynamic allocation can create threads that outlive the scope in which the thread is created much like dynamically allocating memory lets objects outlive the scope in which they are created
     212This semantic has several advantages over explicit semantics typesafety is guaranteed, a thread is always started and stopped exaclty once and users cannot make any progamming errors. However, one of the apparent drawbacks of this system is that threads now always form a lattice, that is they are always destroyed in opposite order of construction. While this seems like a significant limitation, existing \CFA semantics can solve this problem. Indeed, using dynamic allocation to create threads will naturally let threads outlive the scope in which the thread was created much like dynamically allocating memory will let objects outlive the scope in which thy were created
    279213
    280214\begin{cfacode}
     
    307241        }
    308242\end{cfacode}
     243
     244Another advantage of this semantic is that it naturally scale to multiple threads meaning basic synchronisation is very simple
     245
     246\begin{cfacode}
     247        thread MyThread {
     248                //...
     249        };
     250
     251        //main
     252        void main(MyThread* this) {
     253                //...
     254        }
     255
     256        void foo() {
     257                MyThread thrds[10];
     258                //Start 10 threads at the beginning of the scope
     259
     260                DoStuff();
     261
     262                //Wait for the 10 threads to finish
     263        }
     264\end{cfacode}
  • doc/proposals/concurrency/text/concurrency.tex

    r436c0de rade20d0  
    44% ======================================================================
    55% ======================================================================
    6 Several tool can be used to solve concurrency challenges. Since many of these challenges appear with the use of mutable shared-state, some languages and libraries simply disallow mutable shared-state (Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, Akka (Scala)~\cite{Akka}). In these paradigms, interaction among concurrent objects relies on message passing~\cite{Thoth,Harmony,V-Kernel} or other paradigms that closely relate to networking concepts (channels\cit for example). However, in languages that use routine calls as their core abstraction-mechanism, these approaches force a clear distinction between concurrent and non-concurrent paradigms (i.e., message passing versus routine call). This distinction in turn means that, in order to be effective, programmers need to learn two sets of designs patterns. While this distinction can be hidden away in library code, effective use of the librairy still has to take both paradigms into account.
    7 
    8 Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on basic constructs like routine calls and shared objects. At the lowest level, concurrent paradigms are implemented as atomic operations and locks. Many such mechanisms have been proposed, including semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}. However, for productivity reasons it is desireable to have a higher-level construct be the core concurrency paradigm~\cite{HPP:Study}.
    9 
    10 An approach that is worth mentionning because it is gaining in popularity is transactionnal memory~\cite{Dice10}[Check citation]. While this approach is even pursued by system languages like \CC\cit, the performance and feature set is currently too restrictive to be the main concurrency paradigm for general purpose language, which is why it was rejected as the core paradigm for concurrency in \CFA.
    11 
    12 One of the most natural, elegant, and efficient mechanisms for synchronization and communication, especially for shared memory systems, is the \emph{monitor}. Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}. Many programming languages---e.g., Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}---provide monitors as explicit language constructs. In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors. For these reasons, this project proposes monitors as the core concurrency-construct.
     6Several tool can be used to solve concurrency challenges. Since many of these challenges appear with the use of mutable shared-state, some languages and libraries simply disallow mutable shared-state (Erlang~\cite{Erlang}, Haskell~\cite{Haskell}, Akka (Scala)~\cite{Akka}). In these paradigms, interaction among concurrent objects relies on message passing~\cite{Thoth,Harmony,V-Kernel} or other paradigms that closely relate to networking concepts (channels\cit for example). However, in languages that use routine calls as their core abstraction-mechanism, these approaches force a clear distinction between concurrent and non-concurrent paradigms (i.e., message passing versus routine call). This distinction in turn means that, in order to be effective, programmers need to learn two sets of designs patterns. This distinction can be hidden away in library code, effective use of the librairy still has to take both paradigms into account. Approaches based on shared memory are more closely related to non-concurrent paradigms since they often rely on basic constructs like routine calls and shared objects. At a lower level, non-concurrent paradigms are often implemented as locks and atomic operations. Many such mechanisms have been proposed, including semaphores~\cite{Dijkstra68b} and path expressions~\cite{Campbell74}. However, for productivity reasons it is desireable to have a higher-level construct be the core concurrency paradigm~\cite{HPP:Study}. An approach that is worth mentionning because it is gaining in popularity is transactionnal memory~\cite{Dice10}[Check citation]. While this approach is even pursued by system languages like \CC\cit, the performance and feature set is currently too restrictive to add such a paradigm to a language like C or \CC\cit, which is why it was rejected as the core paradigm for concurrency in \CFA. One of the most natural, elegant, and efficient mechanisms for synchronization and communication, especially for shared memory systems, is the \emph{monitor}. Monitors were first proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}. Many programming languages---e.g., Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Modula~\cite{Modula-2}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, NeWS~\cite{NeWS}, Emerald~\cite{Emerald}, \uC~\cite{Buhr92a} and Java~\cite{Java}---provide monitors as explicit language constructs. In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as semaphores or locks to simulate monitors. For these reasons, this project proposes monitors as the core concurrency-construct.
    137
    148\section{Basics}
    15 Non-determinism requires concurrent systems to offer support for mutual-exclusion and synchronisation. Mutual-exclusion is the concept that only a fixed number of threads can access a critical section at any given time, where a critical section is a group of instructions on an associated portion of data that requires the restricted access. On the other hand, synchronization enforces relative ordering of execution and synchronization tools numerous mechanisms to establish timing relationships among threads.
     9The basic features that concurrency tools neet to offer is support for mutual-exclusion and synchronisation. Mutual-exclusion is the concept that only a fixed number of threads can access a critical section at any given time, where a critical section is the group of instructions on an associated portion of data that requires the limited access. On the other hand, synchronization enforces relative ordering of execution and synchronization tools are used to guarantee that event \textit{X} always happens before \textit{Y}.
    1610
    1711\subsection{Mutual-Exclusion}
    18 As mentionned above, mutual-exclusion is the guarantee that only a fix number of threads can enter a critical section at once. However, many solution exists for mutual exclusion which vary in terms of performance, flexibility and ease of use. Methods range from low-level locks, which are fast and flexible but require significant attention to be correct, to  higher-level mutual-exclusion methods, which sacrifice some performance in order to improve ease of use. Ease of use comes by either guaranteeing some problems cannot occur (e.g., being deadlock free) or by offering a more explicit coupling between data and corresponding critical section. For example, the \CC \code{std::atomic<T>} which offer an easy way to express mutual-exclusion on a restricted set of operations (.e.g: reading/writing large types atomically). Another challenge with low-level locks is composability. Locks are not composable because it takes careful organising for multiple locks to be used while preventing deadlocks. Easing composability is another feature higher-level mutual-exclusion mechanisms often offer.
     12As mentionned above, mutual-exclusion is the guarantee that only a fix number of threads can enter a critical section at once. However, many solution exists for mutual exclusion which vary in terms of performance, flexibility and ease of use. Methods range from low level locks, which are fast and flexible but require significant attention to be correct, to  higher level mutual-exclusion methods, which sacrifice some performance in order to improve ease of use. Often by either guaranteeing some problems cannot occur (e.g. being deadlock free) or by offering a more explicit coupling between data and corresponding critical section. For example, the \CC \code{std::atomic<T>} which offer an easy way to express mutual-exclusion on a restricted set of features (.e.g: reading/writing large types atomically). Another challenge with low level locks is composability. Locks are said to not be composable because it takes careful organising for multiple locks to be used and once while preventing deadlocks. Easing composability is another feature higher-level mutual-exclusion mechanisms often offer.
    1913
    2014\subsection{Synchronization}
    21 As for mutual-exclusion, low level synchronisation primitive often offer good performance and good flexibility at the cost of ease of use. Again, higher-level mechanism often simplify usage by adding better coupling between synchronization and data, .eg., message passing, or offering simple solution to otherwise involved challenges. An example of this is barging. As mentionned above synchronization can be expressed as guaranteeing that event \textit{X} always happens before \textit{Y}. Most of the time synchronisation happens around a critical section, where threads most acquire said critical section in a certain order. However, it may also be desired to be able to guarantee that event \textit{Z} does not occur between \textit{X} and \textit{Y}. This is called barging, where event \textit{X} tries to effect event \textit{Y} but anoter thread races to grab the critical section and emits \textit{Z} before \textit{Y}. Preventing or detecting barging is an involved challenge with low-level locks, which can be made much easier by higher-level constructs.
     15As for mutual-exclusion, low level synchronisation primitive often offer great performance and good flexibility at the cost of ease of use. Again, higher-level mechanism often simplify usage by adding better coupling between synchronization and data, for example message passing, or offering simple solution to otherwise involved challenges. An example of this is barging. As mentionned above synchronization can be expressed as guaranteeing that event \textit{X} always happens before \textit{Y}. Most of the time synchronisation happens around a critical section, where threads most acquire said critical section in a certain order. However, it may also be desired to be able to guarantee that event \textit{Z} does not occur between \textit{X} and \textit{Y}. This is called barging, where event \textit{X} tries to effect event \textit{Y} but anoter thread races to grab the critical section and emits \textit{Z} before \textit{Y}. Preventing or detecting barging is an involved challenge with low-level locks, which can be made much easier by higher-level constructs.
    2216
    2317% ======================================================================
     
    2620% ======================================================================
    2721% ======================================================================
    28 A monitor is a set of routines that ensure mutual exclusion when accessing shared state. This concept is generally associated with Object-Oriented Languages like Java~\cite{Java} or \uC~\cite{uC++book} but does not strictly require OO semantics. The only requirements is the ability to declare a handle to a shared object and a set of routines that act on it :
     22A monitor is a set of routines that ensure mutual exclusion when accessing shared state. This concept is generally associated with Object-Oriented Languages like Java~\cite{Java} or \uC~\cite{uC++book} but does not strictly require OOP semantics. The only requirements is the ability to declare a handle to a shared object and a set of routines that act on it :
    2923\begin{cfacode}
    3024        typedef /*some monitor type*/ monitor;
     
    4236% ======================================================================
    4337% ======================================================================
    44 The above monitor example displays some of the intrinsic characteristics. First, it is necessary to use pass-by-reference over pass-by-value for monitor routines. This semantics is important because at their core, monitors are implicit mutual-exclusion objects (locks), and these objects cannot be copied. Therefore, monitors are implicitly non-copyable objects.
    45 
    46 Another aspect to consider is when a monitor acquires its mutual exclusion. For example, a monitor may need to be passed through multiple helper routines that do not acquire the monitor mutual-exclusion on entry. Pass through can occur for generic helper routines (\code{swap}, \code{sort}, etc.) or specific helper routines like the following to implement an atomic counter :
     38The above monitor example displays some of the intrinsic characteristics. Indeed, it is necessary to use pass-by-reference over pass-by-value for monitor routines. This semantics is important because at their core, monitors are implicit mutual-exclusion objects (locks), and these objects cannot be copied. Therefore, monitors are implicitly non-copyable.
     39
     40Another aspect to consider is when a monitor acquires its mutual exclusion. For example, a monitor may need to be passed through multiple helper routines that do not acquire the monitor mutual-exclusion on entry. Pass through can be both generic helper routines (\code{swap}, \code{sort}, etc.) or specific helper routines like the following to implement an atomic counter :
    4741
    4842\begin{cfacode}
     
    5246        size_t ++?(counter_t & mutex this); //increment
    5347
    54         //need for mutex is platform dependent
     48        //need for mutex is platform dependent here
    5549        void ?{}(size_t * this, counter_t & mutex cnt); //conversion
    5650\end{cfacode}
     
    5852Here, the constructor(\code{?\{\}}) uses the \code{nomutex} keyword to signify that it does not acquire the monitor mutual-exclusion when constructing. This semantics is because an object not yet constructed should never be shared and therefore does not require mutual exclusion. The prefix increment operator uses \code{mutex} to protect the incrementing process from race conditions. Finally, there is a conversion operator from \code{counter_t} to \code{size_t}. This conversion may or may not require the \code{mutex} keyword depending on whether or not reading an \code{size_t} is an atomic operation.
    5953
    60 Having both \code{mutex} and \code{nomutex} keywords is redundant based on the meaning of a routine having neither of these keywords. For example, given a routine without qualifiers \code{void foo(counter_t & this)}, then it is reasonable that it should default to the safest option \code{mutex}, whereas assuming \code{nomutex} is unsafe and may cause subtle errors. In fact, \code{nomutex} is the "normal" parameter behaviour, with the \code{nomutex} keyword effectively stating explicitly that "this routine is not special". Another alternative is to make having exactly one of these keywords mandatory, which would provide the same semantics but without the ambiguity of supporting routines neither keyword. Mandatory keywords would also have the added benefit of being self-documented but at the cost of extra typing. While there are several benefits to mandatory keywords, they do bring a few challenges. Mandatory keywords in \CFA would imply that the compiler must know without a doubt wheter or not a parameter is a monitor or not. Since \CFA relies heavily on traits as an abstraction mechanism, the distinction between a type that is a monitor and a type that looks like a monitor can become blurred. For this reason, \CFA only has the \code{mutex} keyword.
     54Having both \code{mutex} and \code{nomutex} keywords could be argued to be redundant based on the meaning of a routine having neither of these keywords. For example, given a routine without qualifiers \code{void foo(counter_t & this)} then it is reasonable that it should default to the safest option \code{mutex}. On the other hand, the option of having routine \code{void foo(counter_t & this)} mean \code{nomutex} is unsafe by default and may easily cause subtle errors. In fact \code{nomutex} is the "normal" parameter behaviour, with the \code{nomutex} keyword effectively stating explicitly that "this routine is not special". Another alternative is to make having exactly one of these keywords mandatory, which would provide the same semantics but without the ambiguity of supporting routines neither keyword. Mandatory keywords would also have the added benefit of being self-documented but at the cost of extra typing. While there are several benefits to mandatory keywords, they do bring a few challenges. Mandatory keywords in \CFA would imply that the compiler must know without a doubt wheter or not a parameter is a monitor or not. Since \CFA relies heavily on traits as an abstraction mechanism, the distinction between a type that is a monitor and a type that looks like a monitor can become blurred. For this reason, \CFA only has the \code{mutex} keyword.
    6155
    6256
     
    6660int f2(const monitor & mutex m);
    6761int f3(monitor ** mutex m);
    68 int f4(monitor * mutex m []);
     62int f4(monitor *[] mutex m);
    6963int f5(graph(monitor*) & mutex m);
    7064\end{cfacode}
     
    7468int f1(monitor & mutex m);   //Okay : recommanded case
    7569int f2(monitor * mutex m);   //Okay : could be an array but probably not
    76 int f3(monitor mutex m []);  //Not Okay : Array of unkown length
     70int f3(monitor [] mutex m);  //Not Okay : Array of unkown length
    7771int f4(monitor ** mutex m);  //Not Okay : Could be an array
    78 int f5(monitor * mutex m []); //Not Okay : Array of unkown length
     72int f5(monitor *[] mutex m); //Not Okay : Array of unkown length
    7973\end{cfacode}
    8074
  • doc/proposals/concurrency/text/intro.tex

    r436c0de rade20d0  
    33% ======================================================================
    44
    5 This proposal provides a minimal concurrency API that is simple, efficient and can be reused to build higher-level features. The simplest possible concurrency system is a thread and a lock but this low-level approach is hard to master. An easier approach for users is to support higher-level constructs as the basis of the concurrency, in \CFA. Indeed, for highly productive parallel programming, high-level approaches are much more popular~\cite{HPP:Study}. Examples are task based, message passing and implicit threading. Therefore a high-level approach is adapted in \CFA
     5This proposal provides a minimal concurrency API that is simple, efficient and can be reused to build higher-level features. The simplest possible concurrency core is a thread and a lock but this low-level approach is hard to master. An easier approach for users is to support higher-level constructs as the basis of the concurrency in \CFA. Indeed, for highly productive parallel programming, high-level approaches are much more popular~\cite{HPP:Study}. Examples are task based, message passing and implicit threading.
    66
    7 There are actually two problems that need to be solved in the design of concurrency for a programming language: which concurrency and which parallelism tools are available to the users. While these two concepts are often combined, they are in fact distinct concepts that require different tools~\cite{Buhr05a}. Concurrency tools need to handle mutual exclusion and synchronization, while parallelism tools are about performance, cost and resource utilization.
     7There are actually two problems that need to be solved in the design of concurrency for a programming language: which concurrency tools are available to the users and which parallelism tools are available. While these two concepts are often seen together, they are in fact distinct concepts that require different sorts of tools~\cite{Buhr05a}. Concurrency tools need to handle mutual exclusion and synchronization, while parallelism tools are about performance, cost and resource utilization.
  • doc/proposals/concurrency/thesis.tex

    r436c0de rade20d0  
    7777\fancyhf{}
    7878\cfoot{\thepage}
    79 \rfoot{v\input{version}}
     79\rfoot{v\input{build/version}}
    8080
    8181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    9494
    9595\input{intro}
    96 
    97 \input{cforall}
    9896
    9997\input{basics}
  • doc/user/user.tex

    r436c0de rade20d0  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Fri Jun 16 12:00:01 2017
    14 %% Update Count     : 2433
     13%% Last Modified On : Fri Jun  2 10:07:51 2017
     14%% Update Count     : 2128
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    4343\usepackage[pagewise]{lineno}
    4444\renewcommand{\linenumberfont}{\scriptsize\sffamily}
    45 \input{common}                                          % common CFA document macros
     45\input{common}                                          % bespoke macros used in the document
    4646\usepackage[dvips,plainpages=false,pdfpagelabels,pdfpagemode=UseNone,colorlinks=true,pagebackref=true,linkcolor=blue,citecolor=blue,urlcolor=blue,pagebackref=true,breaklinks=true]{hyperref}
    4747\usepackage{breakurl}
     
    110110\renewcommand{\subsectionmark}[1]{\markboth{\thesubsection\quad #1}{\thesubsection\quad #1}}
    111111\pagenumbering{roman}
    112 %\linenumbers                                            % comment out to turn off line numbering
     112\linenumbers                                            % comment out to turn off line numbering
    113113
    114114\maketitle
     
    454454the type suffixes ©U©, ©L©, etc. may start with an underscore ©1_U©, ©1_ll© or ©1.0E10_f©.
    455455\end{enumerate}
    456 It is significantly easier to read and enter long constants when they are broken up into smaller groupings (many cultures use comma and/or period among digits for the same purpose).
     456It is significantly easier to read and enter long constants when they are broken up into smaller groupings (most cultures use comma or period among digits for the same purpose).
    457457This extension is backwards compatible, matches with the use of underscore in variable names, and appears in \Index*{Ada} and \Index*{Java} 8.
    458458
     
    464464\begin{cfa}
    465465int ®`®otype®`® = 3;                    §\C{// make keyword an identifier}§
    466 double ®`®forall®`® = 3.5;
    467 \end{cfa}
    468 Existing C programs with keyword clashes can be converted by enclosing keyword identifiers in backquotes, and eventually the identifier name can be changed to a non-keyword name.
     466double ®`®choose®`® = 3.5;
     467\end{cfa}
     468Programs can be converted easily by enclosing keyword identifiers in backquotes, and the backquotes can be removed later when the identifier name is changed to a non-keyword name.
    469469\VRef[Figure]{f:InterpositionHeaderFile} shows how clashes in C header files (see~\VRef{s:StandardHeaders}) can be handled using preprocessor \newterm{interposition}: ©#include_next© and ©-I filename©:
    470470
     
    473473// include file uses the CFA keyword "otype".
    474474#if ! defined( otype )                  §\C{// nesting ?}§
    475 #define otype ®`®otype®`®               §\C{// make keyword an identifier}§
     475#define otype `otype`
    476476#define __CFA_BFD_H__
    477477#endif // ! otype
     
    497497\begin{tabular}{@{}ll@{}}
    498498\begin{cfa}
    499 int * x[5]
     499int *x[5]
    500500\end{cfa}
    501501&
     
    508508For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way:
    509509\begin{cfa}
    510 int ®(*®f®())[®5®]® {...};                              §\C{definition
    511  ... ®(*®f®())[®3®]® += 1;                              §\C{usage}§
     510int (*f())[5] {...};                    §\C{
     511... (*f())[3] += 1;
    512512\end{cfa}
    513513Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}).
     
    516516\CFA provides its own type, variable and routine declarations, using a different syntax.
    517517The new declarations place qualifiers to the left of the base type, while C declarations place qualifiers to the right of the base type.
    518 In the following example, \R{red} is the base type and \B{blue} is qualifiers.
     518In the following example, \R{red} is for the base type and \B{blue} is for the qualifiers.
    519519The \CFA declarations move the qualifiers to the left of the base type, \ie move the blue to the left of the red, while the qualifiers have the same meaning but are ordered left to right to specify a variable's type.
    520520\begin{quote2}
     
    534534\end{tabular}
    535535\end{quote2}
    536 The only exception is \Index{bit field} specification, which always appear to the right of the base type.
     536The only exception is bit field specification, which always appear to the right of the base type.
    537537% Specifically, the character ©*© is used to indicate a pointer, square brackets ©[©\,©]© are used to represent an array or function return value, and parentheses ©()© are used to indicate a routine parameter.
    538538However, unlike C, \CFA type declaration tokens are distributed across all variables in the declaration list.
     
    583583\begin{cfa}
    584584int z[ 5 ];
    585 char * w[ 5 ];
    586 double (* v)[ 5 ];
     585char *w[ 5 ];
     586double (*v)[ 5 ];
    587587struct s {
    588588        int f0:3;
    589         int * f1;
    590         int * f2[ 5 ]
     589        int *f1;
     590        int *f2[ 5 ]
    591591};
    592592\end{cfa}
     
    637637\begin{cfa}
    638638int extern x[ 5 ];
    639 const int static * y;
     639const int static *y;
    640640\end{cfa}
    641641&
     
    658658\begin{cfa}
    659659y = (®int *®)x;
    660 i = sizeof(®int * [ 5 ]®);
     660i = sizeof(®int *[ 5 ]®);
    661661\end{cfa}
    662662\end{tabular}
     
    672672C provides a \newterm{pointer type};
    673673\CFA adds a \newterm{reference type}.
    674 These types may be derived from an object or routine type, called the \newterm{referenced type}.
     674These types may be derived from a object or routine type, called the \newterm{referenced type}.
    675675Objects of these types contain an \newterm{address}, which is normally a location in memory, but may also address memory-mapped registers in hardware devices.
    676676An integer constant expression with the value 0, or such an expression cast to type ©void *©, is called a \newterm{null-pointer constant}.\footnote{
     
    729729
    730730A \Index{pointer}/\Index{reference} object is a generalization of an object variable-name, \ie a mutable address that can point to more than one memory location during its lifetime.
    731 (Similarly, an integer variable can contain multiple integer literals during its lifetime versus an integer constant representing a single literal during its lifetime, and like a variable name, may not occupy storage if the literal is embedded directly into instructions.)
     731(Similarly, an integer variable can contain multiple integer literals during its lifetime versus an integer constant representing a single literal during its lifetime, and like a variable name, may not occupy storage as the literal is embedded directly into instructions.)
    732732Hence, a pointer occupies memory to store its current address, and the pointer's value is loaded by dereferencing, \eg:
    733733\begin{quote2}
     
    758758\begin{cfa}
    759759p1 = p2;                                                §\C{// p1 = p2\ \ rather than\ \ *p1 = *p2}§
    760 p2 = p1 + x;                                    §\C{// p2 = p1 + x\ \ rather than\ \ *p2 = *p1 + x}§
     760p2 = p1 + x;                                    §\C{// p2 = p1 + x\ \ rather than\ \ *p1 = *p1 + x}§
    761761\end{cfa}
    762762even though the assignment to ©p2© is likely incorrect, and the programmer probably meant:
     
    765765®*®p2 = ®*®p1 + x;                              §\C{// pointed-to value assignment / operation}§
    766766\end{cfa}
    767 The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©).
     767The C semantics works well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©).
    768768
    769769However, in most other situations, the pointed-to value is requested more often than the pointer address.
     
    799799For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}):
    800800\begin{cfa}
    801 (&®*®)r1 = &x;                                  §\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}§
     801(&®*®)r1 = &x;                                  §\C{// (\&*) cancel giving address of r1 not variable pointed-to by r1}§
    802802\end{cfa}
    803803Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}):
    804804\begin{cfa}
    805 (&(&®*®)®*®)r3 = &(&®*®)r2;             §\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}§
     805(&(&®*®)®*®)r3 = &(&®*®)r2;             §\C{// (\&*) cancel giving address of r2, (\&(\&*)*) cancel giving address of r3}§
    806806\end{cfa}
    807807Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth.
     
    824824As for a pointer type, a reference type may have qualifiers:
    825825\begin{cfa}
    826 const int cx = 5;                                       §\C{// cannot change cx;}§
    827 const int & cr = cx;                            §\C{// cannot change what cr points to}§
    828 ®&®cr = &cx;                                            §\C{// can change cr}§
    829 cr = 7;                                                         §\C{// error, cannot change cx}§
    830 int & const rc = x;                                     §\C{// must be initialized}§
    831 ®&®rc = &x;                                                     §\C{// error, cannot change rc}§
    832 const int & const crc = cx;                     §\C{// must be initialized}§
    833 crc = 7;                                                        §\C{// error, cannot change cx}§
    834 ®&®crc = &cx;                                           §\C{// error, cannot change crc}§
    835 \end{cfa}
    836 Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}:
    837 \begin{cfa}
    838 int & const cr = *0;                            §\C{// where 0 is the int * zero}§
    839 \end{cfa}
    840 Note, constant reference-types do not prevent \Index{addressing errors} because of explicit storage-management:
     826const int cx = 5;                               §\C{// cannot change cx;}§
     827const int & cr = cx;                    §\C{// cannot change what cr points to}§
     828®&®cr = &cx;                                    §\C{// can change cr}§
     829cr = 7;                                                 §\C{// error, cannot change cx}§
     830int & const rc = x;                             §\C{// must be initialized}§
     831®&®rc = &x;                                             §\C{// error, cannot change rc}§
     832const int & const crc = cx;             §\C{// must be initialized}§
     833crc = 7;                                                §\C{// error, cannot change cx}§
     834®&®crc = &cx;                                   §\C{// error, cannot change crc}§
     835\end{cfa}
     836Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced into the reference}:
     837\begin{cfa}
     838int & const cr = *0;                    §\C{// where 0 is the int * zero}§
     839\end{cfa}
     840Note, constant reference-types do not prevent addressing errors because of explicit storage-management:
    841841\begin{cfa}
    842842int & const cr = *malloc();
    843843cr = 5;
    844 free( &cr );
    845 cr = 7;                                                         §\C{// unsound pointer dereference}§
    846 \end{cfa}
    847 
    848 The position of the ©const© qualifier \emph{after} the pointer/reference qualifier causes confuse for C programmers.
     844delete &cr;
     845cr = 7;                                                 §\C{// unsound pointer dereference}§
     846\end{cfa}
     847
     848Finally, the position of the ©const© qualifier \emph{after} the pointer/reference qualifier causes confuse for C programmers.
    849849The ©const© qualifier cannot be moved before the pointer/reference qualifier for C style-declarations;
    850 \CFA-style declarations (see \VRef{s:Declarations}) attempt to address this issue:
     850\CFA-style declarations attempt to address this issue:
    851851\begin{quote2}
    852852\begin{tabular}{@{}l@{\hspace{3em}}l@{}}
     
    863863\end{tabular}
    864864\end{quote2}
    865 where the \CFA declaration is read left-to-right.
    866 
    867 Finally, like pointers, references are usable and composable with other type operators and generators.
    868 \begin{cfa}
    869 int w, x, y, z, & ar[3] = { x, y, z }; §\C{// initialize array of references}§
    870 &ar[1] = &w;                                            §\C{// change reference array element}§
    871 typeof( ar[1] ) p;                                      §\C{// (gcc) is int, i.e., the type of referenced object}§
    872 typeof( &ar[1] ) q;                                     §\C{// (gcc) is int \&, i.e., the type of reference}§
    873 sizeof( ar[1] ) == sizeof( int );       §\C{// is true, i.e., the size of referenced object}§
    874 sizeof( &ar[1] ) == sizeof( int *)      §\C{// is true, i.e., the size of a reference}§
    875 \end{cfa}
     865where the \CFA declaration is read left-to-right (see \VRef{s:Declarations}).
    876866
    877867In contrast to \CFA reference types, \Index*[C++]{\CC{}}'s reference types are all ©const© references, preventing changes to the reference address, so only value assignment is possible, which eliminates half of the \Index{address duality}.
    878 Also, \CC does not allow \Index{array}s\index{array!reference} of reference\footnote{
    879 The reason for disallowing arrays of reference is unknown, but possibly comes from references being ethereal (like a textual macro), and hence, replaceable by the referant object.}
    880868\Index*{Java}'s reference types to objects (all Java objects are on the heap) are like C pointers, which always manipulate the address, and there is no (bit-wise) object assignment, so objects are explicitly cloned by shallow or deep copying, which eliminates half of the address duality.
    881 
    882 
    883 \subsection{Initialization}
    884869
    885870\Index{Initialization} is different than \Index{assignment} because initialization occurs on the empty (uninitialized) storage on an object, while assignment occurs on possibly initialized storage of an object.
     
    887872Because the object being initialized has no value, there is only one meaningful semantics with respect to address duality: it must mean address as there is no pointed-to value.
    888873In contrast, the left-hand side of assignment has an address that has a duality.
    889 Therefore, for pointer/reference initialization, the initializing value must be an address not a value.
    890 \begin{cfa}
    891 int * p = &x;                                           §\C{// assign address of x}§
    892 ®int * p = x;®                                          §\C{// assign value of x}§
    893 int & r = x;                                            §\C{// must have address of x}§
    894 \end{cfa}
    895 Like the previous example with C pointer-arithmetic, it is unlikely assigning the value of ©x© into a pointer is meaningful (again, a warning is usually given).
    896 Therefore, for safety, this context requires an address, so it is superfluous to require explicitly taking the address of the initialization object, even though the type is incorrect.
    897 Note, this is strictly a convenience and safety feature for a programmer.
    898 Hence, \CFA allows ©r© to be assigned ©x© because it infers a reference for ©x©, by implicitly inserting a address-of operator, ©&©, and it is an error to put an ©&© because the types no longer match due to the implicit dereference.
    899 Unfortunately, C allows ©p© to be assigned with ©&x© (address) or ©x© (value), but most compilers warn about the latter assignment as being potentially incorrect.
     874Therefore, for pointer/reference initialization, the initializing value must be an address (\Index{lvalue}) not a value (\Index{rvalue}).
     875\begin{cfa}
     876int * p = &x;                           §\C{// must have address of x}§
     877int & r = x;                            §\C{// must have address of x}§
     878\end{cfa}
     879Therefore, it is superfluous to require explicitly taking the address of the initialization object, even though the type is incorrect.
     880Hence, \CFA allows ©r© to be assigned ©x© because it infers a reference for ©x©, by implicitly inserting a address-of operator, ©&©, and it is an error to put an ©&© because the types no longer match.
     881Unfortunately, C allows ©p© to be assigned with ©&x© or ©x©, by value, but most compilers warn about the latter assignment as being potentially incorrect.
     882(\CFA extends pointer initialization so a variable name is automatically referenced, eliminating the unsafe assignment.)
    900883Similarly, when a reference type is used for a parameter/return type, the call-site argument does not require a reference operator for the same reason.
    901884\begin{cfa}
    902 int & f( int & r );                                     §\C{// reference parameter and return}§
    903 z = f( x ) + f( y );                            §\C{// reference operator added, temporaries needed for call results}§
     885int & f( int & r );                             §\C{// reference parameter and return}§
     886z = f( x ) + f( y );                    §\C{// reference operator added, temporaries needed for call results}§
    904887\end{cfa}
    905888Within routine ©f©, it is possible to change the argument by changing the corresponding parameter, and parameter ©r© can be locally reassigned within ©f©.
     
    909892z = temp1 + temp2;
    910893\end{cfa}
    911 This \Index{implicit referencing} is crucial for reducing the syntactic burden for programmers when using references;
     894This implicit referencing is crucial for reducing the syntactic burden for programmers when using references;
    912895otherwise references have the same syntactic  burden as pointers in these contexts.
    913896
     
    916899void f( ®const® int & cr );
    917900void g( ®const® int * cp );
    918 f( 3 );                   g( ®&®3 );
    919 f( x + y );             g( ®&®(x + y) );
     901f( 3 );                   g( &3 );
     902f( x + y );             g( &(x + y) );
    920903\end{cfa}
    921904Here, the compiler passes the address to the literal 3 or the temporary for the expression ©x + y©, knowing the argument cannot be changed through the parameter.
    922 The ©&© before the constant/expression for the pointer-type parameter (©g©) is a \CFA extension necessary to type match and is a common requirement before a variable in C (\eg ©scanf©).
    923 Importantly, ©&3© may not be equal to ©&3©, where the references occur across calls because the temporaries maybe different on each call.
    924 
     905(The ©&© is necessary for the pointer-type parameter to make the types match, and is a common requirement for a C programmer.)
    925906\CFA \emph{extends} this semantics to a mutable pointer/reference parameter, and the compiler implicitly creates the necessary temporary (copying the argument), which is subsequently pointed-to by the reference parameter and can be changed.\footnote{
    926907If whole program analysis is possible, and shows the parameter is not assigned, \ie it is ©const©, the temporary is unnecessary.}
     
    928909void f( int & r );
    929910void g( int * p );
    930 f( 3 );                   g( ®&®3 );            §\C{// compiler implicit generates temporaries}§
    931 f( x + y );             g( ®&®(x + y) );        §\C{// compiler implicit generates temporaries}§
     911f( 3 );                   g( &3 );              §\C{// compiler implicit generates temporaries}§
     912f( x + y );             g( &(x + y) );  §\C{// compiler implicit generates temporaries}§
    932913\end{cfa}
    933914Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{
     
    936917
    937918%\CFA attempts to handle pointers and references in a uniform, symmetric manner.
    938 Finally, C handles \Index{routine object}s in an inconsistent way.
    939 A routine object is both a pointer and a reference (\Index{particle and wave}).
     919However, C handles routine objects in an inconsistent way.
     920A routine object is both a pointer and a reference (particle and wave).
    940921\begin{cfa}
    941922void f( int i );
    942 void (*fp)( int );                                      §\C{// routine pointer}§
    943 fp = f;                                                         §\C{// reference initialization}§
    944 fp = &f;                                                        §\C{// pointer initialization}§
    945 fp = *f;                                                        §\C{// reference initialization}§
    946 fp(3);                                                          §\C{// reference invocation}§
    947 (*fp)(3);                                                       §\C{// pointer invocation}§
    948 \end{cfa}
    949 While C's treatment of routine objects has similarity to inferring a reference type in initialization contexts, the examples are assignment not initialization, and all possible forms of assignment are possible (©f©, ©&f©, ©*f©) without regard for type.
    950 Instead, a routine object should be referenced by a ©const© reference:
    951 \begin{cfa}
    952 ®const® void (®&® fr)( int ) = f;       §\C{// routine reference}§
    953 fr = ...                                                        §\C{// error, cannot change code}§
    954 &fr = ...;                                                      §\C{// changing routine reference}§
    955 fr( 3 );                                                        §\C{// reference call to f}§
    956 (*fr)(3);                                                       §\C{// error, incorrect type}§
     923void (*fp)( int );
     924fp = f;                                                 §\C{// reference initialization}§
     925fp = &f;                                                §\C{// pointer initialization}§
     926fp = *f;                                                §\C{// reference initialization}§
     927fp(3);                                                  §\C{// reference invocation}§
     928(*fp)(3);                                               §\C{// pointer invocation}§
     929\end{cfa}
     930A routine object is best described by a ©const© reference:
     931\begin{cfa}
     932const void (&fr)( int ) = f;
     933fr = ...                                                §\C{// error, cannot change code}§
     934&fr = ...;                                              §\C{// changing routine reference}§
     935fr( 3 );                                                §\C{// reference call to f}§
     936(*fr)(3);                                               §\C{// error, incorrect type}§
    957937\end{cfa}
    958938because the value of the routine object is a routine literal, \ie the routine code is normally immutable during execution.\footnote{
     
    960940\CFA allows this additional use of references for routine objects in an attempt to give a more consistent meaning for them.
    961941
    962 
    963 \subsection{Address-of Semantics}
    964 
    965 In C, ©&E© is an rvalue for any expression ©E©.
    966 \CFA extends the ©&© (address-of) operator as follows:
    967 \begin{itemize}
    968 \item
    969 if ©R© is an \Index{rvalue} of type ©T &$_1$...&$_r$© where $r \ge 1$ references (©&© symbols) than ©&R© has type ©T ®*®&$_{\color{red}2}$...&$_{\color{red}r}$©, \ie ©T© pointer with $r-1$ references (©&© symbols).
    970 
    971 \item
    972 if ©L© is an \Index{lvalue} of type ©T &$_1$...&$_l$© where $l \ge 0$ references (©&© symbols) then ©&L© has type ©T ®*®&$_{\color{red}1}$...&$_{\color{red}l}$©, \ie ©T© pointer with $l$ references (©&© symbols).
    973 \end{itemize}
    974 The following example shows the first rule applied to different \Index{rvalue} contexts:
    975 \begin{cfa}
    976 int x, * px, ** ppx, *** pppx, **** ppppx;
    977 int & rx = x, && rrx = rx, &&& rrrx = rrx ;
    978 x = rrrx;               // rrrx is an lvalue with type int &&& (equivalent to x)
    979 px = &rrrx;             // starting from rrrx, &rrrx is an rvalue with type int *&&& (&x)
    980 ppx = &&rrrx;   // starting from &rrrx, &&rrrx is an rvalue with type int **&& (&rx)
    981 pppx = &&&rrrx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (&rrx)
    982 ppppx = &&&&rrrx; // starting from &&&rrrx, &&&&rrrx is an rvalue with type int **** (&rrrx)
    983 \end{cfa}
    984 The following example shows the second rule applied to different \Index{lvalue} contexts:
    985 \begin{cfa}
    986 int x, * px, ** ppx, *** pppx;
    987 int & rx = x, && rrx = rx, &&& rrrx = rrx ;
    988 rrrx = 2;               // rrrx is an lvalue with type int &&& (equivalent to x)
    989 &rrrx = px;             // starting from rrrx, &rrrx is an rvalue with type int *&&& (rx)
    990 &&rrrx = ppx;   // starting from &rrrx, &&rrrx is an rvalue with type int **&& (rrx)
    991 &&&rrrx = pppx; // starting from &&rrrx, &&&rrrx is an rvalue with type int ***& (rrrx)
    992 \end{cfa}
    993 
    994 
    995 \subsection{Conversions}
    996 
    997 C provides a basic implicit conversion to simplify variable usage:
    998 \begin{enumerate}
    999 \setcounter{enumi}{-1}
    1000 \item
    1001 lvalue to rvalue conversion: ©cv T© converts to ©T©, which allows implicit variable dereferencing.
    1002 \begin{cfa}
    1003 int x;
    1004 x + 1;                  // lvalue variable (int) converts to rvalue for expression
    1005 \end{cfa}
    1006 An rvalue has no type qualifiers (©cv©), so the lvalue qualifiers are dropped.
    1007 \end{enumerate}
    1008 \CFA provides three new implicit conversion for reference types to simplify reference usage.
    1009 \begin{enumerate}
    1010 \item
    1011 reference to rvalue conversion: ©cv T &© converts to ©T©, which allows implicit reference dereferencing.
    1012 \begin{cfa}
    1013 int x, &r = x, f( int p );
    1014 x = ®r® + f( ®r® );  // lvalue reference converts to rvalue
    1015 \end{cfa}
    1016 An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped.
    1017 
    1018 \item
    1019 lvalue to reference conversion: \lstinline[deletekeywords={lvalue}]@lvalue-type cv1 T@ converts to ©cv2 T &©, which allows implicitly converting variables to references.
    1020 \begin{cfa}
    1021 int x, &r = ®x®, f( int & p ); // lvalue variable (int) convert to reference (int &)
    1022 f( ®x® );               // lvalue variable (int) convert to reference (int &)
    1023 \end{cfa}
    1024 Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost.
    1025 Conversion can expand a type, where ©cv1© $>$ ©cv2©, \eg passing a ©const volatile int© to an ©int &©, which has high cost (\Index{warning});
    1026 furthermore, if ©cv1© has ©const© but not ©cv2©, a temporary variable is created to preserve the immutable lvalue.
    1027 
    1028 \item
    1029 rvalue to reference conversion: ©T© converts to ©cv T &©, which allows binding references to temporaries.
    1030 \begin{cfa}
    1031 int x, & f( int & p );
    1032 f( ®x + 3® );   // rvalue parameter (int) implicitly converts to lvalue temporary reference (int &)
    1033 ®&f®(...) = &x; // rvalue result (int &) implicitly converts to lvalue temporary reference (int &)
    1034 \end{cfa}
    1035 In both case, modifications to the temporary are inaccessible (\Index{warning}).
    1036 Conversion expands the temporary-type with ©cv©, which is low cost since the temporary is inaccessible.
    1037 \end{enumerate}
     942This situation is different from inferring with reference type being used ...
     943
    1038944
    1039945
    1040946\begin{comment}
     947\section{References}
     948
     949By introducing references in parameter types, users are given an easy way to pass a value by reference, without the need for NULL pointer checks.
     950In structures, a reference can replace a pointer to an object that should always have a valid value.
     951When a structure contains a reference, all of its constructors must initialize the reference and all instances of this structure must initialize it upon definition.
     952
     953The syntax for using references in \CFA is the same as \CC with the exception of reference initialization.
     954Use ©&© to specify a reference, and access references just like regular objects, not like pointers (use dot notation to access fields).
     955When initializing a reference, \CFA uses a different syntax which differentiates reference initialization from assignment to a reference.
     956The ©&© is used on both sides of the expression to clarify that the address of the reference is being set to the address of the variable to which it refers.
     957
     958
    1041959From: Richard Bilson <rcbilson@gmail.com>
    1042960Date: Wed, 13 Jul 2016 01:58:58 +0000
     
    12001118\section{Routine Definition}
    12011119
    1202 \CFA also supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax.
     1120\CFA also supports a new syntax for routine definition, as well as ISO C and K\&R routine syntax.
    12031121The point of the new syntax is to allow returning multiple values from a routine~\cite{Galletly96,CLU}, \eg:
    12041122\begin{cfa}
     
    12201138in both cases the type is assumed to be void as opposed to old style C defaults of int return type and unknown parameter types, respectively, as in:
    12211139\begin{cfa}
    1222 [§\,§] g();                                                     §\C{// no input or output parameters}§
    1223 [ void ] g( void );                                     §\C{// no input or output parameters}§
     1140[§\,§] g();                                             §\C{// no input or output parameters}§
     1141[ void ] g( void );                             §\C{// no input or output parameters}§
    12241142\end{cfa}
    12251143
     
    12391157\begin{cfa}
    12401158typedef int foo;
    1241 int f( int (* foo) );                           §\C{// foo is redefined as a parameter name}§
     1159int f( int (* foo) );                   §\C{// foo is redefined as a parameter name}§
    12421160\end{cfa}
    12431161The string ``©int (* foo)©'' declares a C-style named-parameter of type pointer to an integer (the parenthesis are superfluous), while the same string declares a \CFA style unnamed parameter of type routine returning integer with unnamed parameter of type pointer to foo.
     
    12471165C-style declarations can be used to declare parameters for \CFA style routine definitions, \eg:
    12481166\begin{cfa}
    1249 [ int ] f( * int, int * );                      §\C{// returns an integer, accepts 2 pointers to integers}§
    1250 [ * int, int * ] f( int );                      §\C{// returns 2 pointers to integers, accepts an integer}§
     1167[ int ] f( * int, int * );              §\C{// returns an integer, accepts 2 pointers to integers}§
     1168[ * int, int * ] f( int );              §\C{// returns 2 pointers to integers, accepts an integer}§
    12511169\end{cfa}
    12521170The reason for allowing both declaration styles in the new context is for backwards compatibility with existing preprocessor macros that generate C-style declaration-syntax, as in:
    12531171\begin{cfa}
    12541172#define ptoa( n, d ) int (*n)[ d ]
    1255 int f( ptoa( p, 5 ) ) ...                       §\C{// expands to int f( int (*p)[ 5 ] )}§
    1256 [ int ] f( ptoa( p, 5 ) ) ...           §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§
     1173int f( ptoa( p, 5 ) ) ...               §\C{// expands to int f( int (*p)[ 5 ] )}§
     1174[ int ] f( ptoa( p, 5 ) ) ...   §\C{// expands to [ int ] f( int (*p)[ 5 ] )}§
    12571175\end{cfa}
    12581176Again, programmers are highly encouraged to use one declaration form or the other, rather than mixing the forms.
     
    12761194        int z;
    12771195        ... x = 0; ... y = z; ...
    1278         ®return;®                                                       §\C{// implicitly return x, y}§
     1196        ®return;® §\C{// implicitly return x, y}§
    12791197}
    12801198\end{cfa}
     
    12861204[ int x, int y ] f() {
    12871205        ...
    1288 }                                                                               §\C{// implicitly return x, y}§
     1206} §\C{// implicitly return x, y}§
    12891207\end{cfa}
    12901208In this case, the current values of ©x© and ©y© are returned to the calling routine just as if a ©return© had been encountered.
    1291 
    1292 Named return values may be used in conjunction with named parameter values;
    1293 specifically, a return and parameter can have the same name.
    1294 \begin{cfa}
    1295 [ int x, int y ] f( int, x, int y ) {
    1296         ...
    1297 }                                                                               §\C{// implicitly return x, y}§
    1298 \end{cfa}
    1299 This notation allows the compiler to eliminate temporary variables in nested routine calls.
    1300 \begin{cfa}
    1301 [ int x, int y ] f( int, x, int y );    §\C{// prototype declaration}§
    1302 int a, b;
    1303 [a, b] = f( f( f( a, b ) ) );
    1304 \end{cfa}
    1305 While the compiler normally ignores parameters names in prototype declarations, here they are used to eliminate temporary return-values by inferring that the results of each call are the inputs of the next call, and ultimately, the left-hand side of the assignment.
    1306 Hence, even without the body of routine ©f© (separate compilation), it is possible to perform a global optimization across routine calls.
    1307 The compiler warns about naming inconsistencies between routine prototype and definition in this case, and behaviour is \Index{undefined} if the programmer is inconsistent.
    13081209
    13091210
     
    13131214as well, parameter names are optional, \eg:
    13141215\begin{cfa}
    1315 [ int x ] f ();                                                 §\C{// returning int with no parameters}§
    1316 [ * int ] g (int y);                                    §\C{// returning pointer to int with int parameter}§
    1317 [ ] h ( int, char );                                    §\C{// returning no result with int and char parameters}§
    1318 [ * int, int ] j ( int );                               §\C{// returning pointer to int and int, with int parameter}§
     1216[ int x ] f ();                                 §\C{// returning int with no parameters}§
     1217[ * int ] g (int y);                    §\C{// returning pointer to int with int parameter}§
     1218[ ] h (int,char);                               §\C{// returning no result with int and char parameters}§
     1219[ * int,int ] j (int);                  §\C{// returning pointer to int and int, with int parameter}§
    13191220\end{cfa}
    13201221This syntax allows a prototype declaration to be created by cutting and pasting source text from the routine definition header (or vice versa).
     
    13241225\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c}{\textbf{C}}        \\
    13251226\begin{cfa}
    1326 [ int ] f( int ), g;
     1227[ int ] f(int), g;
    13271228\end{cfa}
    13281229&
    13291230\begin{cfa}
    1330 int f( int ), g( int );
     1231int f(int), g(int);
    13311232\end{cfa}
    13321233\end{tabular}
     
    13341235Declaration qualifiers can only appear at the start of a \CFA routine declaration,\footref{StorageClassSpecifier} \eg:
    13351236\begin{cfa}
    1336 extern [ int ] f ( int );
    1337 static [ int ] g ( int );
     1237extern [ int ] f (int);
     1238static [ int ] g (int);
    13381239\end{cfa}
    13391240
     
    13431244The syntax for pointers to \CFA routines specifies the pointer name on the right, \eg:
    13441245\begin{cfa}
    1345 * [ int x ] () fp;                                              §\C{// pointer to routine returning int with no parameters}§
    1346 * [ * int ] (int y) gp;                                 §\C{// pointer to routine returning pointer to int with int parameter}§
    1347 * [ ] (int,char) hp;                                    §\C{// pointer to routine returning no result with int and char parameters}§
    1348 * [ * int,int ] ( int ) jp;                             §\C{// pointer to routine returning pointer to int and int, with int parameter}§
     1246* [ int x ] () fp;                      §\C{// pointer to routine returning int with no parameters}§
     1247* [ * int ] (int y) gp;         §\C{// pointer to routine returning pointer to int with int parameter}§
     1248* [ ] (int,char) hp;            §\C{// pointer to routine returning no result with int and char parameters}§
     1249* [ * int,int ] (int) jp;       §\C{// pointer to routine returning pointer to int and int, with int parameter}§
    13491250\end{cfa}
    13501251While parameter names are optional, \emph{a routine name cannot be specified};
    13511252for example, the following is incorrect:
    13521253\begin{cfa}
    1353 * [ int x ] f () fp;                                    §\C{// routine name "f" is not allowed}§
     1254* [ int x ] f () fp;            §\C{// routine name "f" is not allowed}§
    13541255\end{cfa}
    13551256
     
    13571258\section{Named and Default Arguments}
    13581259
    1359 Named\index{named arguments}\index{arguments!named} and default\index{default arguments}\index{arguments!default} arguments~\cite{Hardgrave76}\footnote{
     1260Named and default arguments~\cite{Hardgrave76}\footnote{
    13601261Francez~\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.}
    13611262are two mechanisms to simplify routine call.
     
    15381439        int ;                                   §\C{// disallowed, unnamed field}§
    15391440        int *;                                  §\C{// disallowed, unnamed field}§
    1540         int (*)( int );                 §\C{// disallowed, unnamed field}§
     1441        int (*)(int);                   §\C{// disallowed, unnamed field}§
    15411442};
    15421443\end{cfa}
     
    16611562}
    16621563int main() {
    1663         * [int]( int ) fp = foo();      §\C{// int (*fp)( int )}§
     1564        * [int](int) fp = foo();        §\C{// int (*fp)(int)}§
    16641565        sout | fp( 3 ) | endl;
    16651566}
     
    27822683
    27832684
    2784 \section{Constructors and Destructors}
     2685\subsection{Constructors and Destructors}
    27852686
    27862687\CFA supports C initialization of structures, but it also adds constructors for more advanced initialization.
     
    31133014
    31143015
    3115 \begin{comment}
    31163016\section{Generics}
    31173017
     
    33203220        }
    33213221\end{cfa}
    3322 \end{comment}
    33233222
    33243223
     
    33803279        Complex *p3 = new(0.5, 1.0); // allocate + 2 param constructor
    33813280}
     3281
    33823282\end{cfa}
    33833283
     
    33913291
    33923292
    3393 \begin{comment}
    33943293\subsection{Unsafe C Constructs}
    33953294
     
    34023301The exact set of unsafe C constructs that will be disallowed in \CFA has not yet been decided, but is sure to include pointer arithmetic, pointer casting, etc.
    34033302Once the full set is decided, the rules will be listed here.
    3404 \end{comment}
    34053303
    34063304
    34073305\section{Concurrency}
     3306
     3307Today's processors for nearly all use cases, ranging from embedded systems to large cloud computing servers, are composed of multiple cores, often heterogeneous.
     3308As machines grow in complexity, it becomes more difficult for a program to make the most use of the hardware available.
     3309\CFA includes built-in concurrency features to enable high performance and improve programmer productivity on these multi-/many-core machines.
    34083310
    34093311Concurrency support in \CFA is implemented on top of a highly efficient runtime system of light-weight, M:N, user level threads.
     
    34123314This enables a very familiar interface to all programmers, even those with no parallel programming experience.
    34133315It also allows the compiler to do static type checking of all communication, a very important safety feature.
    3414 This controlled communication with type safety has some similarities with channels in \Index*{Go}, and can actually implement channels exactly, as well as create additional communication patterns that channels cannot.
     3316This controlled communication with type safety has some similarities with channels in \Index*{Go}, and can actually implement
     3317channels exactly, as well as create additional communication patterns that channels cannot.
    34153318Mutex objects, monitors, are used to contain mutual exclusion within an object and synchronization across concurrent threads.
    34163319
    3417 \begin{figure}
    3418 \begin{cfa}
    3419 #include <fstream>
    3420 #include <coroutine>
    3421 
    3422 coroutine Fibonacci {
    3423         int fn;                                                         §\C{// used for communication}§
    3424 };
    3425 void ?{}( Fibonacci * this ) {
    3426         this->fn = 0;
    3427 }
    3428 void main( Fibonacci * this ) {
    3429         int fn1, fn2;                                           §\C{// retained between resumes}§
    3430         this->fn = 0;                                           §\C{// case 0}§
    3431         fn1 = this->fn;
    3432         suspend();                                                      §\C{// return to last resume}§
    3433 
    3434         this->fn = 1;                                           §\C{// case 1}§
    3435         fn2 = fn1;
    3436         fn1 = this->fn;
    3437         suspend();                                                      §\C{// return to last resume}§
    3438 
    3439         for ( ;; ) {                                            §\C{// general case}§
    3440                 this->fn = fn1 + fn2;
    3441                 fn2 = fn1;
    3442                 fn1 = this->fn;
    3443                 suspend();                                              §\C{// return to last resume}§
    3444         } // for
    3445 }
    3446 int next( Fibonacci * this ) {
    3447         resume( this );                                         §\C{// transfer to last suspend}§
    3448         return this->fn;
    3449 }
    3450 int main() {
    3451         Fibonacci f1, f2;
    3452         for ( int i = 1; i <= 10; i += 1 ) {
    3453                 sout | next( &f1 ) | ' ' | next( &f2 ) | endl;
    3454         } // for
    3455 }
    3456 \end{cfa}
    3457 \caption{Fibonacci Coroutine}
    3458 \label{f:FibonacciCoroutine}
    3459 \end{figure}
    3460 
    3461 
    3462 \subsection{Coroutine}
    3463 
    3464 \Index{Coroutines} are the precursor to tasks.
    3465 \VRef[Figure]{f:FibonacciCoroutine} shows a coroutine that computes the \Index*{Fibonacci} numbers.
     3320Three new keywords are added to support these features:
     3321
     3322monitor creates a structure with implicit locking when accessing fields
     3323
     3324mutex implies use of a monitor requiring the implicit locking
     3325
     3326task creates a type with implicit locking, separate stack, and a thread
    34663327
    34673328
     
    34783339\end{cfa}
    34793340
    3480 \begin{figure}
    3481 \begin{cfa}
    3482 #include <fstream>
    3483 #include <kernel>
    3484 #include <monitor>
    3485 #include <thread>
    3486 
    3487 monitor global_t {
    3488         int value;
    3489 };
    3490 
    3491 void ?{}(global_t * this) {
    3492         this->value = 0;
    3493 }
    3494 
    3495 static global_t global;
    3496 
    3497 void increment3( global_t * mutex this ) {
    3498         this->value += 1;
    3499 }
    3500 void increment2( global_t * mutex this ) {
    3501         increment3( this );
    3502 }
    3503 void increment( global_t * mutex this ) {
    3504         increment2( this );
    3505 }
    3506 
    3507 thread MyThread {};
    3508 
    3509 void main( MyThread* this ) {
    3510         for(int i = 0; i < 1_000_000; i++) {
    3511                 increment( &global );
    3512         }
    3513 }
    3514 int main(int argc, char* argv[]) {
    3515         processor p;
    3516         {
    3517                 MyThread f[4];
    3518         }
    3519         sout | global.value | endl;
    3520 }
    3521 \end{cfa}
    3522 \caption{Atomic-Counter Monitor}
    3523 \caption{f:AtomicCounterMonitor}
    3524 \end{figure}
    3525 
    3526 \begin{comment}
    35273341Since a monitor structure includes an implicit locking mechanism, it does not make sense to copy a monitor;
    35283342it is always passed by reference.
     
    35713385}
    35723386\end{cfa}
    3573 \end{comment}
    35743387
    35753388
     
    35793392A task provides mutual exclusion like a monitor, and also has its own execution state and a thread of control.
    35803393Similar to a monitor, a task is defined like a structure:
    3581 
    3582 \begin{figure}
    3583 \begin{cfa}
    3584 #include <fstream>
    3585 #include <kernel>
    3586 #include <stdlib>
    3587 #include <thread>
    3588 
    3589 thread First  { signal_once * lock; };
    3590 thread Second { signal_once * lock; };
    3591 
    3592 void ?{}( First * this, signal_once* lock ) { this->lock = lock; }
    3593 void ?{}( Second * this, signal_once* lock ) { this->lock = lock; }
    3594 
    3595 void main( First * this ) {
    3596         for ( int i = 0; i < 10; i += 1 ) {
    3597                 sout | "First : Suspend No." | i + 1 | endl;
    3598                 yield();
    3599         }
    3600         signal( this->lock );
    3601 }
    3602 
    3603 void main( Second * this ) {
    3604         wait( this->lock );
    3605         for ( int i = 0; i < 10; i += 1 ) {
    3606                 sout | "Second : Suspend No." | i + 1 | endl;
    3607                 yield();
    3608         }
    3609 }
    3610 
    3611 int main( void ) {
    3612         signal_once lock;
    3613         sout | "User main begin" | endl;
    3614         {
    3615                 processor p;
    3616                 {
    3617                         First  f = { &lock };
    3618                         Second s = { &lock };
    3619                 }
    3620         }
    3621         sout | "User main end" | endl;
    3622 }
    3623 \end{cfa}
    3624 \caption{Simple Tasks}
    3625 \label{f:SimpleTasks}
    3626 \end{figure}
    3627 
    3628 
    3629 \begin{comment}
    36303394\begin{cfa}
    36313395type Adder = task {
     
    36813445\end{cfa}
    36823446
     3447
    36833448\subsection{Cooperative Scheduling}
    36843449
     
    37933558}
    37943559\end{cfa}
    3795 \end{comment}
    3796 
     3560
     3561
     3562\section{Modules and Packages }
    37973563
    37983564\begin{comment}
    3799 \section{Modules and Packages }
    3800 
    38013565High-level encapsulation is useful for organizing code into reusable units, and accelerating compilation speed.
    38023566\CFA provides a convenient mechanism for creating, building and sharing groups of functionality that enhances productivity and improves compile time.
     
    44624226
    44634227
    4464 \begin{comment}
    44654228\subsection[Comparing Key Features of CFA]{Comparing Key Features of \CFA}
    44664229
     
    48404603
    48414604
     4605\begin{comment}
    48424606\subsubsection{Modules / Packages}
    48434607
     
    49194683}
    49204684\end{cfa}
     4685\end{comment}
    49214686
    49224687
     
    50794844
    50804845\subsection{Summary of Language Comparison}
    5081 \end{comment}
    5082 
    5083 
    5084 \subsection[C++]{\CC}
     4846
     4847
     4848\subsubsection[C++]{\CC}
    50854849
    50864850\Index*[C++]{\CC{}} is a general-purpose programming language.
     
    51034867
    51044868
    5105 \subsection{Go}
     4869\subsubsection{Go}
    51064870
    51074871\Index*{Go}, also commonly referred to as golang, is a programming language developed at Google in 2007 [.].
     
    51194883
    51204884
    5121 \subsection{Rust}
     4885\subsubsection{Rust}
    51224886
    51234887\Index*{Rust} is a general-purpose, multi-paradigm, compiled programming language developed by Mozilla Research.
     
    51334897
    51344898
    5135 \subsection{D}
     4899\subsubsection{D}
    51364900
    51374901The \Index*{D} programming language is an object-oriented, imperative, multi-paradigm system programming
     
    52455009\item[Rationale:] keywords added to implement new semantics of \CFA.
    52465010\item[Effect on original feature:] change to semantics of well-defined feature. \\
    5247 Any \Celeven programs using these keywords as identifiers are invalid \CFA programs.
     5011Any ISO C programs using these keywords as identifiers are invalid \CFA programs.
    52485012\item[Difficulty of converting:] keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism (see~\VRef{s:BackquoteIdentifiers}).
    52495013\item[How widely used:] clashes among new \CFA keywords and existing identifiers are rare.
     
    54655229hence, names in these include files are not mangled\index{mangling!name} (see~\VRef{s:Interoperability}).
    54665230All other C header files must be explicitly wrapped in ©extern "C"© to prevent name mangling.
    5467 For \Index*[C++]{\CC{}}, the name-mangling issue is handled implicitly because most C header-files are augmented with checks for preprocessor variable ©__cplusplus©, which adds appropriate ©extern "C"© qualifiers.
    54685231
    54695232
     
    55485311}
    55495312
    5550 // §\CFA§ safe initialization/copy, i.e., implicit size specification
     5313// §\CFA§ safe initialization/copy
    55515314forall( dtype T | sized(T) ) T * memset( T * dest, char c );§\indexc{memset}§
    55525315forall( dtype T | sized(T) ) T * memcpy( T * dest, const T * src );§\indexc{memcpy}§
     
    56585421\leavevmode
    56595422\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    5660 forall( otype T | { int ?<?( T, T ); } ) T min( T t1, T t2 );§\indexc{min}§
    5661 forall( otype T | { int ?>?( T, T ); } ) T max( T t1, T t2 );§\indexc{max}§
    5662 forall( otype T | { T min( T, T ); T max( T, T ); } ) T clamp( T value, T min_val, T max_val );§\indexc{clamp}§
    5663 forall( otype T ) void swap( T * t1, T * t2 );§\indexc{swap}§
     5423forall( otype T | { int ?<?( T, T ); } )
     5424T min( T t1, T t2 );§\indexc{min}§
     5425
     5426forall( otype T | { int ?>?( T, T ); } )
     5427T max( T t1, T t2 );§\indexc{max}§
     5428
     5429forall( otype T | { T min( T, T ); T max( T, T ); } )
     5430T clamp( T value, T min_val, T max_val );§\indexc{clamp}§
     5431
     5432forall( otype T )
     5433void swap( T * t1, T * t2 );§\indexc{swap}§
    56645434\end{cfa}
    56655435
  • doc/working/exception/design.txt

    r436c0de rade20d0  
    11Design of Exceptions and EHM in Cforall:
    22
    3 
    4 Exception Instances:
    5 Currently, exceptions are integers (like errno).
    6 
    7 They are planned to be the new "tagged structures", which allows them to
    8 exist in a simple hierarchy which shared functionality throughout. However
    9 the tagged structures are not yet implemented so that will wait.
    10 
    11 A single built in exception is at the top of the hierarchy and all other
    12 exceptions are its children. When you match against an exception, you match
    13 for an exception and its children, so the top of the hierarchy is used as a
    14 catch-all option.
    15 
    16 The shared functionality across exceptions has not been finalized, but will
    17 probably include things like human readable descriptions and default handlers.
     3Currently this is a combination of ideas and big questions that still have to
     4be addressed. It also includes some other error handling options, how they
     5interact and compare to exceptions.
    186
    197
    20 Throwing:
    21 There are currently two kinds of throws, "throw" for termination and
    22 "throwResume" for resumption. Both keywords can be used to create a throw
    23 statement. The kind of throw decides what handlers may catch the exception
    24 and weither control flow can return to the throw site.
     8What is an Exception:
    259
    26 Syntax
    27 "throw" exception ";"
    28 "throwResume" exception ";"
     10In other words what do we throw? What is matched against, how does it carry
     11data with it? A very important question that has not been answered.
    2912
    30 Non-local throws are allowed for resumption only. A target is an object with
    31 a stack, with which it may propagate and handle the exception.
     13Option 1: Strutures
    3214
    33 Syntax
    34 "throwResume" exception "_At" target ";"
     15Considering the current state of Cforall the most natural form of the
     16exception would likely be a struture, implementing a trait repersenting the
     17minimum features of an exception. This has many advantages, including arbitray
     18fields, some polymorphism and it matches exceptations of many current systems.
    3519
    36 Termination throws unwind the stack until a handler is reached, control moves
    37 onwards from the end of the handler. Resumption throws do not unwind, if a
    38 handler is found and control will return to the throw after the exception is
    39 handled.
     20The main issue with this is matching, without OOP inheritance there is no
     21exception hierarchy. Meaning all handling has to happen on the exact exception
     22without the ease of grouping parents. There are several ways to attempt to
     23recover this.
     24
     25The first is with conditional matching (a check after the type has been
     26matched) which allows for matching particular values of a known type. However
     27this does not dynamically expand and requires an extra step (as opposed to
     28mearly allowing one). I would not recomend this as the primary method.
     29
     30Second is to try and use type casts/conversions to create an implicate
     31hierachy, so that a catch clause catches anything of the given type or
     32anything that converts to the given type.
     33
     34Plan9 (from what I know of it) would be a powerful tool here. Even with it,
     35creating a hierarchy of types at runtime might be too expencive. Esecially
     36since they are less likely to be tree like at that point.
     37
     38Option 2: Tags
     39
     40The other option is to introduce a new construct into the language. A tag
     41repersents a type of exception, it is not a structure or variable (or even
     42a normal type). It may be usable in some of those contexts.
     43
     44Tags can declare an existing tag as its parent. Tags can be caught by handlers
     45that catch their parents. (There is a single base_exception that all other
     46exceptions are children of eventually.) This allows for grouping of exceptions
     47that repersent similar errors.
     48
     49Tags should also have some assotiated data, where and on what did the error
     50occur. Keeping with the otherness of exception tags and allowing them to be
     51expanded, using a parameter list. Each exception can have a list of paramters
     52given to it on a throw. Each tag would have a declared list of parameters
     53(which could be treated more like a set of fields as well). Child tags must
     54use their parent's list as a prefix to their own, so that the parameters can
     55be accessed when the child tag is matched against the parent.
     56
     57Option N: ...
     58
     59This list is not complete.
    4060
    4161
    42 Catching:
    43 The catch and handle of an exception is preformed with a try statement, which
    44 also can have finally clauses to exceute on exit from the scope.
     62Seperating Termination and Resumption:
    4563
    46 Syntax
    47 "try"
    48         try-block
    49 ( ("catch" | "catchResume")
    50   "(" exception_type [identifier] [";" conditional_expression] ")"
    51         catch-block
    52 )*
    53 ("finally"
    54         finally-block
    55 )?
     64Differentating the types of exceptions based on exception would be hard with
     65exceptions as structures. It is possible with exceptions as tags by having
     66two base exceptions, one for each type of throw. However recompining them
     67to dual types would be harder.
    5668
    57 Either at least 1 handler clause or the finally clasue must be given on each
    58 try block. Each handler clause handles 1 of the two types of throws. Each
    59 handler also specifies a type of exception it handles, and will handle all
    60 children exceptions as well. In addition, a conditional expression which, if
    61 included, must be true for the handler to catch the exception.
    62 
    63 The two types of handlers may be intermixed. Multiple handlers catching the
    64 same type may also be used, to allow for fallbacks on false conditionals.
     69Reguardless, using different keywords would also be useful for clarity, even
     70if it does not add functality. Using the C++ like keywords would be a good
     71base. Resumption exceptions could use a different set (ex. raise->handle) or
     72use resume as a qualifier on the existing statements.
    6573
    6674
    67 Implementation Overview:
     75Conditional Matching:
    6876
    69 The implementation has two main parts. The first is just a collection of the
    70 support definitions we need, the data types and functions used within the
    71 exception handling code. Second is a translation from Cforall code to C code
    72 that uses those definitions to throw, catch and handle exceptions.
     77A possible useful feature, it allows for arbitrary checks on a catch block
     78instead of merely matching a type. However there are few use cases that
     79cannot be avoided with proper use of a type hierarchy, and this shrinks even
     80further with a good use of re-throws.
    7381
    74 Termination handlers call a specially annotated function, passing it inner
    75 functions that act as the varius sub-blocks. Termination throws use the
    76 unwind library that checks the underlying code for those annotations. Each
    77 time one is found some magic is used to check for a matching handler, if one
    78 is found control goes to the special function which excecutes the handler and
    79 returns.
    80 
    81 Resumption handlers maintain a linked list of stack allocated nodes that have
    82 the handler functions attached. Throwing a resumption exception traverses this
    83 list, and calls each handler, the handlers handle the exception if they can
    84 and return if they did or not.
    85 
    86 Finally clauses just use stack cleanup to force a nested function, which has
    87 the code from the finally clause, to execute when we leave that section.
     82Also it assumes one sweep, that might also be a problem. But might also give
     83it an advantage over re-throws.
    8884
    8985
    90 Alternative Error Handling: Return Unions
     86Alternatives: Implicate Handlers & Return Unions
    9187
    92 Return unions (Maybe and Result), are types that can encode a success or
    93 other result in a single value. Maybe stores a value or nothing, Result stores
    94 a value or an error.
     88Both act as a kind of local version of an exception. Implicate handlers act as
     89resumption exceptions and return unions like termination exceptions. By local
     90I mean they work well at one or two levels of calls, but do not cover N levels
     91as cleanly.
    9592
    96 For errors that are usually handled quite close to where they occur, these
    97 can replace exceptions.
     93Implicate handles require a growing number of function pointers (which should
     94not be used very often) to be passed to functions, creating and additional
     95preformance cost. Return unions have to be checked and handled at every level,
     96which has some preformance cost, but also can significantly clutter code.
     97Proper tools can help with the latter.
    9898
    99 They tend to be faster and require similar or less amounts of code to handle.
    100 However they can slow down the normal path with some extra conditionals and
    101 can mix the normal and exceptional control flow path. If handling the error
    102 is simple, and happens relatively frequently, this might be prefered but in
    103 other cases it just hurts speed and readability.
     99However, they may work better at that local level as they do not require stack
     100walking or unwinding. In addition they are closer to regular control flow and
     101are easier to staticly check. So even if they can't replace exceptions
     102(directly) they may still be worth using together.
     103
     104For instance, consider the Python iterator interface. It uses a single
     105function, __next__, to access the next value and to signal the end of the
     106sequence. If a value is returned, it is the next value, if the StopIteration
     107exception is thrown the sequence has finished.
     108
     109However almost every use of an iterator will add a try-except block around the
     110call site (possibly through for or next) to catch and handle the exception
     111immediately, ignoring the advantages of more distant exception handling.
     112
     113In this case it may be cleaner to use a Maybe for both cases (as in Rust)
     114which gives similar results without having to jump to the exception handler.
     115This will likely handle the error case more efficiently and the success case a
     116bit less so.
     117
     118It also mixes the error and regular control flow, which can hurt readablity,
     119but very little if the handling is simple, for instance providing a default
     120value. Similarly, if the error (or alternate outcome) is common enough
     121encoding it in the function signature may be good commuication.
    104122
    105123In short, these errors seem to be more effective when errors are likely and
     
    107125be handled locally, might be better off using these instead of exceptions.
    108126
    109 Also the return unions could use exceptions as well. Getting the improper
    110 side of a return union might throw an exception. Or we can provide helpers
    111 for results withe exceptions as in:
     127Also the implicate handlers and return unions could use exceptions as well.
     128For instance, a useful default might handler might be to throw an exception,
     129seaching up the stack for a solution if one is not locally provided.
     130
     131Or here is a possible helper for unpacking a Result value:
    112132                forall(otype T, otype E | exception(E))
    113133                T get_or_throw (Result(T, E) * this) {
    114                         if (has_value(this)) {
    115                                 return get_value(this);
     134                        if (is_success(this)) {
     135                                return get_success(this);
    116136                        } else {
    117                                 throw get_error(this);
     137                                throw get_failure(this);
    118138                        }
    119139                }
     140So they can feed off of each other.
  • src/CodeGen/CodeGenerator.cc

    r436c0de rade20d0  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Jun  8 16:00:00 2017
    13 // Update Count     : 485
     12// Last Modified On : Wed May 10 14:45:00 2017
     13// Update Count     : 484
    1414//
    1515
     
    112112
    113113        CodeGenerator::CodeGenerator( std::ostream & os, bool pretty, bool genC, bool lineMarks ) : indent( *this), cur_indent( 0 ), insideFunction( false ), output( os ), printLabels( *this ), pretty( pretty ), genC( genC ), lineMarks( lineMarks ) {}
     114
     115        CodeGenerator::CodeGenerator( std::ostream & os, std::string init, int indentation, bool infunp )
     116                        : indent( *this), cur_indent( indentation ), insideFunction( infunp ), output( os ), printLabels( *this ) {
     117                //output << std::string( init );
     118        }
     119
     120        CodeGenerator::CodeGenerator( std::ostream & os, char * init, int indentation, bool infunp )
     121                        : indent( *this ), cur_indent( indentation ), insideFunction( infunp ), output( os ), printLabels( *this ) {
     122                //output << std::string( init );
     123        }
    114124
    115125        string CodeGenerator::mangleName( DeclarationWithType * decl ) {
     
    908918        }
    909919
    910         void CodeGenerator::visit( ThrowStmt * throwStmt ) {
    911                 assertf( ! genC, "Throw statements should not reach code generation." );
    912 
    913                 output << ((throwStmt->get_kind() == ThrowStmt::Terminate) ?
    914                            "throw" : "throwResume");
    915                 if (throwStmt->get_expr()) {
    916                         output << " ";
    917                         throwStmt->get_expr()->accept( *this );
    918                 }
    919                 if (throwStmt->get_target()) {
    920                         output << " _At ";
    921                         throwStmt->get_target()->accept( *this );
    922                 }
    923                 output << ";";
    924         }
    925 
    926920        void CodeGenerator::visit( WhileStmt * whileStmt ) {
    927921                if ( whileStmt->get_isDoWhile() ) {
  • src/CodeGen/CodeGenerator.h

    r436c0de rade20d0  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Jun  8 15:48:00 2017
    13 // Update Count     : 52
     12// Last Modified On : Wed May 10 10:57:00 2017
     13// Update Count     : 51
    1414//
    1515
     
    9191                virtual void visit( BranchStmt * );
    9292                virtual void visit( ReturnStmt * );
    93                 virtual void visit( ThrowStmt * );
    9493                virtual void visit( WhileStmt * );
    9594                virtual void visit( ForStmt * );
  • src/Common/PassVisitor.h

    r436c0de rade20d0  
    5454        virtual void visit( BranchStmt *branchStmt ) override final;
    5555        virtual void visit( ReturnStmt *returnStmt ) override final;
    56         virtual void visit( ThrowStmt *throwStmt ) override final;
    5756        virtual void visit( TryStmt *tryStmt ) override final;
    5857        virtual void visit( CatchStmt *catchStmt ) override final;
     
    9190        virtual void visit( TupleExpr *tupleExpr ) override final;
    9291        virtual void visit( TupleIndexExpr *tupleExpr ) override final;
     92        virtual void visit( MemberTupleExpr *tupleExpr ) override final;
    9393        virtual void visit( TupleAssignExpr *assignExpr ) override final;
    9494        virtual void visit( StmtExpr * stmtExpr ) override final;
     
    140140        virtual Statement* mutate( BranchStmt *branchStmt ) override final;
    141141        virtual Statement* mutate( ReturnStmt *returnStmt ) override final;
    142         virtual Statement* mutate( ThrowStmt *throwStmt ) override final;
    143142        virtual Statement* mutate( TryStmt *returnStmt ) override final;
    144143        virtual Statement* mutate( CatchStmt *catchStmt ) override final;
     
    177176        virtual Expression* mutate( TupleExpr *tupleExpr ) override final;
    178177        virtual Expression* mutate( TupleIndexExpr *tupleExpr ) override final;
     178        virtual Expression* mutate( MemberTupleExpr *tupleExpr ) override final;
    179179        virtual Expression* mutate( TupleAssignExpr *assignExpr ) override final;
    180180        virtual Expression* mutate( StmtExpr * stmtExpr ) override final;
     
    232232        std::list< Statement* > *       get_afterStmts () { return stmtsToAddAfter_impl ( pass, 0); }
    233233        bool visit_children() { bool* skip = skip_children_impl(pass, 0); return ! (skip && *skip); }
    234         void reset_visit() { bool* skip = skip_children_impl(pass, 0); if(skip) *skip = false; }
    235 
    236         guard_value_impl init_guard() {
    237                 guard_value_impl guard;
    238                 auto at_cleanup = at_cleanup_impl(pass, 0);
    239                 if( at_cleanup ) {
    240                         *at_cleanup = [&guard]( cleanup_func_t && func, void* val ) {
    241                                 guard.push( std::move( func ), val );
    242                         };
    243                 }
    244                 return guard;
    245         }
    246234};
    247235
    248 template<typename pass_type, typename T>
    249 void GuardValue( pass_type * pass, T& val ) {
    250         pass->at_cleanup( [ val ]( void * newVal ) {
    251                 * static_cast< T * >( newVal ) = val;
    252         }, static_cast< void * >( & val ) );
    253 }
    254 
    255 class WithTypeSubstitution {
    256 protected:
    257         WithTypeSubstitution() = default;
    258         ~WithTypeSubstitution() = default;
    259 
    260 public:
    261         TypeSubstitution * env;
    262 };
    263 
    264 class WithStmtsToAdd {
    265 protected:
    266         WithStmtsToAdd() = default;
    267         ~WithStmtsToAdd() = default;
    268 
    269 public:
    270         std::list< Statement* > stmtsToAddBefore;
    271         std::list< Statement* > stmtsToAddAfter;
    272 };
    273 
    274 class WithShortCircuiting {
    275 protected:
    276         WithShortCircuiting() = default;
    277         ~WithShortCircuiting() = default;
    278 
    279 public:
    280         bool skip_children;
    281 };
    282 
    283 class WithScopes {
    284 protected:
    285         WithScopes() = default;
    286         ~WithScopes() = default;
    287 
    288 public:
    289         at_cleanup_t at_cleanup;
    290 
    291         template< typename T >
    292         void GuardValue( T& val ) {
    293                 at_cleanup( [ val ]( void * newVal ) {
    294                         * static_cast< T * >( newVal ) = val;
    295                 }, static_cast< void * >( & val ) );
    296         }
    297 };
    298 
    299 
    300236#include "PassVisitor.impl.h"
  • src/Common/PassVisitor.impl.h

    r436c0de rade20d0  
    11#pragma once
    22
    3 #define VISIT_START( node )                     \
    4         __attribute__((unused))                   \
    5         const auto & guard = init_guard();        \
    6         call_previsit( node );                    \
    7         if( visit_children() ) {                  \
    8                 reset_visit();                      \
    9 
    10 #define VISIT_END( node )                       \
    11         }                                         \
    12         call_postvisit( node );                   \
    13 
    14 #define MUTATE_START( node )                    \
    15         __attribute__((unused))                   \
    16         const auto & guard = init_guard();        \
    17         call_premutate( node );                   \
    18         if( visit_children() ) {                  \
    19                 reset_visit();                      \
     3#define VISIT_START( node )  \
     4        call_previsit( node ); \
     5        if( visit_children() ) { \
     6
     7#define VISIT_END( node )            \
     8        }                              \
     9        return call_postvisit( node ); \
     10
     11#define MUTATE_START( node )  \
     12        call_premutate( node ); \
     13        if( visit_children() ) { \
    2014
    2115#define MUTATE_END( type, node )                \
     
    2418
    2519
    26 #define VISIT_BODY( node )        \
    27         VISIT_START( node );        \
    28         Visitor::visit( node );     \
    29         VISIT_END( node );          \
     20#define VISIT_BODY( node )    \
     21        VISIT_START( node );  \
     22        Visitor::visit( node ); \
     23        VISIT_END( node ); \
    3024
    3125
     
    395389
    396390//--------------------------------------------------------------------------
    397 // ThrowStmt
    398 
    399 template< typename pass_type >
    400 void PassVisitor< pass_type >::visit( ThrowStmt * node ) {
    401         VISIT_BODY( node );
    402 }
    403 
    404 template< typename pass_type >
    405 Statement * PassVisitor< pass_type >::mutate( ThrowStmt * node ) {
    406         MUTATE_BODY( Statement, node );
    407 }
    408 
    409 //--------------------------------------------------------------------------
    410391// TryStmt
    411392template< typename pass_type >
     
    636617
    637618template< typename pass_type >
     619void PassVisitor< pass_type >::visit( MemberTupleExpr * node ) {
     620        VISIT_BODY( node );
     621}
     622
     623template< typename pass_type >
    638624void PassVisitor< pass_type >::visit( TupleAssignExpr * node ) {
    639625        VISIT_BODY( node );
     
    1013999
    10141000template< typename pass_type >
     1001Expression * PassVisitor< pass_type >::mutate( MemberTupleExpr * node ) {
     1002        MUTATE_BODY( Expression, node );
     1003}
     1004
     1005template< typename pass_type >
    10151006Expression * PassVisitor< pass_type >::mutate( TupleAssignExpr * node ) {
    10161007        MUTATE_BODY( Expression, node );
  • src/Common/PassVisitor.proto.h

    r436c0de rade20d0  
    11#pragma once
    2 
    3 typedef std::function<void( void * )> cleanup_func_t;
    4 
    5 class guard_value_impl {
    6 public:
    7         guard_value_impl() = default;
    8 
    9         ~guard_value_impl() {
    10                 while( !cleanups.empty() ) {
    11                         auto& cleanup = cleanups.top();
    12                         cleanup.func( cleanup.val );
    13                         cleanups.pop();
    14                 }
    15         }
    16 
    17         void push( cleanup_func_t && func, void* val ) {
    18                 cleanups.emplace( std::move(func), val );
    19         }
    20 
    21 private:
    22         struct cleanup_t {
    23                 cleanup_func_t func;
    24                 void * val;
    25 
    26                 cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {}
    27         };
    28 
    29         std::stack< cleanup_t > cleanups;
    30 };
    31 
    32 typedef std::function< void( cleanup_func_t, void * ) > at_cleanup_t;
    332
    343//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     
    4918// Visit
    5019template<typename pass_type, typename node_type>
    51 static inline auto previsit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.previsit( node ), void() ) {
     20static inline auto previsit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) ->decltype( pass.previsit( node ), void() ) {
    5221        pass.previsit( node );
    5322}
     
    5827
    5928template<typename pass_type, typename node_type>
    60 static inline auto postvisit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.postvisit( node ), void() ) {
     29static inline auto postvisit_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) ->decltype( pass.postvisit( node ), void() ) {
    6130        pass.postvisit( node );
    6231}
     
    6736// Mutate
    6837template<typename pass_type, typename node_type>
    69 static inline auto premutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.premutate( node ), void() ) {
     38static inline auto premutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) ->decltype( pass.premutate( node ), void() ) {
    7039        return pass.premutate( node );
    7140}
     
    7645
    7746template<typename return_type, typename pass_type, typename node_type>
    78 static inline auto postmutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) -> decltype( pass.postmutate( node ) ) {
     47static inline auto postmutate_impl( pass_type& pass, node_type * node, __attribute__((unused)) int unused ) ->decltype( pass.postmutate( node ) ) {
    7948        return pass.postmutate( node );
    8049}
     
    8554// Begin/End scope
    8655template<typename pass_type>
    87 static inline auto begin_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( pass.beginScope(), void() ) {
     56static inline auto begin_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) ->decltype( pass.beginScope(), void() ) {
    8857        pass.beginScope();
    8958}
     
    9463
    9564template<typename pass_type>
    96 static inline auto end_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( pass.endScope(), void() ) {
     65static inline auto end_scope_impl( pass_type& pass, __attribute__((unused)) int unused ) ->decltype( pass.endScope(), void() ) {
    9766        pass.endScope();
    9867}
     
    10473#define FIELD_PTR( type, name )                                                                                                        \
    10574template<typename pass_type>                                                                                                           \
    106 static inline auto name##_impl( pass_type& pass, __attribute__((unused)) int unused ) -> decltype( &pass.name ) { return &pass.name; } \
     75static inline auto name##_impl( pass_type& pass, __attribute__((unused)) int unused ) ->decltype( &pass.name ) { return &pass.name; } \
    10776                                                                                                                                       \
    10877template<typename pass_type>                                                                                                           \
     
    11382FIELD_PTR( std::list< Statement* >, stmtsToAddAfter  )
    11483FIELD_PTR( bool, skip_children )
    115 FIELD_PTR( at_cleanup_t, at_cleanup )
  • src/GenPoly/Box.cc

    r436c0de rade20d0  
    108108                        Type *replaceWithConcrete( ApplicationExpr *appExpr, Type *type, bool doClone = true );
    109109                        /// wraps a function application returning a polymorphic type with a new temporary for the out-parameter return value
    110                         Expression *addDynRetParam( ApplicationExpr *appExpr, Type *polyType, std::list< Expression *>::iterator &arg );
     110                        Expression *addDynRetParam( ApplicationExpr *appExpr, FunctionType *function, Type *polyType, std::list< Expression *>::iterator &arg );
    111111                        Expression *applyAdapter( ApplicationExpr *appExpr, FunctionType *function, std::list< Expression *>::iterator &arg, const TyVarMap &exprTyVars );
    112112                        void boxParam( Type *formal, Expression *&arg, const TyVarMap &exprTyVars );
     
    726726                }
    727727
    728                 Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, Type *dynType, std::list< Expression *>::iterator &arg ) {
     728                Expression *Pass1::addDynRetParam( ApplicationExpr *appExpr, FunctionType *function, Type *dynType, std::list< Expression *>::iterator &arg ) {
    729729                        assert( env );
    730730                        Type *concrete = replaceWithConcrete( appExpr, dynType );
     
    11461146                        if ( dynRetType ) {
    11471147                                Type *concRetType = appExpr->get_result()->isVoid() ? nullptr : appExpr->get_result();
    1148                                 ret = addDynRetParam( appExpr, concRetType, arg ); // xxx - used to use dynRetType instead of concRetType
     1148                                ret = addDynRetParam( appExpr, function, concRetType, arg ); // xxx - used to use dynRetType instead of concRetType
    11491149                        } else if ( needsAdapter( function, scopeTyVars ) && ! needsAdapter( function, exprTyVars) ) { // xxx - exprTyVars is used above...?
    11501150                                // xxx - the ! needsAdapter check may be incorrect. It seems there is some situation where an adapter is applied where it shouldn't be, and this fixes it for some cases. More investigation is needed.
  • src/GenPoly/Specialize.cc

    r436c0de rade20d0  
    9393        }
    9494
    95         bool needsTupleSpecialization( Type *formalType, Type *actualType ) {
     95        bool needsTupleSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    9696                // Needs tuple specialization if the structure of the formal type and actual type do not match.
    9797                // This is the case if the formal type has ttype polymorphism, or if the structure  of tuple types
     
    112112
    113113        bool needsSpecialization( Type *formalType, Type *actualType, TypeSubstitution *env ) {
    114                 return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType );
     114                return needsPolySpecialization( formalType, actualType, env ) || needsTupleSpecialization( formalType, actualType, env );
    115115        }
    116116
  • src/InitTweak/FixInit.cc

    r436c0de rade20d0  
    902902                }
    903903
    904                 void InsertDtors::visit( __attribute((unused)) ReturnStmt * returnStmt ) {
     904                void InsertDtors::visit( ReturnStmt * returnStmt ) {
    905905                        // return exits all scopes, so dump destructors for all scopes
    906906                        for ( OrderedDecls & od : reverseDeclOrder ) {
  • src/InitTweak/GenInit.cc

    r436c0de rade20d0  
    3939
    4040namespace InitTweak {
    41         namespace {
    42                 const std::list<Label> noLabels;
    43                 const std::list<Expression *> noDesignators;
    44         }
    45 
    46         class ReturnFixer : public WithStmtsToAdd, public WithScopes {
     41        class ReturnFixer final : public GenPoly::PolyMutator {
    4742          public:
    4843                /// consistently allocates a temporary variable for the return value
     
    5146                static void makeReturnTemp( std::list< Declaration * > &translationUnit );
    5247
    53                 void premutate( FunctionDecl *functionDecl );
    54                 void premutate( ReturnStmt * returnStmt );
     48                typedef GenPoly::PolyMutator Parent;
     49                using Parent::mutate;
     50                virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ) override;
     51                virtual Statement * mutate( ReturnStmt * returnStmt ) override;
    5552
    5653          protected:
     
    134131
    135132        void ReturnFixer::makeReturnTemp( std::list< Declaration * > & translationUnit ) {
    136                 PassVisitor<ReturnFixer> fixer;
     133                ReturnFixer fixer;
    137134                mutateAll( translationUnit, fixer );
    138135        }
    139136
    140         void ReturnFixer::premutate( ReturnStmt *returnStmt ) {
     137        Statement *ReturnFixer::mutate( ReturnStmt *returnStmt ) {
    141138                std::list< DeclarationWithType * > & returnVals = ftype->get_returnVals();
    142139                assert( returnVals.size() == 0 || returnVals.size() == 1 );
     
    149146                        construct->get_args().push_back( new AddressExpr( new VariableExpr( returnVals.front() ) ) );
    150147                        construct->get_args().push_back( returnStmt->get_expr() );
    151                         stmtsToAddBefore.push_back(new ExprStmt(noLabels, construct));
     148                        stmtsToAdd.push_back(new ExprStmt(noLabels, construct));
    152149
    153150                        // return the retVal object
    154151                        returnStmt->set_expr( new VariableExpr( returnVals.front() ) );
    155152                } // if
    156         }
    157 
    158         void ReturnFixer::premutate( FunctionDecl *functionDecl ) {
    159                 GuardValue( ftype );
    160                 GuardValue( funcName );
     153                return returnStmt;
     154        }
     155
     156        DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) {
     157                ValueGuard< FunctionType * > oldFtype( ftype );
     158                ValueGuard< std::string > oldFuncName( funcName );
    161159
    162160                ftype = functionDecl->get_functionType();
    163161                funcName = functionDecl->get_name();
     162                return Parent::mutate( functionDecl );
    164163        }
    165164
  • src/Parser/ExpressionNode.cc

    r436c0de rade20d0  
    223223} // build_field_name_REALDECIMALconstant
    224224
    225 NameExpr * build_varref( const string *name ) {
     225NameExpr * build_varref( const string *name, bool labelp ) {
    226226        NameExpr *expr = new NameExpr( *name, nullptr );
    227227        delete name;
  • src/Parser/ParseNode.h

    r436c0de rade20d0  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 13:28:16 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun 12 13:00:00 2017
    13 // Update Count     : 779
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Mar 17 15:42:18 2017
     13// Update Count     : 777
    1414//
    1515
     
    166166Expression * build_field_name_REALDECIMALconstant( const std::string & str );
    167167
    168 NameExpr * build_varref( const std::string * name );
     168NameExpr * build_varref( const std::string * name, bool labelp = false );
    169169Expression * build_typevalue( DeclarationNode * decl );
    170170
     
    393393Statement * build_return( ExpressionNode * ctl );
    394394Statement * build_throw( ExpressionNode * ctl );
    395 Statement * build_resume( ExpressionNode * ctl );
    396 Statement * build_resume_at( ExpressionNode * ctl , ExpressionNode * target );
    397395Statement * build_try( StatementNode * try_stmt, StatementNode * catch_stmt, StatementNode * finally_stmt );
    398 Statement * build_catch( CatchStmt::Kind kind, DeclarationNode *decl, ExpressionNode *cond, StatementNode *body );
     396Statement * build_catch( DeclarationNode * decl, StatementNode * stmt, bool catchAny = false );
    399397Statement * build_finally( StatementNode * stmt );
    400398Statement * build_compound( StatementNode * first );
  • src/Parser/StatementNode.cc

    r436c0de rade20d0  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 14:59:41 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun 12 13:03:00 2017
    13 // Update Count     : 329
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Feb  2 22:16:40 2017
     13// Update Count     : 327
    1414//
    1515
     
    152152        return new ReturnStmt( noLabels, exps.size() > 0 ? exps.back() : nullptr );
    153153}
    154 
    155154Statement *build_throw( ExpressionNode *ctl ) {
    156155        std::list< Expression * > exps;
    157156        buildMoveList( ctl, exps );
    158157        assertf( exps.size() < 2, "This means we are leaking memory");
    159         return new ThrowStmt( noLabels, ThrowStmt::Terminate, !exps.empty() ? exps.back() : nullptr );
    160 }
    161 
    162 Statement *build_resume( ExpressionNode *ctl ) {
    163         std::list< Expression * > exps;
    164         buildMoveList( ctl, exps );
    165         assertf( exps.size() < 2, "This means we are leaking memory");
    166         return new ThrowStmt( noLabels, ThrowStmt::Resume, !exps.empty() ? exps.back() : nullptr );
    167 }
    168 
    169 Statement *build_resume_at( ExpressionNode *ctl, ExpressionNode *target ) {
    170         std::list< Expression * > exps;
    171         buildMoveList( ctl, exps );
    172         assertf( exps.size() < 2, "This means we are leaking memory");
    173         return new ThrowStmt( noLabels, ThrowStmt::Resume, !exps.empty() ? exps.back() : nullptr );
     158        return new ReturnStmt( noLabels, !exps.empty() ? exps.back() : nullptr, true );
    174159}
    175160
     
    181166        return new TryStmt( noLabels, tryBlock, branches, finallyBlock );
    182167}
    183 Statement *build_catch( CatchStmt::Kind kind, DeclarationNode *decl, ExpressionNode *cond, StatementNode *body ) {
    184         std::list< Statement * > branches;
    185         buildMoveList< Statement, StatementNode >( body, branches );
    186         assert( branches.size() == 1 );
    187         return new CatchStmt( noLabels, kind, maybeMoveBuild< Declaration >(decl), maybeMoveBuild< Expression >(cond), branches.front() );
     168Statement *build_catch( DeclarationNode *decl, StatementNode *stmt, bool catchAny ) {
     169        std::list< Statement * > branches;
     170        buildMoveList< Statement, StatementNode >( stmt, branches );
     171        assert( branches.size() == 1 );
     172        return new CatchStmt( noLabels, maybeMoveBuild< Declaration >(decl), branches.front(), catchAny );
    188173}
    189174Statement *build_finally( StatementNode *stmt ) {
  • src/Parser/parser.yy

    r436c0de rade20d0  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Jun 12 12:59:00 2017
    13 // Update Count     : 2402
     12// Last Modified On : Thu May 25 15:21:59 2017
     13// Update Count     : 2398
    1414//
    1515
     
    193193%type<sn> case_value_list                               case_label                                      case_label_list
    194194%type<sn> switch_clause_list_opt                switch_clause_list                      choose_clause_list_opt          choose_clause_list
    195 %type<sn> /* handler_list */                    handler_clause                          finally_clause
     195%type<sn> handler_list                                  handler_clause                          finally_clause
    196196
    197197// declarations
     
    547547                { $$ = new ExpressionNode( build_attrtype( build_varref( $1 ), $3 ) ); }
    548548//      | ANDAND IDENTIFIER                                                                     // GCC, address of label
    549 //              { $$ = new ExpressionNode( new OperatorNode( OperKinds::LabelAddress ), new ExpressionNode( build_varref( $2 ) ); }
     549//              { $$ = new ExpressionNode( new OperatorNode( OperKinds::LabelAddress ), new ExpressionNode( build_varref( $2, true ) ); }
    550550        ;
    551551
     
    931931                { $$ = new StatementNode( build_throw( $2 ) ); }
    932932        | THROWRESUME assignment_expression_opt ';'                     // handles reresume
    933                 { $$ = new StatementNode( build_resume( $2 ) ); }
     933                { $$ = new StatementNode( build_throw( $2 ) ); }
    934934        | THROWRESUME assignment_expression_opt AT assignment_expression ';' // handles reresume
    935                 { $$ = new StatementNode( build_resume_at( $2, $4 ) ); }
     935                { $$ = new StatementNode( build_throw( $2 ) ); }
    936936        ;
    937937
    938938exception_statement:
    939         TRY compound_statement handler_clause
     939        TRY compound_statement handler_list
    940940                { $$ = new StatementNode( build_try( $2, $3, 0 ) ); }
    941941        | TRY compound_statement finally_clause
    942942                { $$ = new StatementNode( build_try( $2, 0, $3 ) ); }
    943         | TRY compound_statement handler_clause finally_clause
     943        | TRY compound_statement handler_list finally_clause
    944944                { $$ = new StatementNode( build_try( $2, $3, $4 ) ); }
    945945        ;
    946946
    947 //handler_list:
    948 //      handler_clause
    949 //              // ISO/IEC 9899:1999 Section 15.3(6 ) If present, a "..." handler shall be the last handler for its try block.
    950 //      | CATCH '(' ELLIPSIS ')' compound_statement
    951 //              { $$ = new StatementNode( build_catch( 0, $5, true ) ); }
    952 //      | handler_clause CATCH '(' ELLIPSIS ')' compound_statement
    953 //              { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); }
    954 //      | CATCHRESUME '(' ELLIPSIS ')' compound_statement
    955 //              { $$ = new StatementNode( build_catch( 0, $5, true ) ); }
    956 //      | handler_clause CATCHRESUME '(' ELLIPSIS ')' compound_statement
    957 //              { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); }
    958 //      ;
     947handler_list:
     948        handler_clause
     949                // ISO/IEC 9899:1999 Section 15.3(6 ) If present, a "..." handler shall be the last handler for its try block.
     950        | CATCH '(' ELLIPSIS ')' compound_statement
     951                { $$ = new StatementNode( build_catch( 0, $5, true ) ); }
     952        | handler_clause CATCH '(' ELLIPSIS ')' compound_statement
     953                { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); }
     954        | CATCHRESUME '(' ELLIPSIS ')' compound_statement
     955                { $$ = new StatementNode( build_catch( 0, $5, true ) ); }
     956        | handler_clause CATCHRESUME '(' ELLIPSIS ')' compound_statement
     957                { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( 0, $6, true ) ) ); }
     958        ;
    959959
    960960handler_clause:
    961961        CATCH '(' push push exception_declaration pop ')' compound_statement pop
    962                 { $$ = new StatementNode( build_catch( CatchStmt::Terminate, $5, nullptr, $8 ) ); }
     962                { $$ = new StatementNode( build_catch( $5, $8 ) ); }
    963963        | handler_clause CATCH '(' push push exception_declaration pop ')' compound_statement pop
    964                 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( CatchStmt::Terminate, $6, nullptr, $9 ) ) ); }
     964                { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $6, $9 ) ) ); }
    965965        | CATCHRESUME '(' push push exception_declaration pop ')' compound_statement pop
    966                 { $$ = new StatementNode( build_catch( CatchStmt::Resume, $5, nullptr, $8 ) ); }
     966                { $$ = new StatementNode( build_catch( $5, $8 ) ); }
    967967        | handler_clause CATCHRESUME '(' push push exception_declaration pop ')' compound_statement pop
    968                 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( CatchStmt::Resume, $6, nullptr, $9 ) ) ); }
     968                { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( $6, $9 ) ) ); }
    969969        ;
    970970
  • src/ResolvExpr/AlternativeFinder.cc

    r436c0de rade20d0  
    9797                /// Prunes a list of alternatives down to those that have the minimum conversion cost for a given return type; skips ambiguous interpretations
    9898                template< typename InputIterator, typename OutputIterator >
    99                 void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out ) {
     99                void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out, const SymTab::Indexer &indexer ) {
    100100                        // select the alternatives that have the minimum conversion cost for a particular set of result types
    101101                        std::map< std::string, PruneStruct > selected;
     
    183183                        )
    184184                        AltList::iterator oldBegin = alternatives.begin();
    185                         pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ) );
     185                        pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ), indexer );
    186186                        if ( alternatives.begin() == oldBegin ) {
    187187                                std::ostringstream stream;
  • src/ResolvExpr/CommonType.cc

    r436c0de rade20d0  
    157157        void CommonType::visit( PointerType *pointerType ) {
    158158                if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
    159                         if ( widenFirst && dynamic_cast< VoidType* >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) {
     159                        if ( widenFirst && dynamic_cast< VoidType* >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base(), indexer) ) {
    160160                                getCommonWithVoidPointer( otherPointer, pointerType );
    161                         } else if ( widenSecond && dynamic_cast< VoidType* >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) {
     161                        } else if ( widenSecond && dynamic_cast< VoidType* >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base(), indexer) ) {
    162162                                getCommonWithVoidPointer( pointerType, otherPointer );
    163163                        } else if ( ( pointerType->get_base()->get_qualifiers() >= otherPointer->get_base()->get_qualifiers() || widenFirst )
  • src/ResolvExpr/PtrsCastable.cc

    r436c0de rade20d0  
    135135        }
    136136
    137         void PtrsCastable::visit( __attribute__((unused)) TraitInstType *inst ) {}
     137        void PtrsCastable::visit(TraitInstType *inst) {
     138                // I definitely don't think we should be doing anything here
     139        }
    138140
    139141        void PtrsCastable::visit(TypeInstType *inst) {
  • src/ResolvExpr/Unify.cc

    r436c0de rade20d0  
    114114        }
    115115
    116         bool isFtype( Type *type ) {
     116        bool isFtype( Type *type, const SymTab::Indexer &indexer ) {
    117117                if ( dynamic_cast< FunctionType* >( type ) ) {
    118118                        return true;
     
    123123        }
    124124
    125         bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) {
     125        bool tyVarCompatible( const TypeDecl::Data & data, Type *type, const SymTab::Indexer &indexer ) {
    126126                switch ( data.kind ) {
    127127                  case TypeDecl::Any:
     
    131131                        // type must also be complete
    132132                        // xxx - should this also check that type is not a tuple type and that it's not a ttype?
    133                         return ! isFtype( type ) && (! data.isComplete || type->isComplete() );
     133                        return ! isFtype( type, indexer ) && (! data.isComplete || type->isComplete() );
    134134                  case TypeDecl::Ftype:
    135                         return isFtype( type );
     135                        return isFtype( type, indexer );
    136136                  case TypeDecl::Ttype:
    137137                        // ttype unifies with any tuple type
     
    144144                OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );
    145145                assert( tyvar != openVars.end() );
    146                 if ( ! tyVarCompatible( tyvar->second, other ) ) {
     146                if ( ! tyVarCompatible( tyvar->second, other, indexer ) ) {
    147147                        return false;
    148148                } // if
     
    388388        }
    389389
    390         void Unify::visit( __attribute__((unused)) VoidType *voidType) {
     390        void Unify::visit(VoidType *voidType) {
    391391                result = dynamic_cast< VoidType* >( type2 );
    392392        }
     
    683683
    684684        template< typename Iterator1, typename Iterator2 >
    685         bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
     685        bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
    686686                auto get_type = [](Type * t) { return t; };
    687687                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
     
    733733                        flatten( flat2.get(), back_inserter( types2 ) );
    734734
    735                         result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer );
    736                 } // if
    737         }
    738 
    739         void Unify::visit( __attribute__((unused)) VarArgsType *varArgsType ) {
     735                        result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, widenMode, indexer );
     736                } // if
     737        }
     738
     739        void Unify::visit(VarArgsType *varArgsType) {
    740740                result = dynamic_cast< VarArgsType* >( type2 );
    741741        }
    742742
    743         void Unify::visit( __attribute__((unused)) ZeroType *zeroType ) {
     743        void Unify::visit(ZeroType *zeroType) {
    744744                result = dynamic_cast< ZeroType* >( type2 );
    745745        }
    746746
    747         void Unify::visit( __attribute__((unused)) OneType *oneType ) {
     747        void Unify::visit(OneType *oneType) {
    748748                result = dynamic_cast< OneType* >( type2 );
    749749        }
  • src/ResolvExpr/typeops.h

    r436c0de rade20d0  
    118118
    119119        // in Unify.cc
    120         bool isFtype( Type *type );
     120        bool isFtype( Type *type, const SymTab::Indexer &indexer );
    121121        bool typesCompatible( Type *, Type *, const SymTab::Indexer &indexer, const TypeEnvironment &env );
    122122        bool typesCompatibleIgnoreQualifiers( Type *, Type *, const SymTab::Indexer &indexer, const TypeEnvironment &env );
  • src/SymTab/Autogen.cc

    r436c0de rade20d0  
    262262        // E ?=?(E volatile*, int),
    263263        //   ?=?(E _Atomic volatile*, int);
    264         void makeEnumFunctions( EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) {
     264        void makeEnumFunctions( EnumDecl *enumDecl, EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) {
    265265
    266266                // T ?=?(E *, E);
     
    486486
    487487        /// generates the body of a union assignment/copy constructor/field constructor
    488         void makeUnionAssignBody( FunctionDecl * funcDecl ) {
     488        void makeUnionAssignBody( FunctionDecl * funcDecl, bool isDynamicLayout ) {
    489489                FunctionType * ftype = funcDecl->get_functionType();
    490490                assert( ftype->get_parameters().size() == 2 );
     
    506506                // Make function polymorphic in same parameters as generic union, if applicable
    507507                const std::list< TypeDecl* > & typeParams = aggregateDecl->get_parameters(); // List of type variables to be placed on the generated functions
    508                
     508                bool isDynamicLayout = hasDynamicLayout( aggregateDecl );  // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for struct)
     509
    509510                // default ctor/dtor need only first parameter
    510511                // void ?{}(T *); void ^?{}(T *);
     
    532533                FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting );
    533534
    534                 makeUnionAssignBody( assignDecl );
     535                makeUnionAssignBody( assignDecl, isDynamicLayout );
    535536
    536537                // body of assignment and copy ctor is the same
    537                 makeUnionAssignBody( copyCtorDecl );
     538                makeUnionAssignBody( copyCtorDecl, isDynamicLayout );
    538539
    539540                // create a constructor which takes the first member type as a parameter.
     
    550551                                FunctionDecl * ctor = genFunc( "?{}", memCtorType, functionNesting );
    551552
    552                                 makeUnionAssignBody( ctor );
     553                                makeUnionAssignBody( ctor, isDynamicLayout );
    553554                                memCtors.push_back( ctor );
    554555                                // only generate a ctor for the first field
     
    577578                        EnumInstType *enumInst = new EnumInstType( Type::Qualifiers(), enumDecl->get_name() );
    578579                        // enumInst->set_baseEnum( enumDecl );
    579                         makeEnumFunctions( enumInst, functionNesting, declsToAddAfter );
     580                        makeEnumFunctions( enumDecl, enumInst, functionNesting, declsToAddAfter );
    580581                }
    581582        }
  • src/SymTab/ImplementationType.cc

    r436c0de rade20d0  
    7676        }
    7777
    78         void ImplementationType::visit( __attribute__((unused)) FunctionType *functionType ) {}
     78        void ImplementationType::visit(FunctionType *functionType) {
     79///   FunctionType *newType = functionType->clone();
     80///   for ( std::list< DeclarationWithType* >::iterator i = newType->get_parameters().begin(); i != newType->get_parameters().end(); ++i ) {
     81///     i->set_type( implementationType( i->get_type(), indexer ) );
     82///   }
     83///   for ( std::list< DeclarationWithType* >::iterator i = newType->get_parameters().begin(); i != newType->get_parameters().end(); ++i ) {
     84///     i->set_type( implementationType( i->get_type(), indexer ) );
     85///   }
     86        }
     87
    7988        void ImplementationType::visit( __attribute__((unused)) StructInstType * aggregateUseType ) {}
    8089        void ImplementationType::visit( __attribute__((unused)) UnionInstType * aggregateUseType ) {}
  • src/SymTab/Indexer.cc

    r436c0de rade20d0  
    518518                acceptNewScope( tupleExpr->get_result(), *this );
    519519                maybeAccept( tupleExpr->get_tuple(), *this );
     520        }
     521
     522        void Indexer::visit( MemberTupleExpr *tupleExpr ) {
     523                acceptNewScope( tupleExpr->get_result(), *this );
     524                maybeAccept( tupleExpr->get_member(), *this );
     525                maybeAccept( tupleExpr->get_aggregate(), *this );
    520526        }
    521527
  • src/SymTab/Indexer.h

    r436c0de rade20d0  
    7474                virtual void visit( TupleExpr *tupleExpr );
    7575                virtual void visit( TupleIndexExpr *tupleExpr );
     76                virtual void visit( MemberTupleExpr *tupleExpr );
    7677                virtual void visit( TupleAssignExpr *tupleExpr );
    7778                virtual void visit( StmtExpr * stmtExpr );
  • src/SymTab/Mangler.cc

    r436c0de rade20d0  
    236236        }
    237237
    238         void Mangler::visit( __attribute__((unused)) ZeroType *zeroType ) {
     238        void Mangler::visit( ZeroType *zeroType ) {
    239239                mangleName << "Z";
    240240        }
    241241
    242         void Mangler::visit( __attribute__((unused)) OneType *oneType ) {
     242        void Mangler::visit( OneType *oneType ) {
    243243                mangleName << "O";
    244244        }
  • src/SymTab/Validate.cc

    r436c0de rade20d0  
    611611                returnVals = functionDecl->get_functionType()->get_returnVals();
    612612        }
    613         void ReturnChecker::postvisit( __attribute__((unused)) FunctionDecl * functionDecl ) {
     613        void ReturnChecker::postvisit( FunctionDecl * functionDecl ) {
    614614                returnVals = returnValsStack.top();
    615615                returnValsStack.pop();
  • src/SynTree/Expression.h

    r436c0de rade20d0  
    690690};
    691691
     692/// MemberTupleExpr represents a tuple member selection operation on a struct type, e.g. s.[a, b, c] after processing by the expression analyzer
     693class MemberTupleExpr : public Expression {
     694  public:
     695        MemberTupleExpr( Expression * member, Expression * aggregate, Expression * _aname = nullptr );
     696        MemberTupleExpr( const MemberTupleExpr & other );
     697        virtual ~MemberTupleExpr();
     698
     699        Expression * get_member() const { return member; }
     700        Expression * get_aggregate() const { return aggregate; }
     701        MemberTupleExpr * set_member( Expression * newValue ) { member = newValue; return this; }
     702        MemberTupleExpr * set_aggregate( Expression * newValue ) { aggregate = newValue; return this; }
     703
     704        virtual MemberTupleExpr * clone() const { return new MemberTupleExpr( * this ); }
     705        virtual void accept( Visitor & v ) { v.visit( this ); }
     706        virtual Expression * acceptMutator( Mutator & m ) { return m.mutate( this ); }
     707        virtual void print( std::ostream & os, int indent = 0 ) const;
     708  private:
     709        Expression * member;
     710        Expression * aggregate;
     711};
     712
    692713/// TupleAssignExpr represents a multiple assignment operation, where both sides of the assignment have tuple type, e.g. [a, b, c] = [d, e, f];, a mass assignment operation, where the left hand side has tuple type and the right hand side does not, e.g. [a, b, c] = 5.0;, or a tuple ctor/dtor expression
    693714class TupleAssignExpr : public Expression {
  • src/SynTree/Initializer.cc

    r436c0de rade20d0  
    3333}
    3434
    35 // void Initializer::print( __attribute__((unused)) std::ostream &os, __attribute__((unused)) int indent ) {}
     35void Initializer::print( std::ostream &os, int indent ) {}
    3636
    3737SingleInit::SingleInit( Expression *v, const std::list< Expression *> &_designators, bool maybeConstructed ) : Initializer( maybeConstructed ), value ( v ), designators( _designators ) {
  • src/SynTree/Initializer.h

    r436c0de rade20d0  
    5353        virtual void accept( Visitor &v ) = 0;
    5454        virtual Initializer *acceptMutator( Mutator &m ) = 0;
    55         virtual void print( std::ostream &os, int indent = 0 ) = 0;
     55        virtual void print( std::ostream &os, int indent = 0 );
    5656  private:
    5757        //      std::string name;
  • src/SynTree/Mutator.cc

    r436c0de rade20d0  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Mar  8 16:36:00 2017
    13 // Update Count     : 23
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Mar 30 16:45:19 2017
     13// Update Count     : 22
    1414//
    1515
     
    153153}
    154154
    155 Statement *Mutator::mutate( ThrowStmt *throwStmt ) {
    156         throwStmt->set_expr( maybeMutate( throwStmt->get_expr(), *this ) );
    157         throwStmt->set_target( maybeMutate( throwStmt->get_target(), *this ) );
    158         return throwStmt;
    159 }
    160 
    161155Statement *Mutator::mutate( TryStmt *tryStmt ) {
    162156        tryStmt->set_block( maybeMutate( tryStmt->get_block(), *this ) );
     
    414408}
    415409
     410Expression *Mutator::mutate( MemberTupleExpr *tupleExpr ) {
     411        tupleExpr->set_env( maybeMutate( tupleExpr->get_env(), *this ) );
     412        tupleExpr->set_result( maybeMutate( tupleExpr->get_result(), *this ) );
     413        tupleExpr->set_member( maybeMutate( tupleExpr->get_member(), *this ) );
     414        tupleExpr->set_aggregate( maybeMutate( tupleExpr->get_aggregate(), *this ) );
     415        return tupleExpr;
     416}
     417
    416418Expression *Mutator::mutate( TupleAssignExpr *assignExpr ) {
    417419        assignExpr->set_env( maybeMutate( assignExpr->get_env(), *this ) );
  • src/SynTree/Mutator.h

    r436c0de rade20d0  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Jun  8 15:45:00 2017
    13 // Update Count     : 14
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Feb  9 14:23:23 2017
     13// Update Count     : 13
    1414//
    1515#include <cassert>
     
    4646        virtual Statement* mutate( BranchStmt *branchStmt );
    4747        virtual Statement* mutate( ReturnStmt *returnStmt );
    48         virtual Statement* mutate( ThrowStmt *throwStmt );
    49         virtual Statement* mutate( TryStmt *tryStmt );
     48        virtual Statement* mutate( TryStmt *returnStmt );
    5049        virtual Statement* mutate( CatchStmt *catchStmt );
    5150        virtual Statement* mutate( FinallyStmt *catchStmt );
     
    8382        virtual Expression* mutate( TupleExpr *tupleExpr );
    8483        virtual Expression* mutate( TupleIndexExpr *tupleExpr );
     84        virtual Expression* mutate( MemberTupleExpr *tupleExpr );
    8585        virtual Expression* mutate( TupleAssignExpr *assignExpr );
    8686        virtual Expression* mutate( StmtExpr * stmtExpr );
  • src/SynTree/Statement.cc

    r436c0de rade20d0  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun 12 10:37:00 2017
    13 // Update Count     : 64
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Aug 12 13:58:48 2016
     13// Update Count     : 62
    1414//
    1515
     
    101101}
    102102
    103 ReturnStmt::ReturnStmt( std::list<Label> labels, Expression *_expr ) : Statement( labels ), expr( _expr ) {}
    104 
    105 ReturnStmt::ReturnStmt( const ReturnStmt & other ) : Statement( other ), expr( maybeClone( other.expr ) ) {}
     103ReturnStmt::ReturnStmt( std::list<Label> labels, Expression *_expr, bool throwP ) : Statement( labels ), expr( _expr ), isThrow( throwP ) {}
     104
     105ReturnStmt::ReturnStmt( const ReturnStmt & other ) : Statement( other ), expr( maybeClone( other.expr ) ), isThrow( other.isThrow ) {}
    106106
    107107ReturnStmt::~ReturnStmt() {
     
    110110
    111111void ReturnStmt::print( std::ostream &os, int indent ) const {
    112         os <<  "Return Statement, returning: ";
     112        os << string ( isThrow? "Throw":"Return" ) << " Statement, returning: ";
    113113        if ( expr != 0 ) {
    114114                os << endl << string( indent+2, ' ' );
     
    287287}
    288288
    289 ThrowStmt::ThrowStmt( std::list<Label> labels, Kind kind, Expression * expr, Expression * target ) :
    290                 Statement( labels ), kind(kind), expr(expr), target(target)     {
    291         assertf(Resume == kind || nullptr == target, "Non-local termination throw is not accepted." );
    292 }
    293 
    294 ThrowStmt::ThrowStmt( const ThrowStmt &other ) :
    295         Statement ( other ), kind( other.kind ), expr( maybeClone( other.expr ) ), target( maybeClone( other.target ) ) {
    296 }
    297 
    298 ThrowStmt::~ThrowStmt() {
    299         delete expr;
    300         delete target;
    301 }
    302 
    303 void ThrowStmt::print( std::ostream &os, int indent) const {
    304         if ( target ) {
    305                 os << "Non-Local ";
    306         }
    307         os << "Throw Statement, raising: ";
    308         expr->print(os, indent + 4);
    309         if ( target ) {
    310                 os << "At: ";
    311                 target->print(os, indent + 4);
    312         }
    313 }
    314 
    315289TryStmt::TryStmt( std::list<Label> labels, CompoundStmt *tryBlock, std::list<Statement *> &_handlers, FinallyStmt *_finallyBlock ) :
    316290        Statement( labels ), block( tryBlock ),  handlers( _handlers ), finallyBlock( _finallyBlock ) {
     
    344318}
    345319
    346 CatchStmt::CatchStmt( std::list<Label> labels, Kind _kind, Declaration *_decl, Expression *_cond, Statement *_body ) :
    347         Statement( labels ), kind ( _kind ), decl ( _decl ), cond ( _cond ), body( _body ) {
     320CatchStmt::CatchStmt( std::list<Label> labels, Declaration *_decl, Statement *_body, bool catchAny ) :
     321        Statement( labels ), decl ( _decl ), body( _body ), catchRest ( catchAny ) {
    348322}
    349323
    350324CatchStmt::CatchStmt( const CatchStmt & other ) :
    351         Statement( other ), kind ( other.kind ), decl ( maybeClone( other.decl ) ), cond ( maybeClone( other.cond ) ), body( maybeClone( other.body ) ) {
     325        Statement( other ), decl ( maybeClone( other.decl ) ), body( maybeClone( other.body ) ), catchRest ( other.catchRest ) {
    352326}
    353327
     
    358332
    359333void CatchStmt::print( std::ostream &os, int indent ) const {
    360         os << "Catch " << ((Terminate == kind) ? "Terminate" : "Resume") << " Statement" << endl;
     334        os << "Catch Statement" << endl;
    361335
    362336        os << string( indent, ' ' ) << "... catching" << endl;
     
    364338                decl->printShort( os, indent + 4 );
    365339                os << endl;
    366         }
     340        } else if ( catchRest )
     341                os << string( indent + 4 , ' ' ) << "the rest" << endl;
    367342        else
    368343                os << string( indent + 4 , ' ' ) << ">>> Error:  this catch clause must have a declaration <<<" << endl;
  • src/SynTree/Statement.h

    r436c0de rade20d0  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun 12 13:35:00 2017
    13 // Update Count     : 67
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Aug 12 13:57:46 2016
     13// Update Count     : 65
    1414//
    1515
     
    5757  private:
    5858        std::list<Statement*> kids;
    59 };
    60 
    61 class NullStmt : public CompoundStmt {
    62   public:
    63         NullStmt();
    64         NullStmt( std::list<Label> labels );
    65 
    66         virtual NullStmt *clone() const { return new NullStmt( *this ); }
    67         virtual void accept( Visitor &v ) { v.visit( this ); }
    68         virtual NullStmt *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    69         virtual void print( std::ostream &os, int indent = 0 ) const;
    70 
    71   private:
    7259};
    7360
     
    274261class ReturnStmt : public Statement {
    275262  public:
    276         ReturnStmt( std::list<Label> labels, Expression *expr );
     263        ReturnStmt( std::list<Label> labels, Expression *expr, bool throwP = false );
    277264        ReturnStmt( const ReturnStmt &other );
    278265        virtual ~ReturnStmt();
     
    287274  private:
    288275        Expression *expr;
    289 };
    290 
    291 class ThrowStmt : public Statement {
    292   public:
    293         enum Kind { Terminate, Resume };
    294 
    295         ThrowStmt( std::list<Label> labels, Kind kind, Expression * expr, Expression * target = nullptr );
    296         ThrowStmt( const ThrowStmt &other );
    297         virtual ~ThrowStmt();
    298 
    299         Kind get_kind() { return kind; }
    300         Expression * get_expr() { return expr; }
    301         void set_expr( Expression * newExpr ) { expr = newExpr; }
    302         Expression * get_target() { return target; }
    303         void set_target( Expression * newTarget ) { target = newTarget; }
    304 
    305         virtual ThrowStmt *clone() const { return new ThrowStmt( *this ); }
    306         virtual void accept( Visitor &v ) { v.visit( this ); }
    307         virtual Statement *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    308         virtual void print( std::ostream &os, int indent = 0 ) const;
    309   private:
    310         Kind kind;
    311         Expression * expr;
    312         Expression * target;
     276        bool isThrow;
     277};
     278
     279
     280class NullStmt : public CompoundStmt {
     281  public:
     282        NullStmt();
     283        NullStmt( std::list<Label> labels );
     284
     285        virtual NullStmt *clone() const { return new NullStmt( *this ); }
     286        virtual void accept( Visitor &v ) { v.visit( this ); }
     287        virtual NullStmt *acceptMutator( Mutator &m ) { return m.mutate( this ); }
     288        virtual void print( std::ostream &os, int indent = 0 ) const;
     289
     290  private:
    313291};
    314292
     
    339317class CatchStmt : public Statement {
    340318  public:
    341         enum Kind { Terminate, Resume };
    342 
    343         CatchStmt( std::list<Label> labels, Kind kind, Declaration *decl,
    344                    Expression *cond, Statement *body );
     319        CatchStmt( std::list<Label> labels, Declaration *decl, Statement *body, bool catchAny = false );
    345320        CatchStmt( const CatchStmt &other );
    346321        virtual ~CatchStmt();
    347322
    348         Kind get_kind() { return kind; }
    349323        Declaration *get_decl() { return decl; }
    350324        void set_decl( Declaration *newValue ) { decl = newValue; }
    351         Expression *get_cond() { return cond; }
    352         void set_cond( Expression *newCond ) { cond = newCond; }
     325
    353326        Statement *get_body() { return body; }
    354327        void set_body( Statement *newValue ) { body = newValue; }
     
    360333
    361334  private:
    362         Kind kind;
    363335        Declaration *decl;
    364         Expression *cond;
    365336        Statement *body;
     337        bool catchRest;
    366338};
    367339
  • src/SynTree/SynTree.h

    r436c0de rade20d0  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Jun  8 17:00:00 2017
    13 // Update Count     : 9
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Feb  9 14:23:49 2017
     13// Update Count     : 8
    1414//
    1515
     
    5151class BranchStmt;
    5252class ReturnStmt;
    53 class ThrowStmt;
    5453class TryStmt;
    5554class CatchStmt;
     
    9089class TupleExpr;
    9190class TupleIndexExpr;
     91class MemberTupleExpr;
    9292class TupleAssignExpr;
    9393class StmtExpr;
  • src/SynTree/TupleExpr.cc

    r436c0de rade20d0  
    7878}
    7979
     80MemberTupleExpr::MemberTupleExpr( Expression * member, Expression * aggregate, Expression * _aname ) : Expression( _aname ) {
     81        set_result( maybeClone( member->get_result() ) ); // xxx - ???
     82}
     83
     84MemberTupleExpr::MemberTupleExpr( const MemberTupleExpr &other ) : Expression( other ), member( other.member->clone() ), aggregate( other.aggregate->clone() ) {
     85}
     86
     87MemberTupleExpr::~MemberTupleExpr() {
     88        delete member;
     89        delete aggregate;
     90}
     91
     92void MemberTupleExpr::print( std::ostream &os, int indent ) const {
     93        os << "Member Tuple Expression, with aggregate:" << std::endl;
     94        os << std::string( indent+2, ' ' );
     95        aggregate->print( os, indent+2 );
     96        os << std::string( indent+2, ' ' ) << "with member: " << std::endl;
     97        os << std::string( indent+2, ' ' );
     98        member->print( os, indent+2 );
     99        Expression::print( os, indent );
     100}
     101
    80102TupleAssignExpr::TupleAssignExpr( const std::list< Expression * > & assigns, const std::list< ObjectDecl * > & tempDecls, Expression * _aname ) : Expression( _aname ) {
    81103        // convert internally into a StmtExpr which contains the declarations and produces the tuple of the assignments
  • src/SynTree/Visitor.cc

    r436c0de rade20d0  
    99// Author           : Richard C. Bilson
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Jun  8 16:31:00 2017
    13 // Update Count     : 25
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Mar 30 16:45:25 2017
     13// Update Count     : 24
    1414//
    1515
     
    129129}
    130130
    131 void Visitor::visit( ThrowStmt * throwStmt ) {
    132         maybeAccept( throwStmt->get_expr(), *this );
    133         maybeAccept( throwStmt->get_target(), *this );
    134 }
    135 
    136131void Visitor::visit( TryStmt *tryStmt ) {
    137132        maybeAccept( tryStmt->get_block(), *this );
     
    324319        maybeAccept( tupleExpr->get_result(), *this );
    325320        maybeAccept( tupleExpr->get_tuple(), *this );
     321}
     322
     323void Visitor::visit( MemberTupleExpr *tupleExpr ) {
     324        maybeAccept( tupleExpr->get_result(), *this );
     325        maybeAccept( tupleExpr->get_member(), *this );
     326        maybeAccept( tupleExpr->get_aggregate(), *this );
    326327}
    327328
  • src/SynTree/Visitor.h

    r436c0de rade20d0  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Jun 08 15:45:00 2017
    13 // Update Count     : 11
     12// Last Modified On : Wed May  3 08:58:00 2017
     13// Update Count     : 10
    1414//
    1515
     
    4949        virtual void visit( BranchStmt *branchStmt );
    5050        virtual void visit( ReturnStmt *returnStmt );
    51         virtual void visit( ThrowStmt *throwStmt );
    5251        virtual void visit( TryStmt *tryStmt );
    5352        virtual void visit( CatchStmt *catchStmt );
     
    8685        virtual void visit( TupleExpr *tupleExpr );
    8786        virtual void visit( TupleIndexExpr *tupleExpr );
     87        virtual void visit( MemberTupleExpr *tupleExpr );
    8888        virtual void visit( TupleAssignExpr *assignExpr );
    8989        virtual void visit( StmtExpr * stmtExpr );
  • src/SynTree/ZeroOneType.cc

    r436c0de rade20d0  
    2020ZeroType::ZeroType( Type::Qualifiers tq, const std::list< Attribute * > & attributes ) : Type( tq, attributes ) {}
    2121
    22 void ZeroType::print( std::ostream &os, __attribute__((unused)) int indent ) const {
     22void ZeroType::print( std::ostream &os, int indent ) const {
    2323        os << "zero_t";
    2424}
     
    2828OneType::OneType( Type::Qualifiers tq, const std::list< Attribute * > & attributes ) : Type( tq, attributes ) {}
    2929
    30 void OneType::print( std::ostream &os, __attribute__((unused)) int indent ) const {
     30void OneType::print( std::ostream &os, int indent ) const {
    3131        os << "one_t";
    3232}
  • src/Tuples/TupleExpansion.cc

    r436c0de rade20d0  
    354354                                maybeImpure = true;
    355355                        }
    356                         virtual void visit( __attribute__((unused)) UntypedExpr * untypedExpr ) { maybeImpure = true; }
     356                        virtual void visit( UntypedExpr * untypedExpr ) { maybeImpure = true; }
    357357                        bool maybeImpure = false;
    358358                };
  • src/libcfa/concurrency/alarm.c

    r436c0de rade20d0  
    104104
    105105static inline void remove_at( alarm_list_t * this, alarm_node_t * n, __alarm_it_t it ) {
    106         verify( it );
    107         verify( (*it)->next == n );
     106        assert( it );
     107        assert( (*it)->next == n );
    108108
    109109        (*it)->next = n->next;
  • src/libcfa/concurrency/coroutine

    r436c0de rade20d0  
    7171// Suspend implementation inlined for performance
    7272static inline void suspend() {
    73         coroutine_desc * src = this_coroutine();                // optimization
     73      coroutine_desc * src = this_coroutine();          // optimization
    7474
    7575        assertf( src->last != 0,
     
    9191        coroutine_desc * dst = get_coroutine(cor);
    9292
    93         if( unlikely(!dst->stack.base) ) {
     93      if( unlikely(!dst->stack.base) ) {
    9494                create_stack(&dst->stack, dst->stack.size);
    9595                CtxStart(cor, CtxInvokeCoroutine);
    9696        }
    9797
    98         // not resuming self ?
     98      // not resuming self ?
    9999        if ( src != dst ) {
    100100                assertf( dst->state != Halted ,
     
    103103                        src->name, src, dst->name, dst );
    104104
    105                 // set last resumer
     105            // set last resumer
    106106                dst->last = src;
    107107        } // if
    108108
    109         // always done for performance testing
     109      // always done for performance testing
    110110        CoroutineCtxSwitch( src, dst );
    111111}
     
    114114        coroutine_desc * src = this_coroutine();                // optimization
    115115
    116         // not resuming self ?
     116      // not resuming self ?
    117117        if ( src != dst ) {
    118118                assertf( dst->state != Halted ,
     
    121121                        src->name, src, dst->name, dst );
    122122
    123                 // set last resumer
     123            // set last resumer
    124124                dst->last = src;
    125125        } // if
    126126
    127         // always done for performance testing
     127      // always done for performance testing
    128128        CoroutineCtxSwitch( src, dst );
    129129}
  • src/libcfa/concurrency/kernel.c

    r436c0de rade20d0  
    311311        // appropriate stack.
    312312        proc_cor_storage.__cor.state = Active;
    313         main( &proc_cor_storage );
    314         proc_cor_storage.__cor.state = Halted;
     313      main( &proc_cor_storage );
     314      proc_cor_storage.__cor.state = Halted;
    315315
    316316        // Main routine of the core returned, the core is now fully terminated
     
    333333        if( !thrd ) return;
    334334
    335         verifyf( thrd->next == NULL, "Expected null got %p", thrd->next );
     335        assertf( thrd->next == NULL, "Expected null got %p", thrd->next );
    336336       
    337337        lock( &systemProcessor->proc.cltr->lock );
     
    577577
    578578void append( __thread_queue_t * this, thread_desc * t ) {
    579         verify(this->tail != NULL);
     579        assert(this->tail != NULL);
    580580        *this->tail = t;
    581581        this->tail = &t->next;
     
    599599
    600600void push( __condition_stack_t * this, __condition_criterion_t * t ) {
    601         verify( !t->next );
     601        assert( !t->next );
    602602        t->next = this->top;
    603603        this->top = t;
  • src/libcfa/concurrency/kernel_private.h

    r436c0de rade20d0  
    2222
    2323#include "alarm.h"
    24 
    25 #include "libhdr.h"
    2624
    2725//-----------------------------------------------------------------------------
     
    6866
    6967static inline void enable_interrupts_noRF() {
    70         __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &this_processor->disable_preempt_count, -1, __ATOMIC_SEQ_CST );
    71         verify( prev != (unsigned short) 0 );
     68        unsigned short prev = __atomic_fetch_add_2( &this_processor->disable_preempt_count, -1, __ATOMIC_SEQ_CST );
     69        assert( prev != (unsigned short) 0 );
    7270}
    7371
    7472static inline void enable_interrupts() {
    75         __attribute__((unused)) unsigned short prev = __atomic_fetch_add_2( &this_processor->disable_preempt_count, -1, __ATOMIC_SEQ_CST );
    76         verify( prev != (unsigned short) 0 );
     73        unsigned short prev = __atomic_fetch_add_2( &this_processor->disable_preempt_count, -1, __ATOMIC_SEQ_CST );
     74        assert( prev != (unsigned short) 0 );
    7775        if( prev == 1 && this_processor->pending_preemption ) {
    7876                ScheduleInternal( this_processor->current_thread );
  • src/libcfa/concurrency/monitor

    r436c0de rade20d0  
    2626static inline void ?{}(monitor_desc * this) {
    2727        this->owner = NULL;
    28         this->stack_owner = NULL;
     28      this->stack_owner = NULL;
    2929        this->recursion = 0;
    3030}
     
    3333        monitor_desc ** m;
    3434        int count;
    35         monitor_desc ** prev_mntrs;
    36         unsigned short  prev_count;
     35      monitor_desc ** prev_mntrs;
     36      unsigned short  prev_count;
    3737};
    3838
  • src/libcfa/concurrency/monitor.c

    r436c0de rade20d0  
    5656                else if( this->owner == thrd) {
    5757                        //We already have the monitor, just not how many times we took it
    58                         verify( this->recursion > 0 );
     58                        assert( this->recursion > 0 );
    5959                        this->recursion += 1;
    6060                }
     
    7878                lock( &this->lock );
    7979
     80                thread_desc * thrd = this_thread();
     81
    8082                LIB_DEBUG_PRINT_SAFE("%p Leaving %p (o: %p, r: %i)\n", thrd, this, this->owner, this->recursion);
    81                 verifyf( this_thread() == this->owner, "Expected owner to be %p, got %p (r: %i)", this_thread(), this->owner, this->recursion );
     83                assertf( thrd == this->owner, "Expected owner to be %p, got %p (r: %i)", thrd, this->owner, this->recursion );
    8284
    8385                //Leaving a recursion level, decrement the counter
     
    165167        //Check that everything is as expected
    166168        assertf( this->monitors != NULL, "Waiting with no monitors (%p)", this->monitors );
    167         verifyf( this->monitor_count != 0, "Waiting with 0 monitors (%i)", this->monitor_count );
    168         verifyf( this->monitor_count < 32u, "Excessive monitor count (%i)", this->monitor_count );
     169        assertf( this->monitor_count != 0, "Waiting with 0 monitors (%i)", this->monitor_count );
     170        assertf( this->monitor_count < 32u, "Excessive monitor count (%i)", this->monitor_count );
    169171
    170172        unsigned short count = this->monitor_count;
     
    227229
    228230        //Check that everything is as expected
    229         verify( this->monitors );
    230         verify( this->monitor_count != 0 );
     231        assert( this->monitors );
     232        assert( this->monitor_count != 0 );
    231233
    232234        unsigned short count = this->monitor_count;
     
    276278
    277279        //Check that everything is as expected
    278         verifyf( this->monitors != NULL, "Waiting with no monitors (%p)", this->monitors );
    279         verifyf( this->monitor_count != 0, "Waiting with 0 monitors (%i)", this->monitor_count );
     280        assertf( this->monitors != NULL, "Waiting with no monitors (%p)", this->monitors );
     281        assertf( this->monitor_count != 0, "Waiting with 0 monitors (%i)", this->monitor_count );
    280282
    281283        unsigned short count = this->monitor_count;
     
    325327
    326328uintptr_t front( condition * this ) {
    327         verifyf( !is_empty(this),
    328                 "Attempt to access user data on an empty condition.\n"
    329                 "Possible cause is not checking if the condition is empty before reading stored data."
     329        LIB_DEBUG_DO(
     330                if( is_empty(this) ) {
     331                        abortf( "Attempt to access user data on an empty condition.\n"
     332                    "Possible cause is not checking if the condition is empty before reading stored data." );
     333                }
    330334        );
    331335        return this->blocked.head->user_info;
     
    487491
    488492void append( __condition_blocked_queue_t * this, __condition_node_t * c ) {
    489         verify(this->tail != NULL);
     493        assert(this->tail != NULL);
    490494        *this->tail = c;
    491495        this->tail = &c->next;
  • src/libcfa/containers/maybe

    r436c0de rade20d0  
    1010// Created On       : Wed May 24 14:43:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jun 16 15:42:00 2017
    13 // Update Count     : 2
     12// Last Modified On : Thr May 25 16:36:00 2017
     13// Update Count     : 1
    1414//
    1515
     
    4646bool ?!=?(maybe(T) this, zero_t);
    4747
    48 /* Waiting for bug#11 to be fixed.
    4948forall(otype T)
    5049maybe(T) maybe_value(T value);
     
    5251forall(otype T)
    5352maybe(T) maybe_none();
    54 */
    5553
    5654forall(otype T)
  • src/libcfa/containers/result

    r436c0de rade20d0  
    1010// Created On       : Wed May 24 14:45:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Jun 16 15:41:00 2017
    13 // Update Count     : 2
     12// Last Modified On : Thr May 25 16:39:00 2017
     13// Update Count     : 1
    1414//
    1515
     
    5555bool ?!=?(result(T, E) this, zero_t);
    5656
    57 /* Wating for bug#11 to be fixed.
    5857forall(otype T, otype E)
    5958result(T, E) result_value(T value);
     
    6160forall(otype T, otype E)
    6261result(T, E) result_error(E error);
    63 */
    6462
    6563forall(otype T, otype E)
  • src/libcfa/containers/result.c

    r436c0de rade20d0  
    7474forall(otype T, otype E)
    7575bool ?!=?(result(T, E) this, zero_t) {
    76         return this.has_value;
     76        return !this.has_value;
    7777}
    7878
     
    100100forall(otype T, otype E)
    101101E get_error(result(T, E) * this) {
    102         assertf(!this->has_value, "attempt to get from result without error");
     102        assertf(this->has_value, "attempt to get from result without error");
    103103        return this->error;
    104104}
  • src/libcfa/libhdr/libdebug.h

    r436c0de rade20d0  
    1818
    1919#ifdef __CFA_DEBUG__
    20         #define LIB_DEBUG_DO(x) x
    21         #define LIB_NO_DEBUG_DO(x) ((void)0)
     20      #define LIB_DEBUG_DO(x) x
     21      #define LIB_NO_DEBUG_DO(x) ((void)0)
    2222#else
    23         #define LIB_DEBUG_DO(x) ((void)0)
    24         #define LIB_NO_DEBUG_DO(x) x     
     23      #define LIB_DEBUG_DO(x) ((void)0)
     24      #define LIB_NO_DEBUG_DO(x) x     
    2525#endif
    26 
    27 #if !defined(NDEBUG) && (defined(__CFA_DEBUG__) || defined(__CFA_VERIFY__))
    28         #define verify(x) assert(x)
    29         #define verifyf(x, ...) assertf(x, __VA_ARGS__)
    30 #else
    31         #define verify(x)
    32         #define verifyf(x, ...)
    33 #endif
    34 
    3526
    3627#ifdef __cforall
  • src/tests/.expect/io.txt

    r436c0de rade20d0  
    44123
    55
    6 x (1 x [2 x {3 x =4 x $5 x £6 x ¥7 x ¡8 x ¿9 x «10
    7 1, x 2. x 3; x 4! x 5? x 6% x 7¢ x 8» x 9) x 10] x 11} x
    8 x`1`x'2'x"3"x:4:x 5 x   6       x
    9 7
    10 x
    11 8
    12 x
    13 9
    14 x
    15 10
    16 x
    17 x ( 1 ) x 2 , x 3 :x: 4
    186A
    1971 2 3 4 5 6 7 8
     
    3018abc, $xyz
    3119
    32 1, 2, 3, 4
    33 1, $2, $3 ", $"
    34 1 2 3 " "
    35  1 2 3
    36 12 3
    37 123
    38 1 23
    39 1 2 3
    40 1 2 3 4 " "
    41 1, 2, 3, 4 ", "
    42 1, 2, 3, 4
     20v(27 v[27 v{27 $27 =27 £27 ¥27 ¡27 ¿27 «27
     2125, 25. 25: 25; 25! 25? 25% 25¢ 25» 25) 25] 25}
     2225'27 25`27 25"27 25 27 25
     2327 25
     2427 25
     2527 25   27 25
     2627
    43273, 4, a, 7.2
    44283, 4, a, 7.2
    45293 4 a 7.2
    46  3 4 a 7.234a7.23 4 a 7.2
     30 3 4 a 7.234a7.2 3 4 a 7.2
    47313-4-a-7.2^3^4-3-4-a-7.2
  • src/tests/Makefile.am

    r436c0de rade20d0  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Thu Jun  8 07:41:43 2017
    14 ## Update Count     : 44
     13## Last Modified On : Thu May 25 14:39:15 2017
     14## Update Count     : 43
    1515###############################################################################
    1616
     
    2020
    2121if BUILD_CONCURRENCY
    22 concurrent = yes
    23 quick_test += coroutine thread monitor
    24 concurrent_test = coroutine thread monitor multi-monitor sched-int-barge sched-int-block sched-int-disjoint sched-int-wait sched-ext sched-ext-multi preempt
     22concurrent=yes
     23quick_test+= coroutine thread monitor
     24concurrent_test=coroutine thread monitor multi-monitor sched-int-barge sched-int-block sched-int-disjoint sched-int-wait sched-ext sched-ext-multi preempt
    2525else
    2626concurrent=no
     
    5757        @+python test.py --debug=${debug} --concurrent=${concurrent} ${concurrent_test}
    5858
    59 .dummy : .dummy.c @CFA_BINDIR@/@CFA_NAME@
     59.dummy : .dummy.c
    6060        ${CC} ${BUILD_FLAGS} -XCFA -n ${<} -o ${@}                              #don't use CFLAGS, this rule is not a real test
    6161
    62 
    63 % : %.c @CFA_BINDIR@/@CFA_NAME@
    64         ${CC} ${CFLAGS} ${<} -o ${@}
    65 
    66 dtor-early-exit-ERR1: dtor-early-exit.c @CFA_BINDIR@/@CFA_NAME@
     62dtor-early-exit-ERR1: dtor-early-exit.c
    6763        ${CC} ${CFLAGS} -DERR1 ${<} -o ${@}
    6864
    69 dtor-early-exit-ERR2: dtor-early-exit.c @CFA_BINDIR@/@CFA_NAME@
     65dtor-early-exit-ERR2: dtor-early-exit.c
    7066        ${CC} ${CFLAGS} -DERR2 ${<} -o ${@}
    7167
    72 declarationSpecifier: declarationSpecifier.c @CFA_BINDIR@/@CFA_NAME@
     68declarationSpecifier: declarationSpecifier.c
    7369        ${CC} ${CFLAGS} -CFA -XCFA -p -XCFA -L ${<} -o ${@}
    7470
    75 gccExtensions : gccExtensions.c @CFA_BINDIR@/@CFA_NAME@
     71gccExtensions : gccExtensions.c
    7672        ${CC} ${CFLAGS} -CFA -XCFA -p -XCFA -L ${<} -o ${@}
    7773
    78 extension : extension.c @CFA_BINDIR@/@CFA_NAME@
     74extension : extension.c
    7975        ${CC} ${CFLAGS} -CFA -XCFA -p -XCFA -L ${<} -o ${@}
    8076
    81 attributes : attributes.c @CFA_BINDIR@/@CFA_NAME@
     77attributes : attributes.c
    8278        ${CC} ${CFLAGS} -CFA -XCFA -p -XCFA -L ${<} -o ${@}
    8379
    84 KRfunctions : KRfunctions.c @CFA_BINDIR@/@CFA_NAME@
     80KRfunctions : KRfunctions.c
    8581        ${CC} ${CFLAGS} -CFA -XCFA -p -XCFA -L ${<} -o ${@}
    8682
    87 gmp : gmp.c @CFA_BINDIR@/@CFA_NAME@
     83gmp : gmp.c
    8884        ${CC} ${CFLAGS} -lgmp ${<} -o ${@}
    8985
    90 memberCtors-ERR1: memberCtors.c @CFA_BINDIR@/@CFA_NAME@
     86memberCtors-ERR1: memberCtors.c
    9187        ${CC} ${CFLAGS} -DERR1 ${<} -o ${@}
    9288
    93 completeTypeError : completeTypeError.c @CFA_BINDIR@/@CFA_NAME@
     89completeTypeError : completeTypeError.c
    9490        ${CC} ${CFLAGS} -DERR1 ${<} -o ${@}
  • src/tests/Makefile.in

    r436c0de rade20d0  
    661661        @+python test.py --debug=${debug} --concurrent=${concurrent} ${concurrent_test}
    662662
    663 .dummy : .dummy.c @CFA_BINDIR@/@CFA_NAME@
     663.dummy : .dummy.c
    664664        ${CC} ${BUILD_FLAGS} -XCFA -n ${<} -o ${@}                              #don't use CFLAGS, this rule is not a real test
    665665
    666 % : %.c @CFA_BINDIR@/@CFA_NAME@
    667         ${CC} ${CFLAGS} ${<} -o ${@}
    668 
    669 dtor-early-exit-ERR1: dtor-early-exit.c @CFA_BINDIR@/@CFA_NAME@
     666dtor-early-exit-ERR1: dtor-early-exit.c
    670667        ${CC} ${CFLAGS} -DERR1 ${<} -o ${@}
    671668
    672 dtor-early-exit-ERR2: dtor-early-exit.c @CFA_BINDIR@/@CFA_NAME@
     669dtor-early-exit-ERR2: dtor-early-exit.c
    673670        ${CC} ${CFLAGS} -DERR2 ${<} -o ${@}
    674671
    675 declarationSpecifier: declarationSpecifier.c @CFA_BINDIR@/@CFA_NAME@
     672declarationSpecifier: declarationSpecifier.c
    676673        ${CC} ${CFLAGS} -CFA -XCFA -p -XCFA -L ${<} -o ${@}
    677674
    678 gccExtensions : gccExtensions.c @CFA_BINDIR@/@CFA_NAME@
     675gccExtensions : gccExtensions.c
    679676        ${CC} ${CFLAGS} -CFA -XCFA -p -XCFA -L ${<} -o ${@}
    680677
    681 extension : extension.c @CFA_BINDIR@/@CFA_NAME@
     678extension : extension.c
    682679        ${CC} ${CFLAGS} -CFA -XCFA -p -XCFA -L ${<} -o ${@}
    683680
    684 attributes : attributes.c @CFA_BINDIR@/@CFA_NAME@
     681attributes : attributes.c
    685682        ${CC} ${CFLAGS} -CFA -XCFA -p -XCFA -L ${<} -o ${@}
    686683
    687 KRfunctions : KRfunctions.c @CFA_BINDIR@/@CFA_NAME@
     684KRfunctions : KRfunctions.c
    688685        ${CC} ${CFLAGS} -CFA -XCFA -p -XCFA -L ${<} -o ${@}
    689686
    690 gmp : gmp.c @CFA_BINDIR@/@CFA_NAME@
     687gmp : gmp.c
    691688        ${CC} ${CFLAGS} -lgmp ${<} -o ${@}
    692689
    693 memberCtors-ERR1: memberCtors.c @CFA_BINDIR@/@CFA_NAME@
     690memberCtors-ERR1: memberCtors.c
    694691        ${CC} ${CFLAGS} -DERR1 ${<} -o ${@}
    695692
    696 completeTypeError : completeTypeError.c @CFA_BINDIR@/@CFA_NAME@
     693completeTypeError : completeTypeError.c
    697694        ${CC} ${CFLAGS} -DERR1 ${<} -o ${@}
    698695
  • src/tests/coroutine.c

    r436c0de rade20d0  
    1 //
    2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    3 //
    4 // The contents of this file are covered under the licence agreement in the
    5 // file "LICENCE" distributed with Cforall.
    6 //
    7 // fibonacci.c --
    8 //
    9 // Author           : Thierry Delisle
    10 // Created On       : Thu Jun  8 07:29:37 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jun  8 07:37:12 2017
    13 // Update Count     : 5
    14 //
    15 
    161#include <fstream>
    172#include <coroutine>
    183
    194coroutine Fibonacci {
    20         int fn;                                         // used for communication
     5      int fn; // used for communication
    216};
    227
    23 void ?{}( Fibonacci * this ) {
    24         this->fn = 0;
     8void ?{}(Fibonacci* this) {
     9      this->fn = 0;
    2510}
    2611
    27 void main( Fibonacci * this ) {
    28         int fn1, fn2;                                   // retained between resumes
    29         this->fn = 0;                                   // case 0
    30         fn1 = this->fn;
    31         suspend();                                              // return to last resume
     12void main(Fibonacci* this) {
     13      int fn1, fn2;             // retained between resumes
     14      this->fn = 0;
     15      fn1 = this->fn;
     16      suspend();                // return to last resume
    3217
    33         this->fn = 1;                                   // case 1
    34         fn2 = fn1;
    35         fn1 = this->fn;
    36         suspend();                                              // return to last resume
     18      this->fn = 1;
     19      fn2 = fn1;
     20      fn1 = this->fn;
     21      suspend();                // return to last resume
    3722
    38         for ( ;; ) {                                    // general case
    39                 this->fn = fn1 + fn2;
    40                 fn2 = fn1;
    41                 fn1 = this->fn;
    42                 suspend();                                      // return to last resume
    43         } // for
     23      for ( ;; ) {
     24            this->fn = fn1 + fn2;
     25            fn2 = fn1;
     26            fn1 = this->fn;
     27            suspend(); // return to last resume
     28      }
    4429}
    4530
    46 int next( Fibonacci * this ) {
    47         resume( this );                                 // transfer to last suspend
    48         return this->fn;
     31int next(Fibonacci* this) {
     32      resume(this); // transfer to last suspend
     33      return this->fn;
    4934}
    5035
    5136int main() {
    52         Fibonacci f1, f2;
    53         for ( int i = 1; i <= 10; i += 1 ) {
    54                 sout | next( &f1 ) | ' ' | next( &f2 ) | endl;
    55         } // for
     37      Fibonacci f1, f2;
     38      for ( int i = 1; i <= 10; i += 1 ) {
     39            sout | next(&f1) | ' ' | next(&f2) | endl;
     40      }
     41
     42      return 0;
    5643}
    57 
    58 // Local Variables: //
    59 // tab-width: 4 //
    60 // compile-command: "cfa fibonacci.c" //
    61 // End: //
  • src/tests/io.c

    r436c0de rade20d0  
    1010// Created On       : Wed Mar  2 16:56:02 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jun  8 09:52:10 2017
    13 // Update Count     : 51
     12// Last Modified On : Tue Mar 21 22:36:06 2017
     13// Update Count     : 48
    1414//
    1515
     
    1717
    1818int main() {
    19         char c;                                                                                         // basic types
     19        char c;                                                                                                         // basic types
    2020        short int si;
    2121        unsigned short int usi;
     
    3232        double _Complex dc;
    3333        long double _Complex ldc;
    34         enum { size = 10 };
    35         char s1[size], s2[size];
     34        char s1[10], s2[10];
    3635
    3736        int x = 3, y = 5, z = 7;
     
    4241        sout | endl;
    4342
     43        ifstream in;                                                                                            // create / open file
     44        open( &in, "io.data", "r" );
     45
     46        &in | &c                                                                                                        // character
     47                | &si | &usi | &i | &ui | &li | &uli | &lli | &ulli             // integral
     48                | &f | &d | &ld                                                                                 // floating point
     49                | &fc | &dc | &ldc                                                                              // floating-point complex
     50                | cstr( s1 ) | cstr( s2, 10 );                                                  // C string, length unchecked and checked
     51
     52        sout | c | ' ' | endl                                                                           // character
     53                 | si | usi | i | ui | li | uli | lli | ulli | endl             // integral
     54                 | f | d | ld | endl                                                                    // floating point
     55                 | fc | dc | ldc | endl;                                                                // complex
     56        sout | endl;
     57        sout | f | "" | d | "" | ld | endl                                                      // floating point without separator
     58                 | sepDisable | fc | dc | ldc | sepEnable | endl                // complex without separator
     59                 | sepOn | s1 | sepOff | s2 | endl                                              // local separator removal
     60                 | s1 | "" | s2 | endl;                                                                 // C string without separator
     61        sout | endl;
     62
     63        sepSet( sout, ", $" );                                                                          // change separator, maximum of 15 characters
     64        sout | f | d | ld | endl
     65                 | fc | dc | ldc | endl
     66                 | s1 | s2 | endl;
     67        sout | endl;
     68        sepSet( sout, " " );
     69
    4470        sout
    4571                // opening delimiters
    46                 | "x (" | 1
    47                 | "x [" | 2
    48                 | "x {" | 3
    49                 | "x =" | 4
    50                 | "x $" | 5
    51                 | "x £" | 6
    52                 | "x ¥" | 7
    53                 | "x ¡" | 8
    54                 | "x ¿" | 9
    55                 | "x «" | 10
     72                | "v(" | 27
     73                | "v[" | 27
     74                | "v{" | 27
     75                | "$" | 27
     76                | "=" | 27
     77                | "£" | 27
     78                | "¥" | 27
     79                | "¡" | 27
     80                | "¿" | 27
     81                | "«" | 27
     82                | endl
     83                // closing delimiters
     84                | 25 | ","
     85                | 25 | "."
     86                | 25 | ":"
     87                | 25 | ";"
     88                | 25 | "!"
     89                | 25 | "?"
     90                | 25 | "%"
     91                | 25 | "¢"
     92                | 25 | "»"
     93                | 25 | ")"
     94                | 25 | "]"
     95                | 25 | "}"
     96                | endl
     97                // opening-closing delimiters
     98                | 25 | "'" | 27
     99                | 25 | "`" | 27
     100                | 25 | "\"" | 27
     101                | 25 | " " | 27
     102                | 25 | "\f" | 27
     103                | 25 | "\n" | 27
     104                | 25 | "\r" | 27
     105                | 25 | "\t" | 27
     106                | 25 | "\v" | 27
    56107                | endl;
    57         sout
    58                 // closing delimiters
    59                 | 1 | ", x"
    60                 | 2 | ". x"
    61                 | 3 | "; x"
    62                 | 4 | "! x"
    63                 | 5 | "? x"
    64                 | 6 | "% x"
    65                 | 7 | "¢ x"
    66                 | 8 | "» x"
    67                 | 9 | ") x"
    68                 | 10 | "] x"
    69                 | 11 | "} x"
    70                 | endl;
    71         sout
    72                 // opening-closing delimiters
    73                 | "x`" | 1 | "`x'" | 2
    74                 | "'x\"" | 3 | "\"x:" | 4
    75                 | ":x " | 5 | " x\t" | 6
    76                 | "\tx\f" | 7 | "\fx\v" | 8
    77                 | "\vx\n" | 9 | "\nx\r" | 10
    78                 | "\rx" |
    79                 endl;
    80         sout | "x ( " | 1 | " ) x" | 2 | " , x" | 3 | " :x: " | 4 | endl;
    81108
    82         ifstream in;                                                                            // create / open file
    83         open( &in, "io.data", "r" );
    84 
    85         &in | &c                                                                                        // character
    86                 | &si | &usi | &i | &ui | &li | &uli | &lli | &ulli     // integral
    87                 | &f | &d | &ld                                                                 // floating point
    88                 | &fc | &dc | &ldc                                                              // floating-point complex
    89                 | cstr( s1 ) | cstr( s2, size );                                // C string, length unchecked and checked
    90 
    91         sout | c | ' ' | endl                                                           // character
    92                 | si | usi | i | ui | li | uli | lli | ulli | endl // integral
    93                 | f | d | ld | endl                                                             // floating point
    94                 | fc | dc | ldc | endl;                                                 // complex
    95         sout | endl;
    96         sout | f | "" | d | "" | ld | endl                                      // floating point without separator
    97                 | sepDisable | fc | dc | ldc | sepEnable | endl // complex without separator
    98                 | sepOn | s1 | sepOff | s2 | endl                               // local separator removal
    99                 | s1 | "" | s2 | endl;                                                  // C string without separator
    100         sout | endl;
    101 
    102         sepSet( sout, ", $" );                                                          // change separator, maximum of 15 characters
    103         sout | f | d | ld | endl
    104                 | fc | dc | ldc | endl
    105                 | s1 | s2 | endl;
    106         sout | endl;
    107 
    108         [int, int] t1 = [1, 2], t2 = [3, 4];
    109         sout | t1 | t2 | endl;                                                          // print tuple
    110 
    111         sepSet( sout, " " );
    112         sepSet( sout, ", $" );                                                          // set separator from " " to ", $"
    113         sout | 1 | 2 | 3 | " \"" | sepGet( sout ) | "\"" | endl;
    114         sepSet( sout, " " );                                                            // reset separator to " "
    115         sout | 1 | 2 | 3 | " \"" | sepGet( sout ) | "\"" | endl;
    116 
    117         sout | sepOn | 1 | 2 | 3 | sepOn | endl;                        // separator at start of line
    118         sout | 1 | sepOff | 2 | 3 | endl;                                       // locally turn off implicit separator
    119 
    120         sout | sepDisable | 1 | 2 | 3 | endl;                           // globally turn off implicit separation
    121         sout | 1 | sepOn | 2 | 3 | endl;                                        // locally turn on implicit separator
    122         sout | sepEnable | 1 | 2 | 3 | endl;                            // globally turn on implicit separation
    123 
    124         sepSetTuple( sout, " " );                                                       // set tuple separator from ", " to " "
    125         sout | t1 | t2 | " \"" | sepGetTuple( sout ) | "\"" | endl;
    126         sepSetTuple( sout, ", " );                                                      // reset tuple separator to ", "
    127         sout | t1 | t2 | " \"" | sepGetTuple( sout ) | "\"" | endl;
    128 
    129         sout | t1 | t2 | endl;                                                          // print tuple
    130 
    131         [int, int, const char *, double] t3 = { 3, 4, "a", 7.2 };
     109        [int, int, const char *, double] t = { 3, 4, "a", 7.2 };
    132110        sout | [ 3, 4, "a", 7.2 ] | endl;
    133         sout | t3 | endl;
     111        sout | t | endl;
    134112        sepSetTuple( sout, " " );
    135         sout | t3 | endl;
    136         sout | sepOn | t3 | sepDisable | t3 | sepEnable | t3 | endl;
     113        sout | t | endl;
     114        sout | sepOn | t | sepDisable | t | sepEnable | t | endl;
    137115        sepSet( sout, "^" );
    138116        sepSetTuple( sout, "-" );
    139         sout | t3 | 3 | 4 | t3 | endl;
     117        sout | t | 3 | 4 | t | endl;
    140118}
    141119
  • tools/cfa.nanorc

    r436c0de rade20d0  
    3333## Update/Redistribute
    3434# GCC builtins
    35 color cyan "__attribute__[[:space:]]*\(\([^()]*(\([^()]*\)[^()]*)*\)\)"
    36 ##color cyan "__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__"
     35##color cyan "__attribute__[[:space:]]*\(\([^)]*\)\)" "__(aligned|asm|builtin|hidden|inline|packed|restrict|section|typeof|weak)__"
    3736
    3837# Preprocesser Directives
Note: See TracChangeset for help on using the changeset viewer.