Changes in / [69c37cc:f343c6b]


Ignore:
Files:
49 added
14 deleted
92 edited

Legend:

Unmodified
Added
Removed
  • benchmark/Makefile.am

    r69c37cc rf343c6b  
    2121include $(top_srcdir)/src/cfa.make
    2222
    23 AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread
    24 AM_CFAFLAGS = -quiet -in-tree -nodebug
    25 AM_UPPFLAGS = -quiet -nodebug -multi
     23AM_CFLAGS = -O2 -Wall -Wextra -Werror -I$(srcdir) -lrt -pthread
     24AM_CFAFLAGS = -quiet -nodebug -in-tree
     25AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14
    2626
    2727BENCH_V_CC = $(__bench_v_CC_$(__quiet))
     
    139139        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
    140140
     141tls-fetch_add$(EXEEXT):
     142        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
     143
    141144## =========================================================================================================
    142145CTXSWITCH_DEPEND  =                 \
     
    144147        function.run                    \
    145148        fetch_add.run                   \
     149        tls-fetch_add.run                       \
    146150        ctxswitch-pthread.run           \
    147151        ctxswitch-cfa_coroutine.run     \
  • benchmark/Makefile.in

    r69c37cc rf343c6b  
    371371
    372372# applies to both programs
    373 AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread
    374 AM_CFAFLAGS = -quiet -in-tree -nodebug
    375 AM_UPPFLAGS = -quiet -nodebug -multi
     373AM_CFLAGS = -O2 -Wall -Wextra -Werror -I$(srcdir) -lrt -pthread
     374AM_CFAFLAGS = -quiet -nodebug -in-tree
     375AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14
    376376BENCH_V_CC = $(__bench_v_CC_$(__quiet))
    377377BENCH_V_CFA = $(__bench_v_CFA_$(__quiet))
     
    402402dummy_SOURCES = dummyC.c dummyCXX.cpp
    403403CTXSWITCH_DEPEND = loop.run function.run fetch_add.run \
    404         ctxswitch-pthread.run ctxswitch-cfa_coroutine.run \
    405         ctxswitch-cfa_thread.run ctxswitch-cfa_thread2.run \
    406         ctxswitch-upp_coroutine.run ctxswitch-upp_thread.run \
    407         ctxswitch-goroutine.run ctxswitch-java_thread.run \
    408         $(am__append_1)
     404        tls-fetch_add.run ctxswitch-pthread.run \
     405        ctxswitch-cfa_coroutine.run ctxswitch-cfa_thread.run \
     406        ctxswitch-cfa_thread2.run ctxswitch-upp_coroutine.run \
     407        ctxswitch-upp_thread.run ctxswitch-goroutine.run \
     408        ctxswitch-java_thread.run $(am__append_1)
    409409testdir = $(top_srcdir)/tests
    410410all: all-am
     
    799799        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
    800800
     801tls-fetch_add$(EXEEXT):
     802        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
     803
    801804@WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre$(EXEEXT):
    802805@WITH_LIBFIBRE_TRUE@    $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp  -I$(LIBFIBRE_DIR) -lfibre
  • configure

    r69c37cc rf343c6b  
    1673816738
    1673916739#==============================================================================
    16740 ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile tests/preempt_longrun/Makefile tools/Makefile tools/prettyprinter/Makefile"
     16740ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile longrun_tests/Makefile tools/Makefile tools/prettyprinter/Makefile"
    1674116741
    1674216742
     
    1787617876    "benchmark/Makefile") CONFIG_FILES="$CONFIG_FILES benchmark/Makefile" ;;
    1787717877    "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;;
    17878     "tests/preempt_longrun/Makefile") CONFIG_FILES="$CONFIG_FILES tests/preempt_longrun/Makefile" ;;
     17878    "longrun_tests/Makefile") CONFIG_FILES="$CONFIG_FILES longrun_tests/Makefile" ;;
    1787917879    "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
    1788017880    "tools/prettyprinter/Makefile") CONFIG_FILES="$CONFIG_FILES tools/prettyprinter/Makefile" ;;
  • configure.ac

    r69c37cc rf343c6b  
    211211        benchmark/Makefile
    212212        tests/Makefile
    213         tests/preempt_longrun/Makefile
     213        longrun_tests/Makefile
    214214        tools/Makefile
    215215        tools/prettyprinter/Makefile
  • doc/bibliography/pl.bib

    r69c37cc rf343c6b  
    11631163    title       = {Checked C: Making C Safe by Extension},
    11641164    booktitle   = {2018 IEEE Cybersecurity Development (SecDev)},
    1165     year = {2018},
    1166     month = {September},
    1167     pages = {53-60},
    1168     publisher = {IEEE},
    1169     url = {https://www.microsoft.com/en-us/research/publication/checkedc-making-c-safe-by-extension/},
     1165    year        = {2018},
     1166    month       = {September},
     1167    pages       = {53-60},
     1168    publisher   = {IEEE},
     1169    url         = {https://www.microsoft.com/en-us/research/publication/checkedc-making-c-safe-by-extension/},
    11701170}
    11711171
    11721172@misc{Clang,
    1173     keywords = {clang},
    1174     contributer = {a3moss@uwaterloo.ca},
    1175     title = {Clang: a {C} language family frontend for {LLVM}},
    1176     howpublished = {\href{https://clang.llvm.org/}{https://\-clang.llvm.org/}}
     1173    keywords    = {clang},
     1174    contributer = {a3moss@uwaterloo.ca},
     1175    title       = {Clang: a {C} language family frontend for {LLVM}},
     1176    howpublished= {\href{https://clang.llvm.org/}{https://\-clang.llvm.org/}}
    11771177}
    11781178
     
    23472347}
    23482348
     2349@article{Ritchie93,
     2350    keywords    = {C, history},
     2351    contributer = {pabuhr@plg},
     2352    author      = {Ritchie, Dennis M.},
     2353    title       = {The Development of the {C} Language},
     2354    journal     = sigplan,
     2355    volume      = 28,
     2356    number      = 3,
     2357    month       = mar,
     2358    year        = 1993,
     2359    pages       = {201--208},
     2360    url         = {http://doi.acm.org/10.1145/155360.155580},
     2361    publisher   = {ACM},
     2362    address     = {New York, NY, USA},
     2363}
     2364
    23492365@article{design,
    23502366    keywords    = {Smalltalk, designing classes},
     
    23542370    journal     = joop,
    23552371    year        = 1988,
    2356     volume      = 1, number = 2, pages = {22-35},
     2372    volume      = 1,
     2373    number      = 2,
     2374    pages       = {22-35},
    23572375    comment     = {
    23582376        Abstract classes represent standard protocols.  ``It is better to
     
    37893807    optaddress  = {Waterloo, Ontario, Canada, N2L 3G1},
    37903808    note        = {\href{https://uwspace.uwaterloo.ca/handle/10012/13935}{https://\-uwspace.uwaterloo.ca/\-handle/\-10012/\-13935}},
     3809}
     3810
     3811@article{Swift05,
     3812   contributer  = {pabuhr@plg},
     3813   author       = {Michael M. Swift and Brian N. Bershad and Henry M. Levy},
     3814   title        = {Improving the Reliability of Commodity Operating Systems},
     3815   journal      = tocs,
     3816   volume       = 23,
     3817   number       = 1,
     3818   month        = feb,
     3819   year         = 2005,
     3820   pages        = {77-110},
    37913821}
    37923822
  • doc/papers/concurrency/Paper.tex

    r69c37cc rf343c6b  
    215215{}
    216216\lstnewenvironment{Go}[1][]
    217 {\lstset{#1}}
     217{\lstset{language=go,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
     218{}
     219\lstnewenvironment{python}[1][]
     220{\lstset{language=python,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}}
    218221{}
    219222
     
    228231}
    229232
    230 \title{\texorpdfstring{Advanced Control-flow in \protect\CFA}{Advanced Control-flow in Cforall}}
     233\title{\texorpdfstring{Advanced Control-flow and Concurrency in \protect\CFA}{Advanced Control-flow in Cforall}}
    231234
    232235\author[1]{Thierry Delisle}
     
    242245\abstract[Summary]{
    243246\CFA is a modern, polymorphic, non-object-oriented, backwards-compatible extension of the C programming language.
    244 This paper discusses the advanced control-flow features in \CFA, which include concurrency and parallelism, and its supporting runtime system.
    245 These features are created from scratch as ISO C's concurrency is low-level and unimplemented, so C programmers continue to rely on the C pthreads library.
    246 \CFA provides high-level control-flow mechanisms, like coroutines and user-level threads, and monitors for mutual exclusion and synchronization.
    247 A unique contribution of this work is allowing multiple monitors to be safely acquired \emph{simultaneously} (deadlock free), while integrating this capability with all monitor synchronization mechanisms.
    248 All features respect the expectations of C programmers, while being fully integrate with the \CFA polymorphic type-system and other language features.
     247This paper discusses some advanced control-flow and concurrency/parallelism features in \CFA, along with the supporting runtime.
     248These features are created from scratch because they do not exist in ISO C, or are low-level and/or unimplemented, so C programmers continue to rely on library features, like C pthreads.
     249\CFA introduces language-level control-flow mechanisms, like coroutines, user-level threading, and monitors for mutual exclusion and synchronization.
     250A unique contribution of this work is allowing multiple monitors to be safely acquired \emph{simultaneously} (deadlock free), while integrating this capability with monitor synchronization mechanisms.
     251These features also integrate with the \CFA polymorphic type-system and exception handling, while respecting the expectations and style of C programmers.
    249252Experimental results show comparable performance of the new features with similar mechanisms in other concurrent programming-languages.
    250253}%
     
    261264\section{Introduction}
    262265
    263 This paper discusses the design of advanced, high-level control-flow extensions (especially concurrency and parallelism) in \CFA and its runtime.
     266This paper discusses the design of language-level control-flow and concurrency/parallelism extensions in \CFA and its runtime.
    264267\CFA is a modern, polymorphic, non-object-oriented\footnote{
    265268\CFA has features often associated with object-oriented programming languages, such as constructors, destructors, virtuals and simple inheritance.
    266269However, functions \emph{cannot} be nested in structures, so there is no lexical binding between a structure and set of functions (member/method) implemented by an implicit \lstinline@this@ (receiver) parameter.},
    267270backwards-compatible extension of the C programming language~\cite{Moss18}.
    268 Within the \CFA framework, new control-flow features were created from scratch.
    269 ISO \Celeven defines only a subset of the \CFA extensions, and with respect to concurrency~\cite[\S~7.26]{C11}, the features are largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}.
    270 Furthermore, \Celeven and pthreads concurrency is basic, based on thread fork/join in a function and a few locks, which is low-level and error prone;
    271 no high-level language concurrency features exist.
    272 Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-8 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C concurrency approach.
    273 Finally, while the \Celeven standard does not state a concurrent threading-model, the historical association with pthreads suggests the threading model is kernel-level threading (1:1)~\cite{ThreadModel}.
     271Within the \CFA framework, new control-flow features are created from scratch.
     272ISO \Celeven defines only a subset of the \CFA extensions, where the overlapping features are concurrency~\cite[\S~7.26]{C11}.
     273However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}.
     274Furthermore, \Celeven and pthreads concurrency is simple, based on thread fork/join in a function and a few locks, which is low-level and error prone;
     275no high-level language concurrency features are defined.
     276Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-8 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach.
     277Finally, while the \Celeven standard does not state a concurrent threading-model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}.
    274278
    275279In contrast, there has been a renewed interest during the past decade in user-level (M:N, green) threading in old and new programming languages.
     
    284288
    285289A further effort over the past decade is the development of language memory-models to deal with the conflict between certain language features and compiler/hardware optimizations.
    286 This issue can be rephrased as some features are pervasive (language and runtime) and cannot be safely added via a library to prevent invalidation by sequential optimizations~\cite{Buhr95a,Boehm05}.
     290This issue can be rephrased as: some language features are pervasive (language and runtime) and cannot be safely added via a library to prevent invalidation by sequential optimizations~\cite{Buhr95a,Boehm05}.
    287291The consequence is that a language must be cognizant of these features and provide sufficient tools to program around any safety issues.
    288292For example, C created the @volatile@ qualifier to provide correct execution for @setjmp@/@logjmp@ (concurrency came later).
    289 The simplest solution is to provide a handful of complex qualifiers and functions (e.g., @volatile@ and atomics) allowing programmers to write consistent/race-free programs, often in the sequentially-consistent memory-model~\cite{Boehm12}.
     293The common solution is to provide a handful of complex qualifiers and functions (e.g., @volatile@ and atomics) allowing programmers to write consistent/race-free programs, often in the sequentially-consistent memory-model~\cite{Boehm12}.
    290294
    291295While having a sufficient memory-model allows sound libraries to be constructed, writing these libraries can quickly become awkward and error prone, and using these low-level libraries has the same issues.
    292296Essentially, using low-level explicit locks is the concurrent equivalent of assembler programming.
    293 Just as most assembler programming is replaced with programming in a high-level language, explicit locks can be replaced with high-level concurrency constructs in a programming language.
    294 The goal is to get the compiler to check for correct usage and follow any complex coding conventions implicitly.
     297Just as most assembler programming is replaced with high-level programming, explicit locks can be replaced with high-level concurrency in a programming language.
     298Then the goal is for the compiler to check for correct usage and follow any complex coding conventions implicitly.
    295299The drawback is that language constructs may preclude certain specialized techniques, therefore introducing inefficiency or inhibiting concurrency.
    296300For most concurrent programs, these drawbacks are insignificant in comparison to the speed of composition, and subsequent reliability and maintainability of the high-level concurrent program.
     
    299303As stated, this observation applies to non-concurrent forms of complex control-flow, like exception handling and coroutines.
    300304
    301 Adapting the programming language allows matching the control-flow model with the programming-language style, versus adapting to one general (sound) library/paradigm.
     305Adapting the programming language to these features also allows matching the control-flow model with the programming-language style, versus adopting one general (sound) library/paradigm.
    302306For example, it is possible to provide exceptions, coroutines, monitors, and tasks as specialized types in an object-oriented language, integrating these constructs to allow leveraging the type-system (static type-checking) and all other object-oriented capabilities~\cite{uC++}.
    303307It is also possible to leverage call/return for blocking communication via new control structures, versus switching to alternative communication paradigms, like channels or message passing.
     
    307311however, the reverse is seldom true, i.e., given implicit concurrency, e.g., actors, it is virtually impossible to create explicit concurrency, e.g., blocking thread objects.}
    308312Finally, with extended language features and user-level threading it is possible to discretely fold locking and non-blocking I/O multiplexing into the language's I/O libraries, so threading implicitly dovetails with the I/O subsystem.
    309 
    310 \CFA embraces language extensions and user-level threading to provide advanced control-flow and concurrency.
    311 We attempt to show the \CFA extensions and runtime are demonstrably better than those proposed for \CC and other concurrent, imperative programming languages.
    312 The contributions of this work are:
     313\CFA embraces language extensions and user-level threading to provide advanced control-flow (exception handling\footnote{
     314\CFA exception handling will be presented in a separate paper.
     315The key feature that dovetails with this paper is non-local exceptions allowing exceptions to be raised across stacks, with synchronous exceptions raised among coroutines and asynchronous exceptions raised among threads, similar to that in \uC~\cite[\S~5]{uC++}
     316} and coroutines) and concurrency.
     317
     318Most augmented traditional (Fortran 18~\cite{Fortran18}, Cobol 14~\cite{Cobol14}, Ada 12~\cite{Ada12}, Java 11~\cite{Java11}) and new languages (Go~\cite{Go}, Rust~\cite{Rust}, and D~\cite{D}), except \CC, diverge from C with different syntax and semantics, only interoperate indirectly with C, and are not systems languages, for those with managed memory.
     319As a result, there is a significant learning curve to move to these languages, and C legacy-code must be rewritten.
     320While \CC, like \CFA, takes an evolutionary approach to extend C, \CC's constantly growing complex and interdependent features-set (e.g., objects, inheritance, templates, etc.) mean idiomatic \CC code is difficult to use from C, and C programmers must expend significant effort learning \CC.
     321Hence, rewriting and retraining costs for these languages, even \CC, are prohibitive for companies with a large C software-base.
     322\CFA with its orthogonal feature-set, its high-performance runtime, and direct access to all existing C libraries circumvents these problems.
     323
     324We present comparative examples so the reader can judge if the \CFA control-flow extensions are equivalent or better than those in or proposed for \Celeven, \CC and other concurrent, imperative programming languages, and perform experiments to show the \CFA runtime is competitive with other similar mechanisms.
     325The detailed contributions of this work are:
    313326\begin{itemize}
    314327\item
     
    615628
    616629
    617 \section{Coroutines: A Stepping Stone}\label{coroutine}
    618 
    619 Advanced controlWhile the focus of this discussion is concurrency and parallelism, it is important to address coroutines, which are a significant building block of a concurrency system (but not concurrent among themselves).
     630\section{Coroutines: Stepping Stone}
     631\label{coroutine}
     632
    620633Coroutines are generalized routines allowing execution to be temporarily suspended and later resumed.
    621634Hence, unlike a normal routine, a coroutine may not terminate when it returns to its caller, allowing it to be restarted with the values and execution location present at the point of suspension.
     
    641654\centering
    642655\newbox\myboxA
     656% \begin{lrbox}{\myboxA}
     657% \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     658% `int fn1, fn2, state = 1;`   // single global variables
     659% int fib() {
     660%       int fn;
     661%       `switch ( state )` {  // explicit execution state
     662%         case 1: fn = 0;  fn1 = fn;  state = 2;  break;
     663%         case 2: fn = 1;  fn2 = fn1;  fn1 = fn;  state = 3;  break;
     664%         case 3: fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;  break;
     665%       }
     666%       return fn;
     667% }
     668% int main() {
     669%
     670%       for ( int i = 0; i < 10; i += 1 ) {
     671%               printf( "%d\n", fib() );
     672%       }
     673% }
     674% \end{cfa}
     675% \end{lrbox}
    643676\begin{lrbox}{\myboxA}
    644677\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    645 `int f1, f2, state = 1;`   // single global variables
    646 int fib() {
    647         int fn;
    648         `switch ( state )` {  // explicit execution state
    649           case 1: fn = 0;  f1 = fn;  state = 2;  break;
    650           case 2: fn = 1;  f2 = f1;  f1 = fn;  state = 3;  break;
    651           case 3: fn = f1 + f2;  f2 = f1;  f1 = fn;  break;
    652         }
    653         return fn;
    654 }
     678#define FIB_INIT { 0, 1 }
     679typedef struct { int fn1, fn; } Fib;
     680int fib( Fib * f ) {
     681
     682        int ret = f->fn1;
     683        f->fn1 = f->fn;
     684        f->fn = ret + f->fn;
     685        return ret;
     686}
     687
     688
     689
    655690int main() {
    656 
     691        Fib f1 = FIB_INIT, f2 = FIB_INIT;
    657692        for ( int i = 0; i < 10; i += 1 ) {
    658                 printf( "%d\n", fib() );
     693                printf( "%d %d\n",
     694                                fib( &f1 ), fib( &f2 ) );
    659695        }
    660696}
     
    665701\begin{lrbox}{\myboxB}
    666702\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    667 #define FIB_INIT `{ 0, 1 }`
    668 typedef struct { int f2, f1; } Fib;
    669 int fib( Fib * f ) {
    670 
    671         int ret = f->f2;
    672         int fn = f->f1 + f->f2;
    673         f->f2 = f->f1; f->f1 = fn;
    674 
    675         return ret;
    676 }
    677 int main() {
    678         Fib f1 = FIB_INIT, f2 = FIB_INIT;
    679         for ( int i = 0; i < 10; i += 1 ) {
    680                 printf( "%d %d\n", fib( &f1 ), fib( &f2 ) );
     703`coroutine` Fib { int fn1; };
     704void main( Fib & fib ) with( fib ) {
     705        int fn;
     706        [fn1, fn] = [0, 1];
     707        for () {
     708                `suspend();`
     709                [fn1, fn] = [fn, fn1 + fn];
    681710        }
    682711}
    683 \end{cfa}
    684 \end{lrbox}
    685 
    686 \subfloat[3 States: global variables]{\label{f:GlobalVariables}\usebox\myboxA}
    687 \qquad
    688 \subfloat[1 State: external variables]{\label{f:ExternalState}\usebox\myboxB}
    689 \caption{C Fibonacci Implementations}
    690 \label{f:C-fibonacci}
    691 
    692 \bigskip
    693 
    694 \newbox\myboxA
    695 \begin{lrbox}{\myboxA}
    696 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    697 `coroutine` Fib { int fn; };
    698 void main( Fib & fib ) with( fib ) {
    699         int f1, f2;
    700         fn = 0;  f1 = fn;  `suspend()`;
    701         fn = 1;  f2 = f1;  f1 = fn;  `suspend()`;
    702         for ( ;; ) {
    703                 fn = f1 + f2;  f2 = f1;  f1 = fn;  `suspend()`;
    704         }
    705 }
    706 int next( Fib & fib ) with( fib ) {
    707         `resume( fib );`
    708         return fn;
     712int ?()( Fib & fib ) with( fib ) {
     713        `resume( fib );`  return fn1;
    709714}
    710715int main() {
    711716        Fib f1, f2;
    712         for ( int i = 1; i <= 10; i += 1 ) {
    713                 sout | next( f1 ) | next( f2 );
    714         }
    715 }
     717        for ( 10 ) {
     718                sout | f1() | f2();
     719}
     720
     721
    716722\end{cfa}
    717723\end{lrbox}
    718 \newbox\myboxB
    719 \begin{lrbox}{\myboxB}
    720 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    721 `coroutine` Fib { int ret; };
    722 void main( Fib & f ) with( fib ) {
    723         int fn, f1 = 1, f2 = 0;
    724         for ( ;; ) {
    725                 ret = f2;
    726 
    727                 fn = f1 + f2;  f2 = f1;  f1 = fn; `suspend();`
    728         }
    729 }
    730 int next( Fib & fib ) with( fib ) {
    731         `resume( fib );`
    732         return ret;
    733 }
    734 
    735 
    736 
    737 
    738 
    739 
    740 \end{cfa}
     724
     725\newbox\myboxC
     726\begin{lrbox}{\myboxC}
     727\begin{python}[aboveskip=0pt,belowskip=0pt]
     728
     729def Fib():
     730
     731    fn1, fn = 0, 1
     732    while True:
     733        `yield fn1`
     734        fn1, fn = fn, fn1 + fn
     735
     736
     737// next prewritten
     738
     739
     740f1 = Fib()
     741f2 = Fib()
     742for i in range( 10 ):
     743        print( next( f1 ), next( f2 ) )
     744
     745
     746
     747\end{python}
    741748\end{lrbox}
    742 \subfloat[3 States, internal variables]{\label{f:Coroutine3States}\usebox\myboxA}
    743 \qquad\qquad
    744 \subfloat[1 State, internal variables]{\label{f:Coroutine1State}\usebox\myboxB}
    745 \caption{\CFA Coroutine Fibonacci Implementations}
    746 \label{f:cfa-fibonacci}
     749
     750\subfloat[C]{\label{f:GlobalVariables}\usebox\myboxA}
     751\hspace{3pt}
     752\vrule
     753\hspace{3pt}
     754\subfloat[\CFA]{\label{f:ExternalState}\usebox\myboxB}
     755\hspace{3pt}
     756\vrule
     757\hspace{3pt}
     758\subfloat[Python]{\label{f:ExternalState}\usebox\myboxC}
     759\caption{Fibonacci Generator}
     760\label{f:C-fibonacci}
     761
     762% \bigskip
     763%
     764% \newbox\myboxA
     765% \begin{lrbox}{\myboxA}
     766% \begin{cfa}[aboveskip=0pt,belowskip=0pt]
     767% `coroutine` Fib { int fn; };
     768% void main( Fib & fib ) with( fib ) {
     769%       fn = 0;  int fn1 = fn; `suspend()`;
     770%       fn = 1;  int fn2 = fn1;  fn1 = fn; `suspend()`;
     771%       for () {
     772%               fn = fn1 + fn2; fn2 = fn1; fn1 = fn; `suspend()`; }
     773% }
     774% int next( Fib & fib ) with( fib ) { `resume( fib );` return fn; }
     775% int main() {
     776%       Fib f1, f2;
     777%       for ( 10 )
     778%               sout | next( f1 ) | next( f2 );
     779% }
     780% \end{cfa}
     781% \end{lrbox}
     782% \newbox\myboxB
     783% \begin{lrbox}{\myboxB}
     784% \begin{python}[aboveskip=0pt,belowskip=0pt]
     785%
     786% def Fibonacci():
     787%       fn = 0; fn1 = fn; `yield fn`  # suspend
     788%       fn = 1; fn2 = fn1; fn1 = fn; `yield fn`
     789%       while True:
     790%               fn = fn1 + fn2; fn2 = fn1; fn1 = fn; `yield fn`
     791%
     792%
     793% f1 = Fibonacci()
     794% f2 = Fibonacci()
     795% for i in range( 10 ):
     796%       print( `next( f1 )`, `next( f2 )` ) # resume
     797%
     798% \end{python}
     799% \end{lrbox}
     800% \subfloat[\CFA]{\label{f:Coroutine3States}\usebox\myboxA}
     801% \qquad
     802% \subfloat[Python]{\label{f:Coroutine1State}\usebox\myboxB}
     803% \caption{Fibonacci input coroutine, 3 states, internal variables}
     804% \label{f:cfa-fibonacci}
    747805\end{figure}
    748806
     
    784842\begin{lrbox}{\myboxA}
    785843\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    786 `coroutine` Format {
    787         char ch;   // used for communication
    788         int g, b;  // global because used in destructor
     844`coroutine` Fmt {
     845        char ch;   // communication variables
     846        int g, b;   // needed in destructor
    789847};
    790 void main( Format & fmt ) with( fmt ) {
    791         for ( ;; ) {
    792                 for ( g = 0; g < 5; g += 1 ) {      // group
    793                         for ( b = 0; b < 4; b += 1 ) { // block
     848void main( Fmt & fmt ) with( fmt ) {
     849        for () {
     850                for ( g = 0; g < 5; g += 1 ) { // groups
     851                        for ( b = 0; b < 4; b += 1 ) { // blocks
    794852                                `suspend();`
    795                                 sout | ch;              // separator
    796                         }
    797                         sout | "  ";               // separator
    798                 }
    799                 sout | nl;
    800         }
    801 }
    802 void ?{}( Format & fmt ) { `resume( fmt );` }
    803 void ^?{}( Format & fmt ) with( fmt ) {
    804         if ( g != 0 || b != 0 ) sout | nl;
    805 }
    806 void format( Format & fmt ) {
    807         `resume( fmt );`
    808 }
     853                                sout | ch; } // print character
     854                        sout | "  "; } // block separator
     855                sout | nl; }  // group separator
     856}
     857void ?{}( Fmt & fmt ) { `resume( fmt );` } // prime
     858void ^?{}( Fmt & fmt ) with( fmt ) { // destructor
     859        if ( g != 0 || b != 0 ) // special case
     860                sout | nl; }
     861void send( Fmt & fmt, char c ) { fmt.ch = c; `resume( fmt )`; }
    809862int main() {
    810         Format fmt;
    811         eof: for ( ;; ) {
    812                 sin | fmt.ch;
    813           if ( eof( sin ) ) break eof;
    814                 format( fmt );
    815         }
     863        Fmt fmt;
     864        sout | nlOff;   // turn off auto newline
     865        for ( 41 )
     866                send( fmt, 'a' );
    816867}
    817868\end{cfa}
     
    820871\newbox\myboxB
    821872\begin{lrbox}{\myboxB}
    822 \begin{cfa}[aboveskip=0pt,belowskip=0pt]
    823 struct Format {
    824         char ch;
    825         int g, b;
    826 };
    827 void format( struct Format * fmt ) {
    828         if ( fmt->ch != -1 ) {      // not EOF ?
    829                 printf( "%c", fmt->ch );
    830                 fmt->b += 1;
    831                 if ( fmt->b == 4 ) {  // block
    832                         printf( "  " );      // separator
    833                         fmt->b = 0;
    834                         fmt->g += 1;
    835                 }
    836                 if ( fmt->g == 5 ) {  // group
    837                         printf( "\n" );     // separator
    838                         fmt->g = 0;
    839                 }
    840         } else {
    841                 if ( fmt->g != 0 || fmt->b != 0 ) printf( "\n" );
    842         }
    843 }
    844 int main() {
    845         struct Format fmt = { 0, 0, 0 };
    846         for ( ;; ) {
    847                 scanf( "%c", &fmt.ch );
    848           if ( feof( stdin ) ) break;
    849                 format( &fmt );
    850         }
    851         fmt.ch = -1;
    852         format( &fmt );
    853 }
    854 \end{cfa}
     873\begin{python}[aboveskip=0pt,belowskip=0pt]
     874
     875
     876
     877def Fmt():
     878        try:
     879                while True:
     880                        for g in range( 5 ):
     881                                for b in range( 4 ):
     882
     883                                        print( `(yield)`, end='' )
     884                                print( '  ', end='' )
     885                        print()
     886
     887
     888        except GeneratorExit:
     889                if g != 0 | b != 0:
     890                        print()
     891
     892
     893fmt = Fmt()
     894`next( fmt )`                    # prime
     895for i in range( 41 ):
     896        `fmt.send( 'a' );`      # send to yield
     897
     898\end{python}
    855899\end{lrbox}
    856 \subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA}
     900\subfloat[\CFA]{\label{f:CFAFmt}\usebox\myboxA}
    857901\qquad
    858 \subfloat[C Linearized]{\label{f:CFmt}\usebox\myboxB}
    859 \caption{Formatting text into lines of 5 blocks of 4 characters.}
     902\subfloat[Python]{\label{f:CFmt}\usebox\myboxB}
     903\caption{Output formatting text}
    860904\label{f:fmt-line}
    861905\end{figure}
     
    878922void main( Prod & prod ) with( prod ) {
    879923        // 1st resume starts here
    880         for ( int i = 0; i < N; i += 1 ) {
     924        for ( i; N ) {
    881925                int p1 = random( 100 ), p2 = random( 100 );
    882926                sout | p1 | " " | p2;
     
    894938}
    895939void start( Prod & prod, int N, Cons &c ) {
    896         &prod.c = &c;
     940        &prod.c = &c; // reassignable reference
    897941        prod.[N, receipt] = [N, 0];
    898942        `resume( prod );`
     
    909953        Prod & p;
    910954        int p1, p2, status;
    911         _Bool done;
     955        bool done;
    912956};
    913957void ?{}( Cons & cons, Prod & p ) {
    914         &cons.p = &p;
     958        &cons.p = &p; // reassignable reference
    915959        cons.[status, done ] = [0, false];
    916960}
     
    9691013The program main restarts after the resume in @start@.
    9701014@start@ returns and the program main terminates.
     1015
     1016One \emph{killer} application for a coroutine is device drivers, which at one time caused 70\%-85\% of failures in Windows/Linux~\cite{Swift05}.
     1017Many device drivers are a finite state-machine parsing a protocol, e.g.:
     1018\begin{tabbing}
     1019\ldots STX \= \ldots message \ldots \= ESC \= ETX \= \ldots message \ldots  \= ETX \= 2-byte crc \= \ldots      \kill
     1020\ldots STX \> \ldots message \ldots \> ESC \> ETX \> \ldots message \ldots  \> ETX \> 2-byte crc \> \ldots
     1021\end{tabbing}
     1022where a network message begins with the control character STX and ends with an ETX, followed by a 2-byte cyclic-redundancy check.
     1023Control characters may appear in a message if preceded by an ESC.
     1024Because FSMs can be complex and occur frequently in important domains, direct support of the coroutine is crucial in a systems programminglanguage.
     1025
     1026\begin{figure}
     1027\begin{cfa}
     1028enum Status { CONT, MSG, ESTX, ELNTH, ECRC };
     1029`coroutine` Driver {
     1030        Status status;
     1031        char * msg, byte;
     1032};
     1033void ?{}( Driver & d, char * m ) { d.msg = m; }         $\C[3.0in]{// constructor}$
     1034Status next( Driver & d, char b ) with( d ) {           $\C{// 'with' opens scope}$
     1035        byte = b; `resume( d );` return status;
     1036}
     1037void main( Driver & d ) with( d ) {
     1038        enum { STX = '\002', ESC = '\033', ETX = '\003', MaxMsg = 64 };
     1039        unsigned short int crc;                                                 $\C{// error checking}$
     1040  msg: for () {                                                                         $\C{// parse message}$
     1041                status = CONT;
     1042                unsigned int lnth = 0, sum = 0;
     1043                while ( byte != STX ) `suspend();`
     1044          emsg: for () {
     1045                        `suspend();`                                                    $\C{// process byte}$
     1046                        choose ( byte ) {                                               $\C{// switch with default break}$
     1047                          case STX:
     1048                                status = ESTX; `suspend();` continue msg;
     1049                          case ETX:
     1050                                break emsg;
     1051                          case ESC:
     1052                                suspend();
     1053                        } // choose
     1054                        if ( lnth >= MaxMsg ) {                                 $\C{// buffer full ?}$
     1055                                status = ELNTH; `suspend();` continue msg; }
     1056                        msg[lnth++] = byte;
     1057                        sum += byte;
     1058                } // for
     1059                msg[lnth] = '\0';                                                       $\C{// terminate string}\CRT$
     1060                `suspend();`
     1061                crc = (unsigned char)byte << 8; // prevent sign extension for signed char
     1062                `suspend();`
     1063                status = (crc | (unsigned char)byte) == sum ? MSG : ECRC;
     1064                `suspend();`
     1065        } // for
     1066}
     1067\end{cfa}
     1068\caption{Device driver for simple communication protocol}
     1069\end{figure}
    9711070
    9721071
  • doc/proposals/vtable.md

    r69c37cc rf343c6b  
    1111should be able to store anything that goes into a trait.
    1212
     13I also include notes on a sample implementation, which primarly exists to show
     14there is a resonable implementation. The code samples for that are in a slight
     15psudo-code to help avoid name mangling and keeps some CFA features while they
     16would actually be writen in C.
     17
    1318Trait Instances
    1419---------------
     
    4247before.
    4348
    44 Internally a trait object is a pair of pointers. One to an underlying object
    45 and the other to the vtable. All calls on an trait are implemented by looking
    46 up the matching function pointer and passing the underlying object and the
    47 remaining arguments to it.
    48 
    49 Trait objects can be moved by moving the pointers. Almost all other operations
    50 require some functions to be implemented on the underlying type. Depending on
    51 what is in the virtual table a trait type could be a dtype or otype.
     49For traits to be used this way they should meet two requirements. First they
     50should only have a single polymorphic type and each assertion should use that
     51type once as a parameter. Extentions may later loosen these requirements.
     52
     53If a trait object is used it should generate a series of implicate functions
     54each of which implements one of the functions required by the trait. So for
     55combiner there is an implicate:
     56
     57    void combine(trait combiner & this, int);
     58
     59This function is the one actually called at the end
     60
     61The main use case for trait objects is that they can be stored. They can be
     62passed into functions, but using the trait directly is prefred in this case.
     63
     64    trait drawable(otype T) {
     65        void draw(Surface & to, T & draw);
     66        Rect(int) drawArea(T & draw);
     67    };
     68
     69    struct UpdatingSurface {
     70        Surface * surface;
     71        vector(trait drawable) drawables;
     72    };
     73
     74    void updateSurface(UpdatingSurface & us) {
     75        for (size_t i = 0 ; i < us.drawables.size ; ++i) {
     76            draw(us.surface, us.drawables[i]);
     77        }
     78    }
     79
     80Currently these traits are limited to 1 trait parameter and functions should
     81have exactly 1 parameter. We cannot abstract away pairs of types and still
     82pass them into normal functions, which take them seperately.
     83
     84The second is required the because we need to get the vtable from somewhere.
     85If there are 0 trait objects than no vtable is avalible, if we have more than
     861 than the vtables give conflicting answers on what underlying function to
     87call. And even then the underlying type assumes a concrete type.
     88
     89This loop can sort of be broken by using the trait object directly in the
     90signature. This has well defined meaning, but might not be useful.
     91
     92    trait example(otype T) {
     93        bool test(T & this, trait example & that);
     94    }
     95
     96#### Sample Implementation
     97A simple way to implement trait objects is by a pair of pointers. One to the
     98underlying object and one to the vtable.
     99
     100    struct vtable_drawable {
     101        void (*draw)(Surface &, void *);
     102        Rect(int) (*drawArea)(void *);
     103    };
     104
     105    struct drawable {
     106        void * object;
     107        vtable_drawable * vtable;
     108    };
     109
     110The functions that run on the trait object would generally be generated using
     111the following pattern:
     112
     113    void draw(Surface & surface, drawable & traitObj) {
     114        return traitObj.vtable->draw(surface, traitObj.object);
     115    }
     116
     117There may have to be special cases for things like copy construction, that
     118might require a more sigificant wrapper. On the other hand moving could be
     119implemented by moving the pointers without any need to refer to the base
     120object.
     121
     122### Extention: Multiple Trait Parameters
     123Currently, this gives traits two independent uses. They use the same syntax,
     124except for limits boxable traits have, and yet don't really mix. The most
     125natural way to do this is to allow trait instances to pick one parameter
     126that they are generic over, the others they choose types to implement.
     127
     128The two ways to do the selection, the first is do it at the trait definition.
     129Each trait picks out a single parameter which it can box (here the `virtual`
     130qualifier). When you create an instance of a trait object you provide
     131arguments like for a generic structure, but skip over the marked parameter.
     132
     133    trait combiner(virtual otype T, otype Combined) {
     134        void combine(T &, Combined &);
     135    }
     136
     137    trait combiner(int) int_combiner;
     138
     139The second is to do it at the instaniation point. A placeholder (here the
     140keyword `virtual`) is used to explicately skip over the parameter that will be
     141abstracted away, with the same rules as above if it was the marked parameter.
     142
     143    trait combiner(otype T, otype Combined) {
     144        void combine(T &, Combined &);
     145    };
     146
     147    trait combiner(virtual, int) int_combiner;
     148
     149Using both (first to set the default, second as a local override) would also
     150work, although might be exessively complicated.
     151
     152This is useful in cases where you want to use a generic type, but leave part
     153of it open and store partially generic result. As a simple example
     154
     155    trait folder(otype T, otype In, otype Out) {
     156        void fold(T & this, In);
     157        Out fold_result(T & this);
     158    }
     159
     160Which allows you to fold values without putting them in a container. If they
     161are already in a container this is exessive, but if they are generated over
     162time this gives you a simple interface. This could for instance be used in
     163a profile, where T changes for each profiling statistic and you can plug in
     164multiple profilers for any run by adding them to an array.
    52165
    53166Hierarchy
     
    90203the pointer to it.
    91204
     205Exception Example:
     206(Also I'm not sure where I got these casing rules.)
     207
     208    trait exception(otype T) virtual() {
     209        char const * what(T & this);
     210    }
     211
     212    trait io_error(otype T) virtual(exception) {
     213        FILE * which_file(T & this);
     214    }
     215
     216    struct eof_error(otype T) virtual(io_error) {
     217        FILE * file;
     218    }
     219
     220    char const * what(eof_error &) {
     221        return "Tried to read from an empty file.";
     222    }
     223
     224    FILE * which_file(eof_error & this) {
     225        return eof_error.file;
     226    }
     227
     228Ast Example:
     229
     230    trait ast_node(otype T) virtual() {
     231        void print(T & this, ostream & out);
     232        void visit(T & this, Visitor & visitor);
     233        CodeLocation const & get_code_location(T & this);
     234    }
     235
     236    trait expression_node(otype T) virtual(ast_node) {
     237        Type eval_type(T const & this);
     238    }
     239
     240    struct operator_expression virtual(expression_node) {
     241        enum operator_kind kind;
     242        trait expression_node rands[2];
     243    }
     244
     245    trait statement_node(otype T) virtual(ast_node) {
     246        vector(Label) & get_labels(T & this);
     247    }
     248
     249    struct goto_statement virtual(statement_node) {
     250        vector(Label) labels;
     251        Label target;
     252    }
     253
     254    trait declaration_node(otype T) virtual(ast_node) {
     255        string name_of(T const & this);
     256        Type type_of(T const & this);
     257    }
     258
     259    struct using_declaration virtual(declaration_node) {
     260        string new_type;
     261        Type old_type;
     262    }
     263
     264    struct variable_declaration virtual(declaration_node) {
     265        string name;
     266        Type type;
     267    }
     268
     269#### Sample Implementation
     270The type id may be as little as:
     271
     272    struct typeid {
     273        struct typeid const * const parent;
     274    };
     275
     276Some linker magic would have to be used to ensure exactly one copy of each
     277structure for each type exists in memory. There seem to be spectial once
     278sections that support this and it should be easier than generating unique
     279ids across compilation units.
     280
     281The structure could be extended to contain any additional type information.
     282
     283There are two general designs for vtables with type ids. The first is to put
     284the type id at the top of the vtable, this is the most compact and efficient
     285solution but only works if we have exactly 1 vtable for each type. The second
     286is to put a pointer to the type id in each vtable. This has more overhead but
     287allows multiple vtables.
     288
     289    struct <trait>_vtable {
     290        struct typeid const id;
     291
     292        // Trait dependent list of vtable members.
     293    };
     294
     295    struct <trait>_vtable {
     296        struct typeid const * const id;
     297
     298        // Trait dependent list of vtable members.
     299    };
     300
     301### Virtual Casts
     302To convert from a pointer to a type higher on the hierarchy to one lower on
     303the hierarchy a check is used to make sure that the underlying type is also
     304of that lower type.
     305
     306The proposed syntax for this is:
     307
     308    trait SubType * new_value = (virtual trait SubType *)super_type;
     309
     310It will return the same pointer if it does point to the subtype and null if
     311it does not, doing the check and conversion in one operation.
     312
    92313### Inline vtables
    93314Since the structures here are usually made to be turned into trait objects
    94315it might be worth it to have fields on them to store the virtual table
    95 pointer. This would have to be declared on the trait as an assertion, but if
    96 it is the trait object could be a single pointer.
    97 
    98 It is trivial to do if the field with the virtual table pointer is fixed.
    99 Otherwise some trickery with pointing to the field and storing the offset in
    100 the virtual table to recover the main object would have to be used.
     316pointer. This would have to be declared on the trait as an assertion (example:
     317`vtable;` or `T.vtable;`), but if it is the trait object could be a single
     318pointer.
     319
     320There are also three options for where the pointer to the vtable. It could be
     321anywhere, a fixed location for each trait or always at the front. For the per-
     322trait solution an extention to specify what it is (example `vtable[0];`) which
     323could also be used to combine it with others. So these options can be combined
     324to allow access to all three options.
    101325
    102326### Virtual Tables as Types
    103 Here we consider encoding plus the implementation of functions on it. Which
    104 is to say in the type hierarchy structures aren't concrete types anymore,
    105 instead they are parent types to vtables, which combine the encoding and
    106 implementation.
     327Here we consider encoding plus the implementation of functions on it to be a
     328type. Which is to say in the type hierarchy structures aren't concrete types
     329anymore, instead they are parent types to vtables, which combine the encoding
     330and implementation.
    107331
    108332Resolution Scope
     
    123347other.
    124348
    125 Some syntax would have to be added. All resolutions can be found at compile
    126 time and a single vtable created for each type at compilation time.
     349Some syntax would have to be added to specify the resolution point. To ensure
     350a single instance there may have to be two variants, one forward declaration
     351and one to create the instance. With some compiler magic the forward
     352declaration maybe enough.
     353
     354    extern trait combiner(struct summation) vtable;
     355    trait combiner(struct summation) vtable;
     356
     357Or (with the same variants):
     358
     359    vtable combiner(struct summation);
     360
     361The extern variant promises that the vtable will exist while the normal one
     362is where the resolution actually happens.
    127363
    128364### Explicit Resolution Points:
     
    141377vtable.
    142378
     379    extern trait combiner(struct summation) vtable sum;
     380    trait combiner(struct summation) vtable sum;
     381
     382    extern trait combiner(struct summation) vtable sum default;
     383    trait combiner(struct summation) vtable sum default;
     384
     385The extern difference is the same before. The name (sum in the samples) is
     386used at the binding site to say which one is picked. The default keyword can
     387be used in only some of the declarations.
     388
     389    trait combiner fee = (summation_instance, sum);
     390    trait combiner foe = summation_instance;
     391
     392(I am not really happy about this syntax, but it kind of works.)
     393The object being bound is required. The name of the vtable is optional if
     394there is exactly one vtable name marked with default.
     395
     396These could also be placed inside functions. In which case both the name and
     397the default keyword might be optional. If the name is ommited in an assignment
     398the closest vtable is choosen (returning to the global default rule if no
     399approprate local vtable is in scope).
     400
    143401### Site Based Resolution:
    144402Every place in code where the binding of a vtable to an object occurs has
  • doc/user/user.tex

    r69c37cc rf343c6b  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Tue Dec 11 23:19:26 2018
    14 %% Update Count     : 3400
     13%% Last Modified On : Sun Apr 14 11:02:34 2019
     14%% Update Count     : 3443
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    508508
    509509As for \Index{division}, there are exponentiation operators for integral and floating types, including the builtin \Index{complex} types.
    510 Unsigned integral exponentiation\index{exponentiation!unsigned integral} is performed with repeated multiplication\footnote{The multiplication computation is $O(\log y)$.} (or shifting if the base is 2).
    511 Signed integral exponentiation\index{exponentiation!signed integral} is performed with repeated multiplication (or shifting if the base is 2), but yields a floating result because $x^{-y}=1/x^y$.
    512 Hence, it is important to designate exponent integral-constants as unsigned or signed: ©3 \ 3u© return an integral result, while ©3 \ 3© returns a floating result.
    513 Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the base cannot be negative.
    514 \begin{cfa}
    515 sout | 2 ®\® 8u | 4 ®\® 3u | -4 ®\® 3u | 4 ®\® -3 | -4 ®\® -3 | 4.0 ®\® 2.1 | (1.0f+2.0fi) ®\® (3.0f+2.0fi);
    516 256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
    517 \end{cfa}
     510Integral exponentiation\index{exponentiation!unsigned integral} is performed with repeated multiplication\footnote{The multiplication computation is $O(\log y)$.} (or shifting if the exponent is 2).
     511Overflow from large exponents or negative exponents return zero.
     512Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative.
     513\begin{cfa}
     514sout | 1 ®\® 0 | 1 ®\® 1 | 2 ®\® 8 | -4 ®\® 3 | 5 ®\® 3 | 5 ®\® 32 | 5L ®\® 32 | 5L ®\® 64 | -4 ®\® -3 | -4.0 ®\® -3 | 4.0 ®\® 2.1
     515           | (1.0f+2.0fi) ®\® (3.0f+2.0fi);
     5161 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i
     517\end{cfa}
     518Note, ©5 ®\® 32© and ©5L ®\® 64© overflow, and ©-4 ®\® -3© is a fraction but stored in an integer so all three computations generate an integral zero.
    518519Parenthesis are necessary for complex constants or the expression is parsed as ©1.0f+®(®2.0fi \ 3.0f®)®+2.0fi©.
    519 The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation versions are available.
    520 For returning an integral value, the user type ©T© must define multiplication, ©*©, and one, ©1©;
    521 for returning a floating value, an additional divide of type ©T© into a ©double© returning a ©double© (©double ?/?( double, T )©) is necessary for negative exponents.
     520The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation version is available.
     521\begin{cfa}
     522forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } )
     523OT ?®\®?( OT ep, unsigned int y );
     524forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } )
     525OT ?®\®?( OT ep, unsigned long int y );
     526\end{cfa}
     527The user type ©T© must define multiplication, one, ©1©, and, ©*©.
    522528
    523529
     
    549555\subsection{Loop Control}
    550556
    551 The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges.
     557The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}).
     558\begin{itemize}
     559\item
    552560An empty conditional implies ©1©.
    553 The up-to range ©~©\index{~@©~©} means exclusive range [M,N);
    554 the up-to range ©~=©\index{~=@©~=©} means inclusive range [M,N].
    555 The down-to range ©-~©\index{-~@©-~©} means exclusive range [N,M);
    556 the down-to range ©-~=©\index{-~=@©-~=©} means inclusive range [N,M].
     561\item
     562The up-to range ©~©\index{~@©~©} means exclusive range [M,N).
     563\item
     564The up-to range ©~=©\index{~=@©~=©} means inclusive range [M,N].
     565\item
     566The down-to range ©-~©\index{-~@©-~©} means exclusive range [N,M).
     567\item
     568The down-to range ©-~=©\index{-~=@©-~=©} means inclusive range [N,M].
     569\item
     570©@© means put nothing in this field.
     571\item
    557572©0© is the implicit start value;
     573\item
    558574©1© is the implicit increment value.
     575\item
    559576The up-to range uses ©+=© for increment;
    560 the down-to range uses ©-=© for decrement.
     577\item
     578The down-to range uses ©-=© for decrement.
     579\item
    561580The loop index is polymorphic in the type of the start value or comparison value when start is implicitly ©0©.
     581\end{itemize}
     582
     583\begin{figure}
    562584\begin{cquote}
    563 \begin{tabular}{@{}ll|l@{}}
    564 \multicolumn{2}{c|}{loop control} & \multicolumn{1}{c}{output} \\
     585\begin{tabular}{@{}l|l@{}}
     586\multicolumn{1}{c|}{loop control} & \multicolumn{1}{c}{output} \\
    565587\hline
    566588\begin{cfa}
    567 while ®()® { sout | "empty"; break; }
    568 do { sout | "empty"; break; } while ®()®;
    569 for ®()® { sout | "empty"; break; }
    570 for ( ®0® ) { sout | "A"; }
    571 for ( ®1® ) { sout | "A"; }
    572 for ( ®10® ) { sout | "A"; }
    573 for ( ®1 ~= 10 ~ 2® ) { sout | "B"; }
    574 for ( ®10 -~= 1 ~ 2® ) { sout | "C"; }
    575 for ( ®0.5 ~ 5.5® ) { sout | "D"; }
    576 for ( ®5.5 -~ 0.5® ) { sout | "E"; }
    577 for ( ®i; 10® ) { sout | i; }
    578 for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; }
    579 for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; }
    580 for ( ®i; 0.5 ~ 5.5® ) { sout | i; }
    581 for ( ®i; 5.5 -~ 0.5® ) { sout | i; }
    582 for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; }
    583 for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; }
     589sout | nlOff;
     590while ®()® { sout | "empty"; break; } sout | nl;
     591do { sout | "empty"; break; } while ®()®; sout | nl;
     592for ®()® { sout | "empty"; break; } sout | nl;
     593for ( ®0® ) { sout | "A"; } sout | "zero" | nl;
     594for ( ®1® ) { sout | "A"; } sout | nl;
     595for ( ®10® ) { sout | "A"; } sout | nl;
     596for ( ®1 ~= 10 ~ 2® ) { sout | "B"; } sout | nl;
     597for ( ®10 -~= 1 ~ 2® ) { sout | "C"; } sout | nl;
     598for ( ®0.5 ~ 5.5® ) { sout | "D"; } sout | nl;
     599for ( ®5.5 -~ 0.5® ) { sout | "E"; } sout | nl;
     600for ( ®i; 10® ) { sout | i; } sout | nl;
     601for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; } sout | nl;
     602for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; } sout | nl;
     603for ( ®i; 0.5 ~ 5.5® ) { sout | i; } sout | nl;
     604for ( ®i; 5.5 -~ 0.5® ) { sout | i; } sout | nl;
     605for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; } sout | nl;
     606for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; } sout | nl;
    584607enum { N = 10 };
    585 for ( ®N® ) { sout | "N"; }
    586 for ( ®i; N® ) { sout | i; }
    587 for ( ®i; N -~ 0® ) { sout | i; }
     608for ( ®N® ) { sout | "N"; } sout | nl;
     609for ( ®i; N® ) { sout | i; } sout | nl;
     610for ( ®i; N -~ 0® ) { sout | i; } sout | nl;
    588611const int start = 3, comp = 10, inc = 2;
    589 for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; }
     612for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; } sout | nl;
     613for ( ®i; 1 ~ @® ) { if ( i > 10 ) break;
     614        sout | i; } sout | nl;
     615for ( ®i; 10 -~ @® ) { if ( i < 0 ) break;
     616        sout | i; } sout | nl;
     617for ( ®i; 2 ~ @ ~ 2® ) { if ( i > 10 ) break;
     618        sout | i; } sout | nl;
     619for ( ®i; 2.1 ~ @ ~ @® ) { if ( i > 10.5 ) break;
     620        sout | i; i += 1.7; } sout | nl;
     621for ( ®i; 10 -~ @ ~ 2® ) { if ( i < 0 ) break;
     622        sout | i; } sout | nl;
     623for ( ®i; 12.1 ~ @ ~ @® ) { if ( i < 2.5 ) break;
     624        sout | i; i -= 1.7; } sout | nl;
     625for ( ®i; 5 : j; -5 ~ @® ) { sout | i | j; } sout | nl;
     626for ( ®i; 5 : j; -5 -~ @® ) { sout | i | j; } sout | nl;
     627for ( ®i; 5 : j; -5 ~ @ ~ 2® ) { sout | i | j; } sout | nl;
     628for ( ®i; 5 : j; -5 -~ @ ~ 2® ) { sout | i | j; } sout | nl;
     629for ( ®j; -5 ~ @ : i; 5® ) { sout | i | j; } sout | nl;
     630for ( ®j; -5 -~ @ : i; 5® ) { sout | i | j; } sout | nl;
     631for ( ®j; -5 ~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl;
     632for ( ®j; -5 -~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl;
     633for ( ®j; -5 -~ @ ~ 2 : i; 5 : k; 1.5 ~ @® ) {
     634        sout | i | j | k; } sout | nl;
     635for ( ®j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 5® ) {
     636        sout | i | j | k; } sout | nl;
     637for ( ®k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 5® ) {
     638        sout | i | j | k; } sout | nl;
    590639\end{cfa}
    591640&
    592641\begin{cfa}
    593 sout | nl;
    594 sout | nl;
    595 sout | nl;
    596 sout | "zero" | nl;
    597 sout | nl;
    598 sout | nl;
    599 sout | nl;
    600 sout | nl;
    601 sout | nl;
    602 sout | nl;
    603 sout | nl;
    604 sout | nl;
    605 sout | nl;
    606 sout | nl;
    607 sout | nl;
    608 sout | nl;
    609 sout | nl | nl;
    610 
    611 sout | nl;
    612 sout | nl;
    613 sout | nl | nl;
    614 
    615 sout | nl;
    616 \end{cfa}
    617 &
    618 \begin{cfa}
     642
    619643empty
    620644empty
     
    640664
    6416653 6 9
     666
     6671 2 3 4 5 6 7 8 9 10
     668
     66910 9 8 7 6 5 4 3 2 1 0
     670
     6712 4 6 8 10
     672
     6732.1 3.8 5.5 7.2 8.9
     674
     67510 8 6 4 2 0
     676
     67712.1 10.4 8.7 7 5.3 3.6
     6780 -5 1 -4 2 -3 3 -2 4 -1
     6790 -5 1 -6 2 -7 3 -8 4 -9
     6800 -5 1 -3 2 -1 3 1 4 3
     6810 -5 1 -7 2 -9 3 -11 4 -13
     6820 -5 1 -4 2 -3 3 -2 4 -1
     6830 -5 1 -6 2 -7 3 -8 4 -9
     6840 -5 1 -3 2 -1 3 1 4 3
     6850 -5 1 -7 2 -9 3 -11 4 -13
     686
     6870 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
     688
     6890 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
     690
     6910 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    642692\end{cfa}
    643693\end{tabular}
    644694\end{cquote}
     695\caption{Loop Control Examples}
     696\label{f:LoopControlExamples}
     697\end{figure}
    645698
    646699
     
    13201373\end{cfa}
    13211374Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}).
    1322 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice.
     1375While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice, even though Dennis Richie believed otherwise:
     1376\begin{quote}
     1377In spite of its difficulties, I believe that the C's approach to declarations remains plausible, and am comfortable with it; it is a useful unifying principle.~\cite[p.~12]{Ritchie93}
     1378\end{quote}
    13231379
    13241380\CFA provides its own type, variable and routine declarations, using a different syntax.
  • libcfa/configure

    r69c37cc rf343c6b  
    29772977        ;;
    29782978esac
     2979
     2980CONFIG_CFAFLAGS="${CONFIG_CFAFLAGS} ${CFAFLAGS}"
    29792981
    29802982
  • libcfa/configure.ac

    r69c37cc rf343c6b  
    6464esac
    6565
     66CONFIG_CFAFLAGS="${CONFIG_CFAFLAGS} ${CFAFLAGS}"
     67
    6668AC_SUBST(CONFIG_CFLAGS)
    6769AC_SUBST(CONFIG_CFAFLAGS)
  • libcfa/prelude/builtins.c

    r69c37cc rf343c6b  
    1010// Created On       : Fri Jul 21 16:21:03 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Mar 10 10:52:50 2019
    13 // Update Count     : 31
     12// Last Modified On : Tue Mar 26 23:10:36 2019
     13// Update Count     : 95
    1414//
    1515
     
    1818typedef unsigned long long __cfaabi_abi_exception_type_t;
    1919
     20#include <limits.h>                                                                             // CHAR_BIT
    2021#include "../src/virtual.h"
    2122#include "../src/exception.h"
     
    2627// increment/decrement unification
    2728
    28 static inline forall( dtype T | { T & ?+=?( T &, one_t ); } )
    29 T & ++? ( T & x ) { return x += 1; }
     29static inline {
     30        forall( dtype DT | { DT & ?+=?( DT &, one_t ); } )
     31        DT & ++?( DT & x ) { return x += 1; }
    3032
    31 static inline forall( dtype T | sized(T) | { void ?{}( T &, T ); void ^?{}( T & ); T & ?+=?( T &, one_t ); } )
    32 T & ?++ ( T & x ) { T tmp = x; x += 1; return tmp; }
     33        forall( dtype DT | sized(DT) | { void ?{}( DT &, DT ); void ^?{}( DT & ); DT & ?+=?( DT &, one_t ); } )
     34        DT & ?++( DT & x ) { DT tmp = x; x += 1; return tmp; }
    3335
    34 static inline forall( dtype T | { T & ?-=?( T &, one_t ); } )
    35 T & --? ( T & x ) { return x -= 1; }
     36        forall( dtype DT | { DT & ?-=?( DT &, one_t ); } )
     37        DT & --?( DT & x ) { return x -= 1; }
    3638
    37 static inline forall( dtype T | sized(T) | { void ?{}( T &, T ); void ^?{}( T & ); T & ?-=?( T &, one_t ); } )
    38 T & ?-- ( T & x ) { T tmp = x; x -= 1; return tmp; }
     39        forall( dtype DT | sized(DT) | { void ?{}( DT &, DT ); void ^?{}( DT & ); DT & ?-=?( DT &, one_t ); } )
     40        DT & ?--( DT & x ) { DT tmp = x; x -= 1; return tmp; }
     41} // distribution
    3942
    4043// universal typed pointer constant
    41 
    42 static inline forall( dtype T ) T * intptr( uintptr_t addr ) { return (T *)addr; }
     44// Compiler issue: there is a problem with anonymous types that do not have a size.
     45static inline forall( dtype DT | sized(DT) ) DT * intptr( uintptr_t addr ) { return (DT *)addr; }
    4346
    4447// exponentiation operator implementation
     
    5356} // extern "C"
    5457
    55 static inline float ?\?( float x, float y ) { return powf( x, y ); }
    56 static inline double ?\?( double x, double y ) { return pow( x, y ); }
    57 static inline long double ?\?( long double x, long double y ) { return powl( x, y ); }
    58 static inline float _Complex ?\?( float _Complex x, _Complex float y ) { return cpowf(x, y ); }
    59 static inline double _Complex ?\?( double _Complex x, _Complex double y ) { return cpow( x, y ); }
    60 static inline long double _Complex ?\?( long double _Complex x, _Complex long double y ) { return cpowl( x, y ); }
     58static inline {
     59        float ?\?( float x, float y ) { return powf( x, y ); }
     60        double ?\?( double x, double y ) { return pow( x, y ); }
     61        long double ?\?( long double x, long double y ) { return powl( x, y ); }
     62        float _Complex ?\?( float _Complex x, _Complex float y ) { return cpowf(x, y ); }
     63        double _Complex ?\?( double _Complex x, _Complex double y ) { return cpow( x, y ); }
     64        long double _Complex ?\?( long double _Complex x, _Complex long double y ) { return cpowl( x, y ); }
     65} // distribution
    6166
    62 static inline long int ?\?( long int ep, unsigned long int y ) { // disallow negative exponent
    63         if ( y == 0 ) return 1;                                                         // base case
    64         if ( ep == 2 ) return ep << (y - 1);                            // special case, positive shifting only
    65         typeof( ep ) op = 1;                                                            // accumulate odd product
    66         for ( ; y > 1; y >>= 1 ) {                                                      // squaring exponentiation, O(log2 y)
    67                 if ( (y & 1) == 1 ) op *= ep;                                   // odd ?
    68                 ep *= ep;
    69         } // for
    70         return ep * op;
    71 } // ?\?
     67#define __CFA_BASE_COMP_1__() if ( ep == 1 ) return 1
     68#define __CFA_BASE_COMP_2__() if ( ep == 2 ) return ep << (y - 1)
     69#define __CFA_EXP_OVERFLOW__() if ( y >= sizeof(y) * CHAR_BIT ) return 0
    7270
    73 static inline forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } )
    74 T ?\?( T ep, unsigned long int y ) {
    75         if ( y == 0 ) return 1;
    76         T op = 1;
    77         for ( ; y > 1; y >>= 1 ) {                                                      // squaring exponentiation, O(log2 y)
    78                 if ( (y & 1) == 1 ) op = op * ep;                               // odd ?
    79                 ep = ep * ep;
    80         } // for
    81         return ep * op;
    82 } // ?\?
     71#define __CFA_EXP__() \
     72        if ( y == 0 ) return 1;                                                         /* convention */ \
     73        __CFA_BASE_COMP_1__();                                                          /* base case */ \
     74        __CFA_BASE_COMP_2__();                                                          /* special case, positive shifting for integral types */ \
     75        __CFA_EXP_OVERFLOW__();                                                         /* immediate overflow, negative exponent > 2^size-1 */ \
     76        typeof(ep) op = 1;                                                                      /* accumulate odd product */ \
     77        for ( ; y > 1; y >>= 1 ) {                                                      /* squaring exponentiation, O(log2 y) */ \
     78                if ( (y & 1) == 1 ) op = op * ep;                               /* odd ? */ \
     79                ep = ep * ep; \
     80        } \
     81        return ep * op
    8382
    84 // unsigned computation may be faster and larger
    85 static inline unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { // disallow negative exponent
    86         if ( y == 0 ) return 1;                                                         // base case
    87         if ( ep == 2 ) return ep << (y - 1);                            // special case, positive shifting only
    88         typeof( ep ) op = 1;                                                            // accumulate odd product
    89         for ( ; y > 1; y >>= 1 ) {                                                      // squaring exponentiation, O(log2 y)
    90                 if ( (y & 1) == 1 ) op *= ep;                                   // odd ?
    91                 ep *= ep;
    92         } // for
    93         return ep * op;
    94 } // ?\?
     83static inline {
     84        long int ?\?( int ep, unsigned int y ) { __CFA_EXP__(); }
     85        long int ?\?( long int ep, unsigned long int y ) { __CFA_EXP__(); }
     86        // unsigned computation may be faster and larger
     87        unsigned long int ?\?( unsigned int ep, unsigned int y ) { __CFA_EXP__(); }
     88        unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { __CFA_EXP__(); }
     89} // distribution
    9590
    96 static inline double ?\?( long int x, signed long int y ) {     // allow negative exponent
    97         if ( y >=  0 ) return (double)(x \ (unsigned long int)y);
    98         else return 1.0 / x \ (unsigned int)(-y);
    99 } // ?\?
     91#undef __CFA_BASE_COMP_1__
     92#undef __CFA_BASE_COMP_2__
     93#undef __CFA_EXP_OVERFLOW__
     94#define __CFA_BASE_COMP_1__()
     95#define __CFA_BASE_COMP_2__()
     96#define __CFA_EXP_OVERFLOW__()
    10097
    101 // FIXME (x \ (unsigned long int)y) relies on X ?\?(T, unsigned long) a function that is neither
    102 // defined, nor passed as an assertion parameter. Without user-defined conversions, cannot specify
    103 // X as a type that casts to double, yet it doesn't make sense to write functions with that type
    104 // signature where X is double.
     98static inline forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) {
     99        OT ?\?( OT ep, unsigned int y ) { __CFA_EXP__(); }
     100        OT ?\?( OT ep, unsigned long int y ) { __CFA_EXP__(); }
     101} // distribution
    105102
    106 // static inline forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); double ?/?( double, T ); } )
    107 // double ?\?( T x, signed long int y ) {
    108 //     if ( y >=  0 ) return (double)(x \ (unsigned long int)y);
    109 //     else return 1.0 / x \ (unsigned long int)(-y);
    110 // } // ?\?
     103#undef __CFA_BASE_COMP_1__
     104#undef __CFA_BASE_COMP_2__
     105#undef __CFA_EXP_OVERFLOW__
    111106
    112 static inline long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; }
    113 static inline unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; }
    114 static inline int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; }
    115 static inline unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; }
     107static inline {
     108        long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; }
     109        unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; }
     110        int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; }
     111        unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; }
     112} // distribution
    116113
    117114// Local Variables: //
  • libcfa/prelude/prelude-gen.cc

    r69c37cc rf343c6b  
    1010// Created On       : Sat Feb 16 08:44:58 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar  8 16:00:22 2019
    13 // Update Count     : 26
     12// Last Modified On : Tue Apr  2 17:18:24 2019
     13// Update Count     : 37
    1414//
    1515
     
    118118        { "?!=?", false, "signed int", Normal, "" },
    119119        { "?=?", true, "", Normal, "" }, // void * LHS, zero_t RHS ???
    120         { "*?", false, "&", Normal, " | sized(DT)" }, // & ???
     120//      { "*?", false, "&", Normal, " | sized(DT)" }, // & ???
     121        { "*?", false, "&", Normal, "" }, // & ???
    121122
    122123        { "?-?", false, "ptrdiff_t", Normal, " | sized(DT)" },
     
    208209                cout << "void ?{} (" << type << " &);" << endl;
    209210                cout << "void ?{} (" << type << " &, " << type << ");" << endl;
    210                 cout << type << "  ?=? (" << type << " &, " << type << ")";
     211                cout << type << " ?=? (" << type << " &, " << type << ")";
    211212                if ( do_volatile ) {
    212                         cout << ",  ?=?(volatile " << type << " &, " << type << ")";
     213                        cout << ", ?=?(volatile " << type << " &, " << type << ")";
    213214                }
    214215                cout << ";" << endl;
     
    217218
    218219        otype("zero_t");
     220        cout << endl;
    219221        otype("one_t");
     222        cout << endl;
    220223        otype("_Bool", true);
    221224        cout << endl;
     
    225228                cout << "void ?{}(" << type.name << " &, " << type.name << ");" << endl;
    226229                cout << "void ?{}(" << type.name << " &, zero_t);" << endl;
     230                cout << "void ?{}(" << type.name << " &, one_t);" << endl;
    227231                cout << "void ^?{}(" << type.name << " &);" << endl;
    228232                cout << endl;
  • libcfa/src/Makefile.am

    r69c37cc rf343c6b  
    7474
    7575prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    76         ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
     76        ${AM_V_GEN}$(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
    7777
    7878prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    7979        ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \
    80         @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
     80        $(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
    8181
    8282
  • libcfa/src/Makefile.in

    r69c37cc rf343c6b  
    926926
    927927prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    928         ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
     928        ${AM_V_GEN}$(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
    929929
    930930prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    931931        ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \
    932         @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
     932        $(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
    933933
    934934#----------------------------------------------------------------------------------------------------------------
  • libcfa/src/concurrency/CtxSwitch-x86_64.S

    r69c37cc rf343c6b  
    8888        ret
    8989
     90//.text
     91//      .align 2
     92//.globl        CtxStore
     93//CtxStore:
     94//      // Save floating & SSE control words on the stack.
     95//
     96//      subq   $8,%rsp
     97//      stmxcsr 0(%rsp)         // 4 bytes
     98//      fnstcw  4(%rsp)         // 2 bytes
     99//
     100//      // Save volatile registers on the stack.
     101//
     102//      pushq %r15
     103//      pushq %r14
     104//      pushq %r13
     105//      pushq %r12
     106//      pushq %rbx
     107//
     108//      // Save old context in the "from" area.
     109//
     110//      movq %rsp,SP_OFFSET(%rdi)
     111//      movq %rbp,FP_OFFSET(%rdi)
     112//
     113//      // Return to thread
     114//
     115//      ret
     116//
     117//.text
     118//      .align 2
     119//.globl        CtxRet
     120//CtxRet:
     121//      // Load new context from the "to" area.
     122//
     123//      movq SP_OFFSET(%rdi),%rsp
     124//      movq FP_OFFSET(%rdi),%rbp
     125//
     126//      // Load volatile registers from the stack.
     127//
     128//      popq %rbx
     129//      popq %r12
     130//      popq %r13
     131//      popq %r14
     132//      popq %r15
     133//
     134//      // Load floating & SSE control words from the stack.
     135//
     136//      fldcw   4(%rsp)
     137//      ldmxcsr 0(%rsp)
     138//      addq   $8,%rsp
     139//
     140//      // Return to thread.
     141//
     142//      ret
     143
     144
    90145.text
    91146        .align 2
  • libcfa/src/concurrency/coroutine.cfa

    r69c37cc rf343c6b  
    3535
    3636extern "C" {
    37       void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) __attribute__ ((__noreturn__));
     37      void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
    3838      static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__));
    3939      static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) {
     
    8484void ^?{}(coroutine_desc& this) {
    8585      if(this.state != Halted && this.state != Start) {
    86             coroutine_desc * src = TL_GET( this_coroutine );
     86            coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    8787            coroutine_desc * dst = &this;
    8888
     
    115115// Wrapper for co
    116116void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
    117       // Safety note : This could cause some false positives due to preemption
     117      // Safety note : Preemption must be disabled since there is a race condition
     118      // kernelTLS.this_thread->curr_cor and $rsp/$rbp must agree at all times
    118119      verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
    119120      disable_interrupts();
     
    123124
    124125      // set new coroutine that task is executing
    125       kernelTLS.this_coroutine = dst;
     126      TL_GET( this_thread )->curr_cor = dst;
    126127
    127128      // context switch to specified coroutine
     
    134135
    135136      enable_interrupts( __cfaabi_dbg_ctx );
    136       // Safety note : This could cause some false positives due to preemption
    137137      verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
    138138
     139
    139140      if( unlikely(src->cancellation != NULL) ) {
    140             _CtxCoroutine_Unwind(src->cancellation);
     141            _CtxCoroutine_Unwind(src->cancellation, src);
    141142      }
    142143} //ctxSwitchDirect
     
    197198      }
    198199
    199       void __leave_coroutine() {
    200             coroutine_desc * src = TL_GET( this_coroutine ); // optimization
     200      void __leave_coroutine( coroutine_desc * src ) {
    201201            coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter;
    202202
  • libcfa/src/concurrency/coroutine.hfa

    r69c37cc rf343c6b  
    4646//-----------------------------------------------------------------------------
    4747// Public coroutine API
    48 static inline void suspend();
     48static inline void suspend(void);
    4949
    5050forall(dtype T | is_coroutine(T))
     
    7171
    7272// Suspend implementation inlined for performance
    73 static inline void suspend() {
     73static inline void suspend(void) {
    7474        // optimization : read TLS once and reuse it
    7575        // Safety note: this is preemption safe since if
     
    7777        // will also migrate which means this value will
    7878        // stay in syn with the TLS
    79         coroutine_desc * src = TL_GET( this_coroutine );
     79        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    8080
    8181        assertf( src->last != 0,
     
    9999        // will also migrate which means this value will
    100100        // stay in syn with the TLS
    101         coroutine_desc * src = TL_GET( this_coroutine );
     101        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    102102        coroutine_desc * dst = get_coroutine(cor);
    103103
     
    129129        // will also migrate which means this value will
    130130        // stay in syn with the TLS
    131         coroutine_desc * src = TL_GET( this_coroutine );
     131        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    132132
    133133        // not resuming self ?
     
    146146}
    147147
     148
     149
     150// static inline bool suspend_checkpoint(void) {
     151//      // optimization : read TLS once and reuse it
     152//      // Safety note: this is preemption safe since if
     153//      // preemption occurs after this line, the pointer
     154//      // will also migrate which means this value will
     155//      // stay in syn with the TLS
     156//      // set state of current coroutine to inactive
     157//       this->state = Checkpoint;
     158
     159//       // context switch to specified coroutine
     160//       assert( src->stack.context );
     161
     162//       CtxStore(src->stack.context);
     163
     164//      bool ret = this->state == Checkpoint;
     165
     166//       // set state of new coroutine to active
     167//       src->state = Active;
     168
     169//       enable_interrupts( __cfaabi_dbg_ctx );
     170//       // Safety note : This could cause some false positives due to preemption
     171//       verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
     172
     173//       if( unlikely(src->cancellation != NULL) ) {
     174//             _CtxCoroutine_Unwind(src->cancellation);
     175//       }
     176
     177//      return ret;
     178// }
     179
     180// static inline void suspend_return(void) {
     181//      // optimization : read TLS once and reuse it
     182//      // Safety note: this is preemption safe since if
     183//      // preemption occurs after this line, the pointer
     184//      // will also migrate which means this value will
     185//      // stay in syn with the TLS
     186//      coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     187
     188//      assertf( src->last != 0,
     189//              "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
     190//              "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
     191//              src->name, src );
     192//      assertf( src->last->state != Halted,
     193//              "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
     194//              "Possible cause is terminated coroutine's main routine has already returned.",
     195//              src->name, src, src->last->name, src->last );
     196
     197//      // Safety note : Preemption must be disabled here since kernelTLS.this_coroutine must always be up to date
     198//       verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
     199//       disable_interrupts();
     200
     201//       // set state of current coroutine to inactive
     202//       src->state = src->state == Halted ? Halted : Inactive;
     203
     204//       // set new coroutine that task is executing
     205//       kernelTLS.this_coroutine = dst;
     206
     207//       // context switch to specified coroutine
     208//       assert( src->stack.context );
     209//      CtxRet( src->stack.context );
     210
     211//      abort();
     212// }
     213
    148214// Local Variables: //
    149215// mode: c //
  • libcfa/src/concurrency/invoke.c

    r69c37cc rf343c6b  
    2828
    2929extern void __suspend_internal(void);
    30 extern void __leave_coroutine(void);
    31 extern void __finish_creation(void);
     30extern void __leave_coroutine( struct coroutine_desc * );
     31extern void __finish_creation( struct coroutine_desc * );
    3232extern void __leave_thread_monitor( struct thread_desc * this );
    3333extern void disable_interrupts();
     
    5252
    5353        //Final suspend, should never return
    54         __leave_coroutine();
     54        __leave_coroutine( cor );
    5555        __cabi_abort( "Resumed dead coroutine" );
    5656}
     
    6262        __attribute((__unused__)) struct _Unwind_Exception * unwind_exception,
    6363        __attribute((__unused__)) struct _Unwind_Context * context,
    64         __attribute((__unused__)) void * param
     64        void * param
    6565) {
    6666        if( actions & _UA_END_OF_STACK  ) {
    6767                // We finished unwinding the coroutine,
    6868                // leave it
    69                 __leave_coroutine();
     69                __leave_coroutine( param );
    7070                __cabi_abort( "Resumed dead coroutine" );
    7171        }
     
    7575}
    7676
    77 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) __attribute__ ((__noreturn__));
    78 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) {
    79         _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, NULL );
     77void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) __attribute__ ((__noreturn__));
     78void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc * cor) {
     79        _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, cor );
    8080        printf("UNWIND ERROR %d after force unwind\n", ret);
    8181        abort();
     
    8888        void *this
    8989) {
     90        // Fetch the thread handle from the user defined thread structure
     91        struct thread_desc* thrd = get_thread( this );
     92
    9093        // First suspend, once the thread arrives here,
    9194        // the function pointer to main can be invalidated without risk
    92         __finish_creation();
     95        __finish_creation(&thrd->self_cor);
    9396
    94         // Fetch the thread handle from the user defined thread structure
    95         struct thread_desc* thrd = get_thread( this );
     97        // Restore the last to NULL, we clobbered because of the thunk problem
    9698        thrd->self_cor.last = NULL;
    9799
  • libcfa/src/concurrency/invoke.h

    r69c37cc rf343c6b  
    5050
    5151                extern thread_local struct KernelThreadData {
    52                         struct coroutine_desc * volatile this_coroutine;
    5352                        struct thread_desc    * volatile this_thread;
    5453                        struct processor      * volatile this_processor;
     
    6160                } kernelTLS __attribute__ ((tls_model ( "initial-exec" )));
    6261        }
    63 
    64         static inline struct coroutine_desc * volatile active_coroutine() { return TL_GET( this_coroutine ); }
    65         static inline struct thread_desc    * volatile active_thread   () { return TL_GET( this_thread    ); }
    66         static inline struct processor      * volatile active_processor() { return TL_GET( this_processor ); } // UNSAFE
    6762        #endif
    6863
     
    170165                        struct thread_desc * prev;
    171166                } node;
    172      };
    173 
    174      #ifdef __cforall
    175      extern "Cforall" {
     167        };
     168
     169        #ifdef __cforall
     170        extern "Cforall" {
     171                static inline struct coroutine_desc * volatile active_coroutine() { return TL_GET( this_thread )->curr_cor; }
     172                static inline struct thread_desc    * volatile active_thread   () { return TL_GET( this_thread    ); }
     173                static inline struct processor      * volatile active_processor() { return TL_GET( this_processor ); } // UNSAFE
     174
    176175                static inline thread_desc * & get_next( thread_desc & this ) {
    177176                        return this.next;
     
    232231        extern void CtxInvokeStub( void );
    233232        void CtxSwitch( void * from, void * to ) asm ("CtxSwitch");
     233        // void CtxStore ( void * this ) asm ("CtxStore");
     234        // void CtxRet   ( void * dst  ) asm ("CtxRet");
    234235
    235236        #if   defined( __i386 )
  • libcfa/src/concurrency/kernel.cfa

    r69c37cc rf343c6b  
    6060        NULL,
    6161        NULL,
    62         NULL,
    6362        { 1, false, false }
    6463};
     
    263262static void returnToKernel() {
    264263        coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner);
    265         coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor = kernelTLS.this_coroutine;
     264        coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor;
    266265        ThreadCtxSwitch(thrd_cor, proc_cor);
    267266}
     
    307306        processor * proc = (processor *) arg;
    308307        kernelTLS.this_processor = proc;
    309         kernelTLS.this_coroutine = NULL;
    310308        kernelTLS.this_thread    = NULL;
    311309        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
     
    321319
    322320        //Set global state
    323         kernelTLS.this_coroutine = get_coroutine(proc->runner);
    324321        kernelTLS.this_thread    = NULL;
    325322
     
    351348// KERNEL_ONLY
    352349void kernel_first_resume(processor * this) {
    353         coroutine_desc * src = kernelTLS.this_coroutine;
     350        coroutine_desc * src = mainThread->curr_cor;
    354351        coroutine_desc * dst = get_coroutine(this->runner);
    355352
     
    366363        // set state of current coroutine to inactive
    367364        src->state = src->state == Halted ? Halted : Inactive;
    368 
    369         // set new coroutine that task is executing
    370         kernelTLS.this_coroutine = dst;
    371365
    372366        // SKULLDUGGERY normally interrupts are enable before leaving a coroutine ctxswitch.
     
    599593        kernelTLS.this_processor = mainProcessor;
    600594        kernelTLS.this_thread    = mainThread;
    601         kernelTLS.this_coroutine = &mainThread->self_cor;
    602595
    603596        // Enable preemption
     
    720713                __cfaabi_dbg_bits_write( abort_text, len );
    721714
    722                 if ( get_coroutine(thrd) != kernelTLS.this_coroutine ) {
    723                         len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", kernelTLS.this_coroutine->name, kernelTLS.this_coroutine );
     715                if ( &thrd->self_cor != thrd->curr_cor ) {
     716                        len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", thrd->curr_cor->name, thrd->curr_cor );
    724717                        __cfaabi_dbg_bits_write( abort_text, len );
    725718                }
  • libcfa/src/concurrency/thread.cfa

    r69c37cc rf343c6b  
    7575        coroutine_desc* thrd_c = get_coroutine(this);
    7676        thread_desc   * thrd_h = get_thread   (this);
    77         thrd_c->last = TL_GET( this_coroutine );
     77        thrd_c->last = TL_GET( this_thread )->curr_cor;
    7878
    7979        // __cfaabi_dbg_print_safe("Thread start : %p (t %p, c %p)\n", this, thrd_c, thrd_h);
     
    8181        disable_interrupts();
    8282        create_stack(&thrd_c->stack, thrd_c->stack.size);
    83         kernelTLS.this_coroutine = thrd_c;
    8483        CtxStart(&this, CtxInvokeThread);
    8584        assert( thrd_c->last->stack.context );
     
    9291extern "C" {
    9392        // KERNEL ONLY
    94         void __finish_creation(void) {
    95                 coroutine_desc* thrd_c = kernelTLS.this_coroutine;
     93        void __finish_creation(coroutine_desc * thrd_c) {
    9694                ThreadCtxSwitch( thrd_c, thrd_c->last );
    9795        }
     
    120118        // set new coroutine that the processor is executing
    121119        // and context switch to it
    122         kernelTLS.this_coroutine = dst;
    123120        assert( src->stack.context );
    124121        CtxSwitch( src->stack.context, dst->stack.context );
    125         kernelTLS.this_coroutine = src;
    126122
    127123        // set state of new coroutine to active
  • libcfa/src/fstream.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 24 18:33:38 2018
    13 // Update Count     : 304
     12// Last Modified On : Sat Apr 20 12:03:43 2019
     13// Update Count     : 311
    1414//
    1515
     
    2323#include <complex.h>                                                                    // creal, cimag
    2424#include <assert.h>
     25#include <errno.h>                                                                              // errno
    2526
    2627#define IO_MSG "I/O error: "
     
    3233        os.nlOnOff = nlOnOff;
    3334        os.prt = prt;
     35        os.sawNL = false;
    3436        sepSet( os, separator );
    3537        sepSetCur( os, sepGet( os ) );
     
    105107        #ifdef __CFA_DEBUG__
    106108        if ( file == 0 ) {
    107                 fprintf( stderr, IO_MSG "open output file \"%s\", ", name );
    108                 perror( 0 );
    109                 exit( EXIT_FAILURE );
     109                abort( IO_MSG "open output file \"%s\", %s", name, strerror( errno ) );
    110110        } // if
    111111        #endif // __CFA_DEBUG__
     
    121121
    122122        if ( fclose( (FILE *)(os.file) ) == EOF ) {
    123                 perror( IO_MSG "close output" );
     123                abort( IO_MSG "close output %s", strerror( errno ) );
    124124        } // if
    125125} // close
     
    127127ofstream & write( ofstream & os, const char * data, size_t size ) {
    128128        if ( fail( os ) ) {
    129                 fprintf( stderr, "attempt write I/O on failed stream\n" );
    130                 exit( EXIT_FAILURE );
     129                abort( "attempt write I/O on failed stream\n" );
    131130        } // if
    132131
    133132        if ( fwrite( data, 1, size, (FILE *)(os.file) ) != size ) {
    134                 perror( IO_MSG "write" );
    135                 exit( EXIT_FAILURE );
     133                abort( IO_MSG "write %s", strerror( errno ) );
    136134        } // if
    137135        return os;
     
    144142        if ( len == EOF ) {
    145143                if ( ferror( (FILE *)(os.file) ) ) {
    146                         fprintf( stderr, "invalid write\n" );
    147                         exit( EXIT_FAILURE );
     144                        abort( "invalid write\n" );
    148145                } // if
    149146        } // if
     
    166163void ?{}( ifstream & is, void * file ) {
    167164        is.file = file;
     165        is.nlOnOff = false;
    168166}
    169167
     
    177175        open( is, name, "r" );
    178176}
     177
     178void nlOn( ifstream & os ) { os.nlOnOff = true; }
     179void nlOff( ifstream & os ) { os.nlOnOff = false; }
     180bool getANL( ifstream & os ) { return os.nlOnOff; }
    179181
    180182int fail( ifstream & is ) {
     
    187189
    188190void open( ifstream & is, const char * name, const char * mode ) {
    189         FILE *file = fopen( name, mode );
     191        FILE * file = fopen( name, mode );
    190192        #ifdef __CFA_DEBUG__
    191193        if ( file == 0 ) {
    192                 fprintf( stderr, IO_MSG "open input file \"%s\", ", name );
    193                 perror( 0 );
    194                 exit( EXIT_FAILURE );
     194                abort( IO_MSG "open input file \"%s\", %s\n", name, strerror( errno ) );
    195195        } // if
    196196        #endif // __CFA_DEBUG__
     
    206206
    207207        if ( fclose( (FILE *)(is.file) ) == EOF ) {
    208                 perror( IO_MSG "close input" );
     208                abort( IO_MSG "close input %s", strerror( errno ) );
    209209        } // if
    210210} // close
     
    212212ifstream & read( ifstream & is, char * data, size_t size ) {
    213213        if ( fail( is ) ) {
    214                 fprintf( stderr, "attempt read I/O on failed stream\n" );
    215                 exit( EXIT_FAILURE );
     214                abort( "attempt read I/O on failed stream\n" );
    216215        } // if
    217216
    218217        if ( fread( data, size, 1, (FILE *)(is.file) ) == 0 ) {
    219                 perror( IO_MSG "read" );
    220                 exit( EXIT_FAILURE );
     218                abort( IO_MSG "read %s", strerror( errno ) );
    221219        } // if
    222220        return is;
     
    225223ifstream &ungetc( ifstream & is, char c ) {
    226224        if ( fail( is ) ) {
    227                 fprintf( stderr, "attempt ungetc I/O on failed stream\n" );
    228                 exit( EXIT_FAILURE );
     225                abort( "attempt ungetc I/O on failed stream\n" );
    229226        } // if
    230227
    231228        if ( ungetc( c, (FILE *)(is.file) ) == EOF ) {
    232                 perror( IO_MSG "ungetc" );
    233                 exit( EXIT_FAILURE );
     229                abort( IO_MSG "ungetc %s", strerror( errno ) );
    234230        } // if
    235231        return is;
     
    243239        if ( len == EOF ) {
    244240                if ( ferror( (FILE *)(is.file) ) ) {
    245                         fprintf( stderr, "invalid read\n" );
    246                         exit( EXIT_FAILURE );
     241                        abort( "invalid read\n" );
    247242                } // if
    248243        } // if
  • libcfa/src/fstream.hfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 24 18:33:41 2018
    13 // Update Count     : 149
     12// Last Modified On : Sat Apr 20 12:03:58 2019
     13// Update Count     : 151
    1414//
    1515
     
    7373struct ifstream {
    7474        void * file;
     75        bool nlOnOff;
    7576}; // ifstream
    7677
    7778// public
     79void nlOn( ifstream & );
     80void nlOff( ifstream & );
     81bool getANL( ifstream & );
    7882int fail( ifstream & is );
    7983int eof( ifstream & is );
  • libcfa/src/gmp.hfa

    r69c37cc rf343c6b  
    1010// Created On       : Tue Apr 19 08:43:43 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec  4 23:25:51 2018
    13 // Update Count     : 22
     12// Last Modified On : Sat Apr 20 09:01:52 2019
     13// Update Count     : 24
    1414//
    1515
     
    271271
    272272        void ?|?( ostype & os, Int mp ) {
    273                 (ostype)(os | mp); if ( getANL( os ) ) nl( os );
     273                (ostype)(os | mp); nl( os );
    274274        } // ?|?
    275275} // distribution
  • libcfa/src/heap.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Sep  6 09:01:30 2018
    13 // Update Count     : 513
     12// Last Modified On : Fri Mar 22 13:43:10 2019
     13// Update Count     : 514
    1414//
    1515
     
    10341034// Local Variables: //
    10351035// tab-width: 4 //
    1036 // compile-command: "cfa -nodebug -O2 heap.c" //
     1036// compile-command: "cfa -nodebug -O2 heap.cfa" //
    10371037// End: //
  • libcfa/src/iostream.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar  4 20:57:24 2019
    13 // Update Count     : 593
     12// Last Modified On : Sat Apr 20 14:02:43 2019
     13// Update Count     : 617
    1414//
    1515
     
    396396
    397397        istype & ?|?( istype & is, char & c ) {
    398                 fmt( is, "%c", &c );                                                    // must pass pointer through varg to fmt
     398                char temp;
     399                for () {
     400                        fmt( is, "%c", &temp );                                                 // must pass pointer through varg to fmt
     401                        // do not overwrite parameter with newline unless appropriate
     402                        if ( temp != '\n' || getANL( is ) ) { c = temp; break; }
     403                        if ( eof( is ) ) break;
     404                } // for
    399405                return is;
    400406        } // ?|?
     
    498504                return is;
    499505        } // nl
     506
     507        istype & nlOn( istype & is ) {
     508                nlOn( is );                                                                             // call void returning
     509                return is;
     510        } // nlOn
     511
     512        istype & nlOff( istype & is ) {
     513                nlOff( is );                                                                    // call void returning
     514                return is;
     515        } // nlOff
    500516} // distribution
    501517
  • libcfa/src/iostream.hfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 26 16:57:22 2019
    13 // Update Count     : 221
     12// Last Modified On : Sat Apr 20 12:04:07 2019
     13// Update Count     : 226
    1414//
    1515
     
    149149
    150150trait istream( dtype istype ) {
     151        void nlOn( istype & );                                                          // read newline
     152        void nlOff( istype & );                                                         // scan newline
     153        bool getANL( istype & );                                                        // get scan newline (on/off)
    151154        int fail( istype & );
    152155        int eof( istype & );
     
    187190
    188191        // manipulators
     192        istype & nlOn( istype & );
     193        istype & nlOff( istype & );
    189194        istype & ?|?( istype &, istype & (*)( istype & ) );
    190195        istype & nl( istype & is );
  • libcfa/src/rational.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed Apr  6 17:54:28 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 23 22:56:49 2018
    13 // Update Count     : 170
     12// Last Modified On : Thu Mar 28 17:33:03 2019
     13// Update Count     : 181
    1414//
    1515
     
    3535        static RationalImpl simplify( RationalImpl & n, RationalImpl & d ) {
    3636                if ( d == (RationalImpl){0} ) {
    37                         serr | "Invalid rational number construction: denominator cannot be equal to 0.";
    38                         exit( EXIT_FAILURE );
     37                        abort( "Invalid rational number construction: denominator cannot be equal to 0.\n" );
    3938                } // exit
    4039                if ( d < (RationalImpl){0} ) { d = -d; n = -n; } // move sign to numerator
     
    5453        void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ) {
    5554                RationalImpl t = simplify( n, d );                              // simplify
    56                 r.numerator = n / t;
    57                 r.denominator = d / t;
     55                r.[numerator, denominator] = [n / t, d / t];
    5856        } // rational
    5957
     
    7876                RationalImpl prev = r.numerator;
    7977                RationalImpl t = gcd( abs( n ), r.denominator ); // simplify
    80                 r.numerator = n / t;
    81                 r.denominator = r.denominator / t;
     78                r.[numerator, denominator] = [n / t, r.denominator / t];
    8279                return prev;
    8380        } // numerator
     
    8683                RationalImpl prev = r.denominator;
    8784                RationalImpl t = simplify( r.numerator, d );    // simplify
    88                 r.numerator = r.numerator / t;
    89                 r.denominator = d / t;
     85                r.[numerator, denominator] = [r.numerator / t, d / t];
    9086                return prev;
    9187        } // denominator
     
    120116
    121117        Rational(RationalImpl) +?( Rational(RationalImpl) r ) {
    122                 Rational(RationalImpl) t = { r.numerator, r.denominator };
    123                 return t;
     118                return (Rational(RationalImpl)){ r.numerator, r.denominator };
    124119        } // +?
    125120
    126121        Rational(RationalImpl) -?( Rational(RationalImpl) r ) {
    127                 Rational(RationalImpl) t = { -r.numerator, r.denominator };
    128                 return t;
     122                return (Rational(RationalImpl)){ -r.numerator, r.denominator };
    129123        } // -?
    130124
    131125        Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    132126                if ( l.denominator == r.denominator ) {                 // special case
    133                         Rational(RationalImpl) t = { l.numerator + r.numerator, l.denominator };
    134                         return t;
     127                        return (Rational(RationalImpl)){ l.numerator + r.numerator, l.denominator };
    135128                } else {
    136                         Rational(RationalImpl) t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator };
    137                         return t;
     129                        return (Rational(RationalImpl)){ l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator };
    138130                } // if
    139131        } // ?+?
     
    141133        Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    142134                if ( l.denominator == r.denominator ) {                 // special case
    143                         Rational(RationalImpl) t = { l.numerator - r.numerator, l.denominator };
    144                         return t;
     135                        return (Rational(RationalImpl)){ l.numerator - r.numerator, l.denominator };
    145136                } else {
    146                         Rational(RationalImpl) t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator };
    147                         return t;
     137                        return (Rational(RationalImpl)){ l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator };
    148138                } // if
    149139        } // ?-?
    150140
    151141        Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    152                 Rational(RationalImpl) t = { l.numerator * r.numerator, l.denominator * r.denominator };
    153                 return t;
     142                return (Rational(RationalImpl)){ l.numerator * r.numerator, l.denominator * r.denominator };
    154143        } // ?*?
    155144
    156145        Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    157146                if ( r.numerator < (RationalImpl){0} ) {
    158                         r.numerator = -r.numerator;
    159                         r.denominator = -r.denominator;
     147                        r.[numerator, denominator] = [-r.numerator, -r.denominator];
    160148                } // if
    161                 Rational(RationalImpl) t = { l.numerator * r.denominator, l.denominator * r.numerator };
    162                 return t;
     149                return (Rational(RationalImpl)){ l.numerator * r.denominator, l.denominator * r.numerator };
    163150        } // ?/?
    164151
     
    167154        forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } )
    168155        istype & ?|?( istype & is, Rational(RationalImpl) & r ) {
    169                 RationalImpl t;
    170156                is | r.numerator | r.denominator;
    171                 t = simplify( r.numerator, r.denominator );
     157                RationalImpl t = simplify( r.numerator, r.denominator );
    172158                r.numerator /= t;
    173159                r.denominator /= t;
     
    185171        } // distribution
    186172} // distribution
     173
     174forall( otype RationalImpl | arithmetic( RationalImpl ) | { RationalImpl ?\?( RationalImpl, unsigned long ); } )
     175Rational(RationalImpl) ?\?( Rational(RationalImpl) x, long int y ) {
     176        if ( y < 0 ) {
     177                return (Rational(RationalImpl)){ x.denominator \ -y, x.numerator \ -y };
     178        } else {
     179                return (Rational(RationalImpl)){ x.numerator \ y, x.denominator \ y };
     180        } // if
     181}
    187182
    188183// conversion
  • libcfa/src/rational.hfa

    r69c37cc rf343c6b  
    1212// Created On       : Wed Apr  6 17:56:25 2016
    1313// Last Modified By : Peter A. Buhr
    14 // Last Modified On : Tue Dec  4 23:07:46 2018
    15 // Update Count     : 106
     14// Last Modified On : Tue Mar 26 23:16:10 2019
     15// Update Count     : 109
    1616//
    1717
     
    9898} // distribution
    9999
     100forall( otype RationalImpl | arithmetic( RationalImpl ) |{RationalImpl ?\?( RationalImpl, unsigned long );} )
     101Rational(RationalImpl) ?\?( Rational(RationalImpl) x, long int y );
     102
    100103// conversion
    101104forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); } )
  • libcfa/src/stdhdr/stdbool.h

    r69c37cc rf343c6b  
    1010// Created On       : Mon Jul  4 23:25:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Jul  5 20:39:51 2016
    13 // Update Count     : 12
     12// Last Modified On : Mon Mar 25 08:00:08 2019
     13// Update Count     : 15
    1414//
    1515
    1616extern "C" {
    1717#include_next <stdbool.h>                                                               // has internal check for multiple expansion
     18
     19// allows printing as true/false
     20#if defined( true )
     21#undef true
     22#define true ((_Bool)1)
     23#endif // true
     24
     25#if defined( false )
     26#undef false
     27#define false ((_Bool)0)
     28#endif // false
    1829} // extern "C"
    1930
  • libcfa/src/stdlib.hfa

    r69c37cc rf343c6b  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Dec 17 15:37:45 2018
    13 // Update Count     : 346
     12// Last Modified On : Wed Apr 24 17:35:43 2019
     13// Update Count     : 352
    1414//
    1515
     
    4040        } // malloc
    4141
    42         // T & malloc( void ) {
    43         //      int & p = *(T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc
    44         //      printf( "& malloc %p\n", &p );
    45         //      return p;
    46         //      //      return (T &)*(T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc
    47         // } // malloc
    48 
    4942        T * calloc( size_t dim ) {
    5043                return (T *)(void *)calloc( dim, sizeof(T) );   // C calloc
     
    7669        T * alloc( char fill ) {
    7770                T * ptr = (T *)(void *)malloc( (size_t)sizeof(T) );     // C malloc
    78                 return (T *)memset( ptr, (int)fill, sizeof(T) );        // initial with fill value
     71                return (T *)memset( ptr, (int)fill, sizeof(T) ); // initialize with fill value
    7972        } // alloc
    8073
     
    8477
    8578        T * alloc( size_t dim, char fill ) {
    86                 T * ptr = (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C malloc
    87                 return (T *)memset( ptr, (int)fill, dim * sizeof(T) );    // initial with fill value
     79                T * ptr = (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C calloc
     80                return (T *)memset( ptr, (int)fill, dim * sizeof(T) ); // initialize with fill value
    8881        } // alloc
    8982
  • src/Common/PassVisitor.cc

    r69c37cc rf343c6b  
    1717
    1818PassVisitorStats pass_visitor_stats;
     19Stats::Counters::SimpleCounter* BaseSyntaxNode::new_nodes = nullptr;
  • src/Common/Stats/Counter.h

    r69c37cc rf343c6b  
    3737                        class SimpleCounter {
    3838                        public:
     39                                inline void operator++() {}
    3940                                inline void operator++(int) {}
    4041                                inline void operator+=(size_t) {}
     
    8485                                virtual void print(std::ostream & os) override { os << count; }
    8586
     87                                inline void operator++()             { if(!enabled) return; count++;        }
    8688                                inline void operator++(int)          { if(!enabled) return; count++;        }
    8789                                inline void operator+=(size_t value) { if(!enabled) return; count += value; }
  • src/ControlStruct/ForExprMutator.cc

    r69c37cc rf343c6b  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Aug 18 10:22:00 2017
    13 // Update Count     : 12
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Mar 11 22:26:52 2019
     13// Update Count     : 14
    1414//
    1515
     
    2121
    2222namespace ControlStruct {
    23         Statement *hoist( Statement *originalStmt, std::list<Statement *> &init ) {
     23        Statement * hoist( Statement * originalStmt, std::list<Statement *> & init ) {
    2424                // If no hoisting is needed, skip:
    2525                if ( 0 == init.size() ) {
     
    2929                // Create compound statement, move initializers outside,
    3030                // the resut of the original stays as is.
    31                 CompoundStmt *block = new CompoundStmt();
    32                 std::list<Statement *> &stmts = block->get_kids();
     31                CompoundStmt * block = new CompoundStmt();
     32                std::list<Statement *> & stmts = block->get_kids();
    3333                stmts.splice( stmts.end(), init );
    3434
     
    3838        }
    3939
    40         Statement *ForExprMutator::postmutate( IfStmt *ifStmt ) {
     40        Statement * ForExprMutator::postmutate( IfStmt * ifStmt ) {
    4141                return hoist( ifStmt, ifStmt->initialization );
    4242        }
    43         Statement *ForExprMutator::postmutate( ForStmt *forStmt ) {
     43        Statement * ForExprMutator::postmutate( ForStmt * forStmt ) {
    4444                // hoist any initializer declarations to make them C89 (rather than C99)
    4545                return hoist( forStmt, forStmt->initialization );
    4646        }
    47         Statement *ForExprMutator::postmutate( WhileStmt *whileStmt ) {
     47        Statement * ForExprMutator::postmutate( WhileStmt * whileStmt ) {
    4848                return hoist( whileStmt, whileStmt->initialization );
    4949        }
  • src/ControlStruct/LabelFixer.cc

    r69c37cc rf343c6b  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Rob Schluntz
    12 // Last Modified On : Tue Jul 28 13:32:43 2015
    13 // Update Count     : 156
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Mar 11 22:26:02 2019
     13// Update Count     : 159
    1414//
    1515
     
    3232        }
    3333
    34         LabelFixer::LabelFixer( LabelGenerator *gen ) : generator ( gen ) {
     34        LabelFixer::LabelFixer( LabelGenerator * gen ) : generator ( gen ) {
    3535                if ( generator == 0 )
    3636                        generator = LabelGenerator::getGenerator();
     
    4949
    5050        // prune to at most one label definition for each statement
    51         void LabelFixer::previsit( Statement *stmt ) {
     51        void LabelFixer::previsit( Statement * stmt ) {
    5252                std::list< Label > &labels = stmt->get_labels();
    5353
     
    5858        }
    5959
    60         void LabelFixer::previsit( BranchStmt *branchStmt ) {
     60        void LabelFixer::previsit( BranchStmt * branchStmt ) {
    6161                previsit( ( Statement *)branchStmt );
    6262
     
    7575
    7676
    77         // sets the definition of the labelTable entry to be the provided
    78         // statement for every label in the list parameter. Happens for every kind of statement
    79         Label LabelFixer::setLabelsDef( std::list< Label > &llabel, Statement *definition ) {
     77        // sets the definition of the labelTable entry to be the provided statement for every label in the list
     78        // parameter. Happens for every kind of statement
     79        Label LabelFixer::setLabelsDef( std::list< Label > & llabel, Statement * definition ) {
    8080                assert( definition != 0 );
    8181                assert( llabel.size() > 0 );
     
    100100                } // for
    101101
    102                 // produce one of the labels attached to this statement to be
    103                 // temporarily used as the canonical label
     102                // produce one of the labels attached to this statement to be temporarily used as the canonical label
    104103                return labelTable[ llabel.front() ]->get_label();
    105104        }
     
    117116
    118117        // Builds a table that maps a label to its defining statement.
    119         std::map<Label, Statement * > *LabelFixer::resolveJumps() throw ( SemanticErrorException ) {
     118        std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) {
    120119                std::map< Label, Statement * > *ret = new std::map< Label, Statement * >();
    121120                for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) {
  • src/ControlStruct/LabelGenerator.cc

    r69c37cc rf343c6b  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Aug 14 14:14:00 2015
    13 // Update Count     : 14
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Mar 11 22:23:20 2019
     13// Update Count     : 15
    1414//
    1515
     
    2424
    2525namespace ControlStruct {
    26         LabelGenerator *LabelGenerator::labelGenerator = 0;
     26        LabelGenerator * LabelGenerator::labelGenerator = 0;
    2727
    28         LabelGenerator *LabelGenerator::getGenerator() {
     28        LabelGenerator * LabelGenerator::getGenerator() {
    2929                if ( LabelGenerator::labelGenerator == 0 )
    3030                        LabelGenerator::labelGenerator = new LabelGenerator();
    31 
    3231                return labelGenerator;
    3332        }
     
    3837                if ( stmt && ! stmt->get_labels().empty() ) {
    3938                        os << "_" << stmt->get_labels().front() << "__";
    40                 }
     39                } // if
    4140                std::string ret = os.str();
    4241                Label l( ret );
  • src/Parser/ParseNode.h

    r69c37cc rf343c6b  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 13 17:36:49 2019
    13 // Update Count     : 867
     12// Last Modified On : Mon Apr 15 14:22:39 2019
     13// Update Count     : 874
    1414//
    1515
     
    132132        void printOneLine( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
    133133
    134         Expression *get_expr() const { return expr.get(); }
    135134        template<typename T>
    136135        bool isExpressionType() const { return nullptr != dynamic_cast<T>(expr.get()); }
    137136
    138137        Expression * build() const { return const_cast<ExpressionNode *>(this)->expr.release(); }
     138
     139        std::unique_ptr<Expression> expr;                                       // public because of lifetime implications
    139140  private:
    140141        bool extension = false;
    141         std::unique_ptr<Expression> expr;
    142142}; // ExpressionNode
    143143
  • src/Parser/lex.ll

    r69c37cc rf343c6b  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Sun Mar 10 09:13:09 2019
    13  * Update Count     : 706
     12 * Last Modified On : Wed Mar 13 14:54:30 2019
     13 * Update Count     : 707
    1414 */
    1515
     
    226226char                    { KEYWORD_RETURN(CHAR); }
    227227choose                  { KEYWORD_RETURN(CHOOSE); }                             // CFA
     228coerce                  { KEYWORD_RETURN(COERCE); }                             // CFA
    228229_Complex                { KEYWORD_RETURN(COMPLEX); }                    // C99
    229230__complex               { KEYWORD_RETURN(COMPLEX); }                    // GCC
  • src/Parser/parser.yy

    r69c37cc rf343c6b  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 21 08:45:07 2019
    13 // Update Count     : 4232
     12// Last Modified On : Mon Apr 15 15:02:56 2019
     13// Update Count     : 4290
    1414//
    1515
     
    185185
    186186ForCtrl * forCtrl( ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    187         ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->get_expr());
     187        ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->expr.get());
    188188        if ( constant && (constant->get_constant()->get_value() == "0" || constant->get_constant()->get_value() == "1") ) {
    189189        type = new ExpressionNode( new CastExpr( maybeMoveBuild< Expression >(type), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ) );
     
    198198
    199199ForCtrl * forCtrl( ExpressionNode * type, ExpressionNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
    200         if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->get_expr()) ) {
     200        if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->expr.get()) ) {
    201201                return forCtrl( type, new string( identifier->name ), start, compop, comp, inc );
    202         } else if ( CommaExpr * commaExpr = dynamic_cast<CommaExpr *>(index->get_expr()) ) {
     202        } else if ( CommaExpr * commaExpr = dynamic_cast<CommaExpr *>(index->expr.get()) ) {
    203203                if ( NameExpr * identifier = dynamic_cast<NameExpr *>(commaExpr->arg1 ) ) {
    204204                        return forCtrl( type, new string( identifier->name ), start, compop, comp, inc );
     
    265265%token RESTRICT                                                                                 // C99
    266266%token ATOMIC                                                                                   // C11
    267 %token FORALL MUTEX VIRTUAL                                                             // CFA
     267%token FORALL MUTEX VIRTUAL COERCE                                              // CFA
    268268%token VOID CHAR SHORT INT LONG FLOAT DOUBLE SIGNED UNSIGNED
    269269%token BOOL COMPLEX IMAGINARY                                                   // C99
     
    334334%type<en> subrange
    335335%type<decl> asm_name_opt
    336 %type<en> asm_operands_opt asm_operands_list asm_operand
     336%type<en> asm_operands_opt                              asm_operands_list                       asm_operand
    337337%type<label> label_list
    338338%type<en> asm_clobbers_list_opt
    339339%type<flag> asm_volatile_opt
    340340%type<en> handler_predicate_opt
    341 %type<genexpr> generic_association generic_assoc_list
     341%type<genexpr> generic_association              generic_assoc_list
    342342
    343343// statements
     
    795795        | '(' type_no_function ')' cast_expression
    796796                { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
     797                // keyword cast cannot be grouped because of reduction in aggregate_key
    797798        | '(' COROUTINE '&' ')' cast_expression                         // CFA
    798799                { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); }
     
    806807        | '(' VIRTUAL type_no_function ')' cast_expression      // CFA
    807808                { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild< Expression >( $5 ), maybeMoveBuildType( $3 ) ) ); }
     809        | '(' RETURN type_no_function ')' cast_expression       // CFA
     810                { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; }
     811        | '(' COERCE type_no_function ')' cast_expression       // CFA
     812                { SemanticError( yylloc, "Coerce cast is currently unimplemented." ); $$ = nullptr; }
     813        | '(' qualifier_cast_list ')' cast_expression           // CFA
     814                { SemanticError( yylloc, "Qualifier cast is currently unimplemented." ); $$ = nullptr; }
    808815//      | '(' type_no_function ')' tuple
    809816//              { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
     817        ;
     818
     819qualifier_cast_list:
     820        cast_modifier type_qualifier_name
     821        | cast_modifier MUTEX
     822        | qualifier_cast_list cast_modifier type_qualifier_name
     823        | qualifier_cast_list cast_modifier MUTEX
     824        ;
     825
     826cast_modifier:
     827        '-'
     828        | '+'
    810829        ;
    811830
     
    11451164        for_control_expression
    11461165        | for_control_expression_list ':' for_control_expression
    1147                 { $$ = $3; }
     1166                // ForCtrl + ForCtrl:
     1167                //    init + init => multiple declaration statements that are hoisted
     1168                //    condition + condition => (expression) && (expression)
     1169                //    change + change => (expression), (expression)
     1170                {
     1171                        $1->init->set_last( $3->init );
     1172                        if ( $1->condition ) {
     1173                                if ( $3->condition ) {
     1174                                        $1->condition->expr.reset( new LogicalExpr( $1->condition->expr.release(), $3->condition->expr.release(), true ) );
     1175                                } // if
     1176                        } else $1->condition = $3->condition;
     1177                        if ( $1->change ) {
     1178                                if ( $3->change ) {
     1179                                        $1->change->expr.reset( new CommaExpr( $1->change->expr.release(), $3->change->expr.release() ) );
     1180                                } // if
     1181                        } else $1->change = $3->change;
     1182                        $$ = $1;
     1183                }
    11481184        ;
    11491185
     
    11551191        | declaration comma_expression_opt ';' comma_expression_opt // C99, declaration has ';'
    11561192                { $$ = new ForCtrl( $1, $2, $4 ); }
     1193
    11571194        | comma_expression                                                                      // CFA
    11581195                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
     
    11691206        | comma_expression ';' comma_expression inclexcl comma_expression '~' comma_expression // CFA
    11701207                { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, $7 ); }
     1208
     1209                // There is a S/R conflicit if ~ and -~ are factored out.
     1210        | comma_expression ';' comma_expression '~' '@'         // CFA
     1211                { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
     1212        | comma_expression ';' comma_expression ErangeDown '@' // CFA
     1213                { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::GThan, nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
    11711214        | comma_expression ';' comma_expression '~' '@' '~' comma_expression // CFA
    11721215                { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, $7 ); }
  • src/ResolvExpr/AlternativeFinder.cc

    r69c37cc rf343c6b  
    258258                        // - necessary pre-requisite to pruning
    259259                        AltList candidates;
     260                        std::list<std::string> errors;
    260261                        for ( unsigned i = 0; i < alternatives.size(); ++i ) {
    261                                 resolveAssertions( alternatives[i], indexer, candidates );
     262                                resolveAssertions( alternatives[i], indexer, candidates, errors );
    262263                        }
    263264                        // fail early if none such
    264265                        if ( mode.failFast && candidates.empty() ) {
    265266                                std::ostringstream stream;
    266                                 stream << "No resolvable alternatives for expression " << expr << "\n"
    267                                        << "Alternatives with failing assertions are:\n";
    268                                 printAlts( alternatives, stream, 1 );
     267                                stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     268                                //        << "Alternatives with failing assertions are:\n";
     269                                // printAlts( alternatives, stream, 1 );
     270                                for ( const auto& err : errors ) {
     271                                        stream << err;
     272                                }
    269273                                SemanticError( expr->location, stream.str() );
    270274                        }
  • src/ResolvExpr/ResolveAssertions.cc

    r69c37cc rf343c6b  
    2020#include <list>                     // for list
    2121#include <memory>                   // for unique_ptr
    22 #include <string>
     22#include <sstream>                  // for ostringstream
     23#include <string>                   // for string
    2324#include <unordered_map>            // for unordered_map, unordered_multimap
    2425#include <utility>                  // for move
     
    2728#include "Alternative.h"            // for Alternative, AssertionItem, AssertionList
    2829#include "Common/FilterCombos.h"    // for filterCombos
     30#include "Common/Indenter.h"        // for Indenter
    2931#include "Common/utility.h"         // for sort_mins
    3032#include "ResolvExpr/RenameVars.h"  // for renameTyVars
     
    9799                        return { item, item.matches[i] };
    98100                }
     101
     102                const DeclarationWithType* get_decl() const { return cache->at(key).deferIds[0].decl; }
    99103
    100104                // sortable by key
     
    364368        static const int recursionLimit = /* 10 */ 4;
    365369
    366         void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out ) {
     370        void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out, std::list<std::string>& errors ) {
    367371                // finish early if no assertions to resolve
    368372                if ( alt.need.empty() ) {
     
    385389                                for ( auto& assn : resn.need ) {
    386390                                        // fail early if any assertion is not resolvable
    387                                         if ( ! resolveAssertion( assn, resn, assnCache ) ) goto nextResn;
     391                                        if ( ! resolveAssertion( assn, resn, assnCache ) ) {
     392                                                Indenter tabs{ Indenter::tabsize, 3 };
     393                                                std::ostringstream ss;
     394                                                ss << tabs << "Unsatisfiable alternative:\n";
     395                                                resn.alt.print( ss, ++tabs );
     396                                                ss << --tabs << "Could not satisfy assertion:\n";
     397                                                assn.decl->print( ss, ++tabs );
     398                                               
     399                                                errors.emplace_back( ss.str() );
     400                                                goto nextResn;
     401                                        }
    388402                                }
    389403
     
    404418                                                resn.deferred,
    405419                                                CandidateEnvMerger{ resn.alt.env, resn.alt.openVars, resn.indexer } );
     420                                        // fail early if no mutually-compatible assertion satisfaction
     421                                        if ( compatible.empty() ) {
     422                                                Indenter tabs{ Indenter::tabsize, 3 };
     423                                                std::ostringstream ss;
     424                                                ss << tabs << "Unsatisfiable alternative:\n";
     425                                                resn.alt.print( ss, ++tabs );
     426                                                ss << --tabs << "No mutually-compatible satisfaction for assertions:\n";
     427                                                ++tabs;
     428                                                for ( const auto& d : resn.deferred ) {
     429                                                        d.get_decl()->print( ss, tabs );
     430                                                }
     431
     432                                                errors.emplace_back( ss.str() );
     433                                                goto nextResn;
     434                                        }
    406435                                        // sort by cost
    407436                                        CandidateCost coster{ resn.indexer };
  • src/ResolvExpr/ResolveAssertions.h

    r69c37cc rf343c6b  
    2424namespace ResolvExpr {
    2525        /// Recursively resolves all assertions provided in an alternative; returns true iff succeeds
    26         void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out );
     26        void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out, std::list<std::string>& errors );
    2727} // namespace ResolvExpr
    2828
  • src/ResolvExpr/TypeEnvironment.cc

    r69c37cc rf343c6b  
    386386        }
    387387
    388         bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
     388        bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2,
     389                        TypeDecl::Data && data, AssertionSet &need, AssertionSet &have,
     390                        const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
    389391
    390392                auto class1 = internal_lookup( var1->get_name() );
     
    428430                                        class1->set_type( common );
    429431                                }
     432                                class1->data.isComplete |= data.isComplete;
    430433                                env.erase( class2 );
    431434                        } else return false;
     
    435438                                class1->vars.insert( class2->vars.begin(), class2->vars.end() );
    436439                                class1->allowWidening = widen1;
     440                                class1->data.isComplete |= data.isComplete;
    437441                                env.erase( class2 );
    438442                        } else {
    439443                                class2->vars.insert( class1->vars.begin(), class1->vars.end() );
    440444                                class2->allowWidening = widen2;
     445                                class2->data.isComplete |= data.isComplete;
    441446                                env.erase( class1 );
    442447                        } // if
     
    445450                        class1->vars.insert( var2->get_name() );
    446451                        class1->allowWidening = widen1;
     452                        class1->data.isComplete |= data.isComplete;
    447453                } else if ( class2 != env.end() ) {
    448454                        // var1 unbound, add to class2
    449455                        class2->vars.insert( var1->get_name() );
    450456                        class2->allowWidening = widen2;
     457                        class2->data.isComplete |= data.isComplete;
    451458                } else {
    452459                        // neither var bound, create new class
  • src/ResolvExpr/TypeEnvironment.h

    r69c37cc rf343c6b  
    139139                /// Binds the type classes represented by `var1` and `var2` together; will add
    140140                /// one or both classes if needed. Returns false on failure.
    141                 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
     141                bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
    142142
    143143                /// Disallows widening for all bindings in the environment
  • src/ResolvExpr/Unify.cc

    r69c37cc rf343c6b  
    172172                bool isopen2 = var2 && ( entry2 != openVars.end() );
    173173
    174                 if ( isopen1 && isopen2 && entry1->second == entry2->second ) {
    175                         result = env.bindVarToVar( var1, var2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );
     174                if ( isopen1 && isopen2 ) {
     175                        if ( entry1->second.kind != entry2->second.kind ) {
     176                                result = false;
     177                        } else {
     178                                result = env.bindVarToVar(
     179                                        var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,
     180                                        haveAssertions, openVars, widenMode, indexer );
     181                        }
    176182                } else if ( isopen1 ) {
    177183                        result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );
  • src/SymTab/Indexer.cc

    r69c37cc rf343c6b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:37:33 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 17 16:08:40 2017
    13 // Update Count     : 20
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Fri Mar  8 13:55:00 2019
     13// Update Count     : 21
    1414//
    1515
     
    1717
    1818#include <cassert>                 // for assert, strict_dynamic_cast
    19 #include <iostream>                // for operator<<, basic_ostream, ostream
    2019#include <string>                  // for string, operator<<, operator!=
     20#include <memory>                  // for shared_ptr, make_shared
    2121#include <unordered_map>           // for operator!=, unordered_map<>::const...
    2222#include <unordered_set>           // for unordered_set
    2323#include <utility>                 // for pair, make_pair, move
     24#include <vector>                  // for vector
    2425
    2526#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
    2627#include "Common/SemanticError.h"  // for SemanticError
    2728#include "Common/utility.h"        // for cloneAll
    28 #include "Common/Stats/Counter.h" // for counters
    29 #include "GenPoly/GenPoly.h"
     29#include "Common/Stats/Counter.h"  // for counters
     30#include "GenPoly/GenPoly.h"       // for getFunctionType
    3031#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
    3132#include "Mangler.h"               // for Mangler
     
    3940#include "SynTree/Type.h"          // for Type, StructInstType, UnionInstType
    4041
    41 #define debugPrint(x) if ( doDebug ) { std::cerr << x; }
    42 
    4342namespace SymTab {
    4443
    4544        // Statistics block
    4645        namespace {
    47 
    48                 static inline auto stats_idtable() {
    49                         using namespace Stats::Counters;
    50                         static auto group = build<CounterGroup>("IdTable");
    51                         static struct {
    52                                 SimpleCounter * find;
    53                                 AverageCounter<double> * size;
    54                                 AverageCounter<double> * key;
    55                         } ret = {
    56                                 .find = build<SimpleCounter>("Find calls", group),
    57                                 .size = build<AverageCounter<double>>("Average Size", group),
    58                                 .key  = build<AverageCounter<double>>("Average Key Size", group),
    59                         };
    60                         return ret;
    61                 }
    62 
    63                 static inline auto stats_indexers() {
     46                static inline auto stats() {
    6447                        using namespace Stats::Counters;
    6548                        static auto group   = build<CounterGroup>("Indexers");
     
    6750                                SimpleCounter * count;
    6851                                AverageCounter<double> * size;
    69                                 AverageCounter<double> * depth_a;
    70                                 MaxCounter<size_t> * depth_m;
     52                                SimpleCounter * new_scopes;
     53                                SimpleCounter * lazy_scopes;
     54                                AverageCounter<double> * avg_scope_depth;
     55                                MaxCounter<size_t> * max_scope_depth;
     56                                SimpleCounter * add_calls;
     57                                SimpleCounter * lookup_calls;
     58                                SimpleCounter * map_lookups;
     59                                SimpleCounter * map_mutations;
    7160                        } ret = {
    7261                                .count   = build<SimpleCounter>("Count", group),
    7362                                .size    = build<AverageCounter<double>>("Average Size", group),
    74                                 .depth_a = build<AverageCounter<double>>("Average Depth", group),
    75                                 .depth_m = build<MaxCounter<size_t>>("Max Depth", group),
     63                                .new_scopes = build<SimpleCounter>("Scopes", group),
     64                                .lazy_scopes = build<SimpleCounter>("Lazy Scopes", group),
     65                                .avg_scope_depth = build<AverageCounter<double>>("Average Scope", group),
     66                                .max_scope_depth = build<MaxCounter<size_t>>("Max Scope", group),
     67                                .add_calls = build<SimpleCounter>("Add Calls", group),
     68                                .lookup_calls = build<SimpleCounter>("Lookup Calls", group),
     69                                .map_lookups = build<SimpleCounter>("Map Lookups", group),
     70                                .map_mutations = build<SimpleCounter>("Map Mutations", group)
    7671                        };
    7772                        return ret;
     
    7974        }
    8075
    81         std::ostream & operator<<( std::ostream & out, const Indexer::IdData & data ) {
    82                 return out << "(" << data.id << "," << data.baseExpr << ")";
    83         }
    84 
    85         typedef std::unordered_map< std::string, Indexer::IdData > MangleTable;
    86         typedef std::unordered_map< std::string, MangleTable > IdTable;
    87         typedef std::unordered_map< std::string, NamedTypeDecl* > TypeTable;
    88         typedef std::unordered_map< std::string, StructDecl* > StructTable;
    89         typedef std::unordered_map< std::string, EnumDecl* > EnumTable;
    90         typedef std::unordered_map< std::string, UnionDecl* > UnionTable;
    91         typedef std::unordered_map< std::string, TraitDecl* > TraitTable;
    92 
    93         void dump( const IdTable &table, std::ostream &os ) {
    94                 for ( IdTable::const_iterator id = table.begin(); id != table.end(); ++id ) {
    95                         for ( MangleTable::const_iterator mangle = id->second.begin(); mangle != id->second.end(); ++mangle ) {
    96                                 os << mangle->second << std::endl;
    97                         }
    98                 }
    99         }
    100 
    101         template< typename Decl >
    102         void dump( const std::unordered_map< std::string, Decl* > &table, std::ostream &os ) {
    103                 for ( typename std::unordered_map< std::string, Decl* >::const_iterator it = table.begin(); it != table.end(); ++it ) {
    104                         os << it->second << std::endl;
    105                 } // for
    106         }
    107 
    108         struct Indexer::Impl {
    109                 Impl( unsigned long _scope ) : refCount(1), scope( _scope ), size( 0 ), base(),
    110                                 idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {}
    111                 Impl( unsigned long _scope, Indexer &&_base ) : refCount(1), scope( _scope ), size( 0 ), base( _base ),
    112                                 idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {}
    113                 unsigned long refCount;   ///< Number of references to these tables
    114                 unsigned long scope;      ///< Scope these tables are associated with
    115                 unsigned long size;       ///< Number of elements stored in this table
    116                 const Indexer base;       ///< Base indexer this extends
    117 
    118                 IdTable idTable;          ///< Identifier namespace
    119                 TypeTable typeTable;      ///< Type namespace
    120                 StructTable structTable;  ///< Struct namespace
    121                 EnumTable enumTable;      ///< Enum namespace
    122                 UnionTable unionTable;    ///< Union namespace
    123                 TraitTable traitTable;    ///< Trait namespace
    124         };
    125 
    126         Indexer::Impl *Indexer::newRef( Indexer::Impl *toClone ) {
    127                 if ( ! toClone ) return 0;
    128 
    129                 // shorten the search chain by skipping empty links
    130                 Indexer::Impl *ret = toClone->size == 0 ? toClone->base.tables : toClone;
    131                 if ( ret ) { ++ret->refCount; }
    132 
    133                 return ret;
    134         }
    135 
    136         void Indexer::deleteRef( Indexer::Impl *toFree ) {
    137                 if ( ! toFree ) return;
    138 
    139                 if ( --toFree->refCount == 0 ) delete toFree;
    140         }
    141 
    142         void Indexer::removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const {
    143                 // only need to perform this step for constructors, destructors, and assignment functions
    144                 if ( ! CodeGen::isCtorDtorAssign( id ) ) return;
    145 
    146                 // helpful data structure to organize properties for a type
    147                 struct ValueType {
    148                         struct DeclBall { // properties for this particular decl
    149                                 IdData decl;
    150                                 bool isUserDefinedFunc;
    151                                 bool isCopyFunc;
    152                         };
    153                         // properties for this type
    154                         bool existsUserDefinedCopyFunc = false;    // user-defined copy ctor found
    155                         BaseSyntaxNode * deleteStmt = nullptr;     // non-null if a user-defined function is found
    156                         std::list< DeclBall > decls;
    157 
    158                         // another FunctionDecl for the current type was found - determine
    159                         // if it has special properties and update data structure accordingly
    160                         ValueType & operator+=( IdData data ) {
    161                                 DeclarationWithType * function = data.id;
    162                                 bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
    163                                 bool isCopyFunc = InitTweak::isCopyFunction( function, function->name );
    164                                 decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } );
    165                                 existsUserDefinedCopyFunc = existsUserDefinedCopyFunc || (isUserDefinedFunc && isCopyFunc);
    166                                 if ( isUserDefinedFunc && ! deleteStmt ) {
    167                                         // any user-defined function can act as an implicit delete statement for generated constructors.
    168                                         // a delete stmt should not act as an implicit delete statement.
    169                                         deleteStmt = data.id;
    170                                 }
    171                                 return *this;
    172                         }
    173                 }; // ValueType
    174 
    175                 std::list< IdData > copy;
    176                 copy.splice( copy.end(), out );
    177 
    178                 // organize discovered declarations by type
    179                 std::unordered_map< std::string, ValueType > funcMap;
    180                 for ( auto decl : copy ) {
    181                         if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) {
    182                                 std::list< DeclarationWithType * > & params = function->type->parameters;
    183                                 assert( ! params.empty() );
    184                                 // use base type of pointer, so that qualifiers on the pointer type aren't considered.
    185                                 Type * base = InitTweak::getPointerBase( params.front()->get_type() );
    186                                 assert( base );
    187                                 funcMap[ Mangler::mangle( base ) ] += decl;
    188                         } else {
    189                                 out.push_back( decl );
    190                         }
    191                 }
    192 
    193                 // if a type contains user defined ctor/dtor/assign, then special rules trigger, which determine
    194                 // the set of ctor/dtor/assign that can be used  by the requester. In particular, if the user defines
    195                 // a default ctor, then the generated default ctor is unavailable, likewise for copy ctor
    196                 // and dtor. If the user defines any ctor/dtor, then no generated field ctors are available.
    197                 // If the user defines any ctor then the generated default ctor is unavailable (intrinsic default
    198                 // ctor must be overridden exactly). If the user defines anything that looks like a copy constructor,
    199                 // then the generated copy constructor is unavailable, and likewise for the assignment operator.
    200                 for ( std::pair< const std::string, ValueType > & pair : funcMap ) {
    201                         ValueType & val = pair.second;
    202                         for ( ValueType::DeclBall ball : val.decls ) {
    203                                 bool isNotUserDefinedFunc = ! ball.isUserDefinedFunc && ball.decl.id->linkage != LinkageSpec::Intrinsic;
    204                                 bool isCopyFunc = ball.isCopyFunc;
    205                                 bool existsUserDefinedCopyFunc = val.existsUserDefinedCopyFunc;
    206 
    207                                 // only implicitly delete non-user defined functions that are not intrinsic, and are
    208                                 // not copy functions (assignment or copy constructor). If a  user-defined copy function exists,
    209                                 // do not pass along the non-user-defined copy functions since signatures do not have to match,
    210                                 // and the generated functions will often be cheaper.
    211                                 if ( isNotUserDefinedFunc ) {
    212                                         if ( isCopyFunc ) {
    213                                                 // Skip over non-user-defined copy functions when there is a user-defined copy function.
    214                                                 // Since their signatures do not have to be exact, deleting them is the wrong choice.
    215                                                 if ( existsUserDefinedCopyFunc ) continue;
    216                                         } else {
    217                                                 // delete non-user-defined non-copy functions if applicable.
    218                                                 // deleteStmt will be non-null only if a user-defined function is found.
    219                                                 ball.decl.deleteStmt = val.deleteStmt;
    220                                         }
    221                                 }
    222                                 out.push_back( ball.decl );
    223                         }
    224                 }
    225         }
    226 
    227         void Indexer::makeWritable() {
    228                 if ( ! tables ) {
    229                         // create indexer if not yet set
    230                         tables = new Indexer::Impl( scope );
    231                 } else if ( tables->refCount > 1 || tables->scope != scope ) {
    232                         // make this indexer the base of a fresh indexer at the current scope
    233                         tables = new Indexer::Impl( scope, std::move( *this ) );
    234                 }
    235         }
    236 
    237         Indexer::Indexer() : tables( 0 ), scope( 0 ) {
    238                 (*stats_indexers().count)++;
    239         }
    240 
    241         Indexer::Indexer( const Indexer &that ) : doDebug( that.doDebug ), tables( newRef( that.tables ) ), scope( that.scope ) {
    242                 (*stats_indexers().count)++;
    243         }
    244 
    245         Indexer::Indexer( Indexer &&that ) : doDebug( that.doDebug ), tables( that.tables ), scope( that.scope ) {
    246                 that.tables = 0;
    247         }
     76        Indexer::Indexer()
     77        : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
     78          prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }
    24879
    24980        Indexer::~Indexer() {
    250                 if(tables) {
    251                         stats_indexers().size->push( tables->idTable.size() );
    252                         size_t depth = 1;
    253                         for( auto crnt = tables->base.tables; crnt; crnt = crnt->base.tables ) {
    254                                 ++depth;
    255                         }
    256                         stats_indexers().depth_a->push( depth );
    257                         stats_indexers().depth_m->push( depth );
    258                 }
    259                 deleteRef( tables );
    260         }
    261 
    262         Indexer& Indexer::operator= ( const Indexer &that ) {
    263                 deleteRef( tables );
    264 
    265                 tables = newRef( that.tables );
    266                 scope = that.scope;
    267                 doDebug = that.doDebug;
    268 
    269                 return *this;
    270         }
    271 
    272         Indexer& Indexer::operator= ( Indexer &&that ) {
    273                 deleteRef( tables );
    274 
    275                 tables = that.tables;
    276                 scope = that.scope;
    277                 doDebug = that.doDebug;
    278 
    279                 that.tables = 0;
    280 
    281                 return *this;
     81                stats().size->push( idTable ? idTable->size() : 0 );
     82        }
     83
     84        void Indexer::lazyInitScope() {
     85                if ( repScope < scope ) {
     86                        ++*stats().lazy_scopes;
     87                        // create rollback
     88                        prevScope = std::make_shared<Indexer>( *this );
     89                        // update repScope
     90                        repScope = scope;
     91                }
     92        }
     93
     94        void Indexer::enterScope() {
     95                ++scope;
     96
     97                ++*stats().new_scopes;
     98                stats().avg_scope_depth->push( scope );
     99                stats().max_scope_depth->push( scope );
     100        }
     101
     102        void Indexer::leaveScope() {
     103                if ( repScope == scope ) {
     104                        Ptr prev = prevScope;           // make sure prevScope stays live
     105                        *this = std::move(*prevScope);  // replace with previous scope
     106                }
     107
     108                --scope;
    282109        }
    283110
    284111        void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const {
    285                 std::unordered_set< std::string > foundMangleNames;
    286 
    287                 Indexer::Impl *searchTables = tables;
    288                 while ( searchTables ) {
    289 
    290                         (*stats_idtable().find)++;
    291                         stats_idtable().key->push( id.size() );
    292                         stats_idtable().size->push( searchTables->idTable.size() );
    293                         IdTable::const_iterator decls = searchTables->idTable.find( id );
    294                         if ( decls != searchTables->idTable.end() ) {
    295                                 const MangleTable &mangleTable = decls->second;
    296                                 for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    297                                         // mark the mangled name as found, skipping this insertion if a declaration for that name has already been found
    298                                         if ( foundMangleNames.insert( decl->first ).second == false ) continue;
    299 
    300                                         out.push_back( decl->second );
    301                                 }
    302                         }
    303 
    304                         // get declarations from base indexers
    305                         searchTables = searchTables->base.tables;
    306                 }
    307 
    308                 // some special functions, e.g. constructors and destructors
    309                 // remove autogenerated functions when they are defined so that
    310                 // they can never be matched
    311                 removeSpecialOverrides( id, out );
     112                ++*stats().lookup_calls;
     113                if ( ! idTable ) return;
     114
     115                ++*stats().map_lookups;
     116                auto decls = idTable->find( id );
     117                if ( decls == idTable->end() ) return;
     118
     119                for ( auto decl : *(decls->second) ) {
     120                        out.push_back( decl.second );
     121                }
    312122        }
    313123
    314124        NamedTypeDecl *Indexer::lookupType( const std::string &id ) const {
    315                 if ( ! tables ) return 0;
    316 
    317                 TypeTable::const_iterator ret = tables->typeTable.find( id );
    318                 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupType( id );
     125                ++*stats().lookup_calls;
     126                if ( ! typeTable ) return nullptr;
     127                ++*stats().map_lookups;
     128                auto it = typeTable->find( id );
     129                return it == typeTable->end() ? nullptr : it->second.decl;
    319130        }
    320131
    321132        StructDecl *Indexer::lookupStruct( const std::string &id ) const {
    322                 if ( ! tables ) return 0;
    323 
    324                 StructTable::const_iterator ret = tables->structTable.find( id );
    325                 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStruct( id );
     133                ++*stats().lookup_calls;
     134                if ( ! structTable ) return nullptr;
     135                ++*stats().map_lookups;
     136                auto it = structTable->find( id );
     137                return it == structTable->end() ? nullptr : it->second.decl;
     138        }
     139
     140        EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
     141                ++*stats().lookup_calls;
     142                if ( ! enumTable ) return nullptr;
     143                ++*stats().map_lookups;
     144                auto it = enumTable->find( id );
     145                return it == enumTable->end() ? nullptr : it->second.decl;
     146        }
     147
     148        UnionDecl *Indexer::lookupUnion( const std::string &id ) const {
     149                ++*stats().lookup_calls;
     150                if ( ! unionTable ) return nullptr;
     151                ++*stats().map_lookups;
     152                auto it = unionTable->find( id );
     153                return it == unionTable->end() ? nullptr : it->second.decl;
     154        }
     155
     156        TraitDecl *Indexer::lookupTrait( const std::string &id ) const {
     157                ++*stats().lookup_calls;
     158                if ( ! traitTable ) return nullptr;
     159                ++*stats().map_lookups;
     160                auto it = traitTable->find( id );
     161                return it == traitTable->end() ? nullptr : it->second.decl;
     162        }
     163
     164        const Indexer* Indexer::atScope( unsigned long target ) const {
     165                // by lazy construction, final indexer in list has repScope 0, cannot be > target
     166                // otherwise, will find first scope representing the target
     167                const Indexer* indexer = this;
     168                while ( indexer->repScope > target ) {
     169                        indexer = indexer->prevScope.get();
     170                }
     171                return indexer;
    326172        }
    327173
    328174        NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
    329                 return lookupTypeAtScope( id, 0 );
     175                return atScope( 0 )->lookupType( id );
    330176        }
    331177
    332178        StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
    333                 return lookupStructAtScope( id, 0 );
     179                return atScope( 0 )->lookupStruct( id );
    334180        }
    335181
    336182        UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
    337                 return lookupUnionAtScope( id, 0 );
     183                return atScope( 0 )->lookupUnion( id );
    338184        }
    339185
    340186        EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
    341                 return lookupEnumAtScope( id, 0 );
    342         }
    343 
    344         EnumDecl *Indexer::lookupEnum( const std::string &id ) const {
    345                 if ( ! tables ) return 0;
    346 
    347                 EnumTable::const_iterator ret = tables->enumTable.find( id );
    348                 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnum( id );
    349         }
    350 
    351         UnionDecl *Indexer::lookupUnion( const std::string &id ) const {
    352                 if ( ! tables ) return 0;
    353 
    354                 UnionTable::const_iterator ret = tables->unionTable.find( id );
    355                 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnion( id );
    356         }
    357 
    358         TraitDecl *Indexer::lookupTrait( const std::string &id ) const {
    359                 if ( ! tables ) return 0;
    360 
    361                 TraitTable::const_iterator ret = tables->traitTable.find( id );
    362                 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTrait( id );
    363         }
    364 
    365         const Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    366                 if ( ! tables ) return nullptr;
    367                 if ( tables->scope < scope ) return nullptr;
    368 
    369                 (*stats_idtable().find)++;
    370                 stats_idtable().key->push( id.size() );
    371                 stats_idtable().size->push( tables->idTable.size() );
    372                 IdTable::const_iterator decls = tables->idTable.find( id );
    373                 if ( decls != tables->idTable.end() ) {
    374                         const MangleTable &mangleTable = decls->second;
    375                         MangleTable::const_iterator decl = mangleTable.find( mangleName );
    376                         if ( decl != mangleTable.end() ) return &decl->second;
    377                 }
    378 
    379                 return tables->base.lookupIdAtScope( id, mangleName, scope );
    380         }
    381 
    382         Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) {
    383                 return const_cast<IdData *>(const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope ));
    384         }
    385 
    386         bool Indexer::hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    387                 if ( ! tables ) return false;
    388                 if ( tables->scope < scope ) return false;
    389 
    390                 (*stats_idtable().find)++;
    391                 stats_idtable().key->push( id.size() );
    392                 stats_idtable().size->push( tables->idTable.size() );
    393                 IdTable::const_iterator decls = tables->idTable.find( id );
    394                 if ( decls != tables->idTable.end() ) {
    395                         const MangleTable &mangleTable = decls->second;
    396                         for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    397                                 // check for C decls with the same name, skipping those with a compatible type (by mangleName)
    398                                 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first != mangleName ) return true;
    399                         }
    400                 }
    401 
    402                 return tables->base.hasIncompatibleCDecl( id, mangleName, scope );
    403         }
    404 
    405         bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const {
    406                 if ( ! tables ) return false;
    407                 if ( tables->scope < scope ) return false;
    408 
    409                 (*stats_idtable().find)++;
    410                 stats_idtable().key->push( id.size() );
    411                 stats_idtable().size->push( tables->idTable.size() );
    412                 IdTable::const_iterator decls = tables->idTable.find( id );
    413                 if ( decls != tables->idTable.end() ) {
    414                         const MangleTable &mangleTable = decls->second;
    415                         for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) {
    416                                 // check for C decls with the same name, skipping
    417                                 // those with an incompatible type (by mangleName)
    418                                 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first == mangleName ) return true;
    419                         }
    420                 }
    421 
    422                 return tables->base.hasCompatibleCDecl( id, mangleName, scope );
    423         }
    424 
    425         NamedTypeDecl *Indexer::lookupTypeAtScope( const std::string &id, unsigned long scope ) const {
    426                 if ( ! tables ) return 0;
    427                 if ( tables->scope < scope ) return 0;
    428                 if ( tables->scope > scope ) return tables->base.lookupTypeAtScope( id, scope );
    429 
    430                 TypeTable::const_iterator ret = tables->typeTable.find( id );
    431                 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupTypeAtScope( id, scope );
    432         }
    433 
    434         StructDecl *Indexer::lookupStructAtScope( const std::string &id, unsigned long scope ) const {
    435                 if ( ! tables ) return 0;
    436                 if ( tables->scope < scope ) return 0;
    437                 if ( tables->scope > scope ) return tables->base.lookupStructAtScope( id, scope );
    438 
    439                 StructTable::const_iterator ret = tables->structTable.find( id );
    440                 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStructAtScope( id, scope );
    441         }
    442 
    443         EnumDecl *Indexer::lookupEnumAtScope( const std::string &id, unsigned long scope ) const {
    444                 if ( ! tables ) return 0;
    445                 if ( tables->scope < scope ) return 0;
    446                 if ( tables->scope > scope ) return tables->base.lookupEnumAtScope( id, scope );
    447 
    448                 EnumTable::const_iterator ret = tables->enumTable.find( id );
    449                 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnumAtScope( id, scope );
    450         }
    451 
    452         UnionDecl *Indexer::lookupUnionAtScope( const std::string &id, unsigned long scope ) const {
    453                 if ( ! tables ) return 0;
    454                 if ( tables->scope < scope ) return 0;
    455                 if ( tables->scope > scope ) return tables->base.lookupUnionAtScope( id, scope );
    456 
    457                 UnionTable::const_iterator ret = tables->unionTable.find( id );
    458                 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnionAtScope( id, scope );
    459         }
    460 
    461         TraitDecl *Indexer::lookupTraitAtScope( const std::string &id, unsigned long scope ) const {
    462                 if ( ! tables ) return 0;
    463                 if ( tables->scope < scope ) return 0;
    464                 if ( tables->scope > scope ) return tables->base.lookupTraitAtScope( id, scope );
    465 
    466                 TraitTable::const_iterator ret = tables->traitTable.find( id );
    467                 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTraitAtScope( id, scope );
     187                return atScope( 0 )->lookupEnum( id );
    468188        }
    469189
     
    487207        }
    488208
    489         bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) {
    490                 // if we're giving the same name mangling to things of different types then there is something wrong
     209       
     210        bool Indexer::addedIdConflicts(
     211                        const Indexer::IdData & existing, DeclarationWithType *added,
     212                        Indexer::OnConflict handleConflicts, BaseSyntaxNode * deleteStmt ) {
     213                // if we're giving the same name mangling to things of different types then there is
     214                // something wrong
    491215                assert( (isObject( added ) && isObject( existing.id ) )
    492216                        || ( isFunction( added ) && isFunction( existing.id ) ) );
    493217
    494                 if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) {
     218                if ( LinkageSpec::isOverridable( existing.id->linkage ) ) {
    495219                        // new definition shadows the autogenerated one, even at the same scope
    496220                        return false;
    497                 } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) {
     221                } else if ( LinkageSpec::isMangled( added->linkage )
     222                                || ResolvExpr::typesCompatible(
     223                                        added->get_type(), existing.id->get_type(), Indexer() ) ) {
    498224
    499225                        // it is a conflict if one declaration is deleted and the other is not
    500226                        if ( deleteStmt && ! existing.deleteStmt ) {
    501                                 return handleConflicts( existing, "deletion of defined identifier " );
     227                                if ( handleConflicts.mode == OnConflict::Error ) {
     228                                        SemanticError( added, "deletion of defined identifier " );
     229                                }
     230                                return true;
    502231                        } else if ( ! deleteStmt && existing.deleteStmt ) {
    503                                 return handleConflicts( existing, "definition of deleted identifier " );
     232                                if ( handleConflicts.mode == OnConflict::Error ) {
     233                                        SemanticError( added, "definition of deleted identifier " );
     234                                }
     235                                return true;
    504236                        }
    505237
    506238                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
    507                                 if ( isFunction( added ) ) {
    508                                         return handleConflicts( existing, "duplicate function definition for " );
     239                                if ( handleConflicts.mode == OnConflict::Error ) {
     240                                        SemanticError( added,
     241                                                isFunction( added ) ?
     242                                                        "duplicate function definition for " :
     243                                                        "duplicate object definition for " );
     244                                }
     245                                return true;
     246                        } // if
     247                } else {
     248                        if ( handleConflicts.mode == OnConflict::Error ) {
     249                                SemanticError( added, "duplicate definition for " );
     250                        }
     251                        return true;
     252                } // if
     253
     254                return true;
     255        }
     256
     257        bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const {
     258                if ( ! idTable ) return false;
     259
     260                ++*stats().map_lookups;
     261                auto decls = idTable->find( id );
     262                if ( decls == idTable->end() ) return false;
     263
     264                for ( auto decl : *(decls->second) ) {
     265                        // skip other scopes (hidden by this decl)
     266                        if ( decl.second.scope != scope ) continue;
     267                        // check for C decl with compatible type (by mangleName)
     268                        if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first == mangleName ) {
     269                                return true;
     270                        }
     271                }
     272               
     273                return false;
     274        }
     275
     276        bool Indexer::hasIncompatibleCDecl(
     277                        const std::string &id, const std::string &mangleName ) const {
     278                if ( ! idTable ) return false;
     279
     280                ++*stats().map_lookups;
     281                auto decls = idTable->find( id );
     282                if ( decls == idTable->end() ) return false;
     283
     284                for ( auto decl : *(decls->second) ) {
     285                        // skip other scopes (hidden by this decl)
     286                        if ( decl.second.scope != scope ) continue;
     287                        // check for C decl with incompatible type (by manglename)
     288                        if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first != mangleName ) {
     289                                return true;
     290                        }
     291                }
     292
     293                return false;
     294        }
     295
     296        /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function
     297        std::string getOtypeKey( FunctionDecl* function ) {
     298                auto& params = function->type->parameters;
     299                assert( ! params.empty() );
     300                // use base type of pointer, so that qualifiers on the pointer type aren't considered.
     301                Type* base = InitTweak::getPointerBase( params.front()->get_type() );
     302                assert( base );
     303                return Mangler::mangle( base );
     304        }
     305
     306        /// gets the declaration for the function acting on a type specified by otype key,
     307        /// nullptr if none such
     308        FunctionDecl * getFunctionForOtype( DeclarationWithType * decl, const std::string& otypeKey ) {
     309                FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl );
     310                if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr;
     311                return func;
     312        }
     313
     314        bool Indexer::removeSpecialOverrides(
     315                        Indexer::IdData& data, Indexer::MangleTable::Ptr& mangleTable ) {
     316                // if a type contains user defined ctor/dtor/assign, then special rules trigger, which
     317                // determinethe set of ctor/dtor/assign that can be used  by the requester. In particular,
     318                // if the user defines a default ctor, then the generated default ctor is unavailable,
     319                // likewise for copy ctor and dtor. If the user defines any ctor/dtor, then no generated
     320                // field ctors are available. If the user defines any ctor then the generated default ctor
     321                // is unavailable (intrinsic default ctor must be overridden exactly). If the user defines
     322                // anything that looks like a copy constructor, then the generated copy constructor is
     323                // unavailable, and likewise for the assignment operator.
     324
     325                // only relevant on function declarations
     326                FunctionDecl * function = dynamic_cast< FunctionDecl * >( data.id );
     327                if ( ! function ) return true;
     328                // only need to perform this check for constructors, destructors, and assignment functions
     329                if ( ! CodeGen::isCtorDtorAssign( data.id->name ) ) return true;
     330
     331                // set up information for this type
     332                bool dataIsUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage );
     333                bool dataIsCopyFunc = InitTweak::isCopyFunction( function, function->name );
     334                std::string dataOtypeKey = getOtypeKey( function );
     335
     336                if ( dataIsUserDefinedFunc && dataIsCopyFunc ) {
     337                        // this is a user-defined copy function
     338                        // if this is the first such, delete/remove non-user-defined overloads as needed
     339                        std::vector< std::string > removed;
     340                        std::vector< MangleTable::value_type > deleted;
     341                        bool alreadyUserDefinedFunc = false;
     342                       
     343                        for ( const auto& entry : *mangleTable ) {
     344                                // skip decls that aren't functions or are for the wrong type
     345                                FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
     346                                if ( ! decl ) continue;
     347
     348                                bool isCopyFunc = InitTweak::isCopyFunction( decl, decl->name );
     349                                if ( ! LinkageSpec::isOverridable( decl->linkage ) ) {
     350                                        // matching user-defined function
     351                                        if ( isCopyFunc ) {
     352                                                // mutation already performed, return early
     353                                                return true;
     354                                        } else {
     355                                                // note that non-copy deletions already performed
     356                                                alreadyUserDefinedFunc = true;
     357                                        }
    509358                                } else {
    510                                         return handleConflicts( existing, "duplicate object definition for " );
    511                                 } // if
    512                         } // if
    513                 } else {
    514                         return handleConflicts( existing, "duplicate definition for " );
    515                 } // if
    516 
     359                                        // non-user-defined function; mark for deletion/removal as appropriate
     360                                        if ( isCopyFunc ) {
     361                                                removed.push_back( entry.first );
     362                                        } else if ( ! alreadyUserDefinedFunc ) {
     363                                                deleted.push_back( entry );
     364                                        }
     365                                }
     366                        }
     367
     368                        // perform removals from mangle table, and deletions if necessary
     369                        for ( const auto& key : removed ) {
     370                                ++*stats().map_mutations;
     371                                mangleTable = mangleTable->erase( key );
     372                        }
     373                        if ( ! alreadyUserDefinedFunc ) for ( const auto& entry : deleted ) {
     374                                ++*stats().map_mutations;
     375                                mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
     376                        }
     377                } else if ( dataIsUserDefinedFunc ) {
     378                        // this is a user-defined non-copy function
     379                        // if this is the first user-defined function, delete non-user-defined overloads
     380                        std::vector< MangleTable::value_type > deleted;
     381                       
     382                        for ( const auto& entry : *mangleTable ) {
     383                                // skip decls that aren't functions or are for the wrong type
     384                                FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
     385                                if ( ! decl ) continue;
     386
     387                                // exit early if already a matching user-defined function;
     388                                // earlier function will have mutated table
     389                                if ( ! LinkageSpec::isOverridable( decl->linkage ) ) return true;
     390
     391                                // skip mutating intrinsic functions
     392                                if ( decl->linkage == LinkageSpec::Intrinsic ) continue;
     393
     394                                // user-defined non-copy functions do not override copy functions
     395                                if ( InitTweak::isCopyFunction( decl, decl->name ) ) continue;
     396
     397                                // this function to be deleted after mangleTable iteration is complete
     398                                deleted.push_back( entry );
     399                        }
     400
     401                        // mark deletions to update mangle table
     402                        // this needs to be a separate loop because of iterator invalidation
     403                        for ( const auto& entry : deleted ) {
     404                                ++*stats().map_mutations;
     405                                mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } );
     406                        }
     407                } else if ( function->linkage != LinkageSpec::Intrinsic ) {
     408                        // this is an overridable generated function
     409                        // if there already exists a matching user-defined function, delete this appropriately
     410                        for ( const auto& entry : *mangleTable ) {
     411                                // skip decls that aren't functions or are for the wrong type
     412                                FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey );
     413                                if ( ! decl ) continue;
     414
     415                                // skip non-user-defined functions
     416                                if ( LinkageSpec::isOverridable( decl->linkage ) ) continue;
     417
     418                                if ( dataIsCopyFunc ) {
     419                                        // remove current function if exists a user-defined copy function
     420                                        // since the signatures for copy functions don't need to match exactly, using
     421                                        // a delete statement is the wrong approach
     422                                        if ( InitTweak::isCopyFunction( decl, decl->name ) ) return false;
     423                                } else {
     424                                        // mark current function deleted by first user-defined function found
     425                                        data.deleteStmt = decl;
     426                                        return true;
     427                                }
     428                        }
     429                }
     430               
     431                // nothing (more) to fix, return true
    517432                return true;
    518433        }
    519434
    520         void Indexer::addId( DeclarationWithType *decl, ConflictFunction handleConflicts, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) {
    521                 if ( decl->name == "" ) return;
    522                 debugPrint( "Adding Id " << decl->name << std::endl );
    523                 makeWritable();
    524 
     435        void Indexer::addId(
     436                        DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr,
     437                        BaseSyntaxNode * deleteStmt ) {
     438                ++*stats().add_calls;
    525439                const std::string &name = decl->name;
     440                if ( name == "" ) return;
     441               
    526442                std::string mangleName;
    527443                if ( LinkageSpec::isOverridable( decl->linkage ) ) {
    528                         // mangle the name without including the appropriate suffix, so overridable routines are placed into the
    529                         // same "bucket" as their user defined versions.
     444                        // mangle the name without including the appropriate suffix, so overridable routines
     445                        // are placed into the same "bucket" as their user defined versions.
    530446                        mangleName = Mangler::mangle( decl, false );
    531447                } else {
     
    533449                } // if
    534450
    535                 // this ensures that no two declarations with the same unmangled name at the same scope both have C linkage
    536                 if ( ! LinkageSpec::isMangled( decl->linkage ) ) {
    537                         // NOTE this is broken in Richard's original code in such a way that it never triggers (it
    538                         // doesn't check decls that have the same manglename, and all C-linkage decls are defined to
    539                         // have their name as their manglename, hence the error can never trigger).
    540                         // The code here is closer to correct, but name mangling would have to be completely
    541                         // isomorphic to C type-compatibility, which it may not be.
    542                         if ( hasIncompatibleCDecl( name, mangleName, scope ) ) {
     451                // this ensures that no two declarations with the same unmangled name at the same scope
     452                // both have C linkage
     453                if ( LinkageSpec::isMangled( decl->linkage ) ) {
     454                        // Check that a Cforall declaration doesn't override any C declaration
     455                        if ( hasCompatibleCDecl( name, mangleName ) ) {
     456                                SemanticError( decl, "Cforall declaration hides C function " );
     457                        }
     458                } else {
     459                        // NOTE: only correct if name mangling is completely isomorphic to C
     460                        // type-compatibility, which it may not be.
     461                        if ( hasIncompatibleCDecl( name, mangleName ) ) {
    543462                                SemanticError( decl, "conflicting overload of C function " );
    544463                        }
    545                 } else {
    546                         // Check that a Cforall declaration doesn't override any C declaration
    547                         if ( hasCompatibleCDecl( name, mangleName, scope ) ) {
    548                                 SemanticError( decl, "Cforall declaration hides C function " );
    549                         }
    550                 }
    551 
    552                 // Skip repeat declarations of the same identifier
    553                 IdData * existing = lookupIdAtScope( name, mangleName, scope );
    554                 if ( existing && existing->id && addedIdConflicts( *existing, decl, deleteStmt, handleConflicts ) ) return;
    555 
    556                 // add to indexer
    557                 tables->idTable[ name ][ mangleName ] = IdData{ decl, baseExpr, deleteStmt };
    558                 ++tables->size;
     464                }
     465
     466                // ensure tables exist and add identifier
     467                MangleTable::Ptr mangleTable;
     468                if ( ! idTable ) {
     469                        idTable = IdTable::new_ptr();
     470                        mangleTable = MangleTable::new_ptr();
     471                } else {
     472                        ++*stats().map_lookups;
     473                        auto decls = idTable->find( name );
     474                        if ( decls == idTable->end() ) {
     475                                mangleTable = MangleTable::new_ptr();
     476                        } else {
     477                                mangleTable = decls->second;
     478                                // skip in-scope repeat declarations of same identifier
     479                                ++*stats().map_lookups;
     480                                auto existing = mangleTable->find( mangleName );
     481                                if ( existing != mangleTable->end()
     482                                                && existing->second.scope == scope
     483                                                && existing->second.id ) {
     484                                        if ( addedIdConflicts( existing->second, decl, handleConflicts, deleteStmt ) ) {
     485                                                if ( handleConflicts.mode == OnConflict::Delete ) {
     486                                                        // set delete expression for conflicting identifier
     487                                                        lazyInitScope();
     488                                                        *stats().map_mutations += 2;
     489                                                        idTable = idTable->set(
     490                                                                name,
     491                                                                mangleTable->set(
     492                                                                        mangleName,
     493                                                                        IdData{ existing->second, handleConflicts.deleteStmt } ) );
     494                                                }
     495                                                return;
     496                                        }
     497                                }
     498                        }
     499                }
     500
     501                // add/overwrite with new identifier
     502                lazyInitScope();
     503                IdData data{ decl, baseExpr, deleteStmt, scope };
     504                // Ensure that auto-generated ctor/dtor/assignment are deleted if necessary
     505                if ( ! removeSpecialOverrides( data, mangleTable ) ) return;
     506                *stats().map_mutations += 2;
     507                idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) );
    559508        }
    560509
    561510        void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
    562511                // default handling of conflicts is to raise an error
    563                 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr );
     512                addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
    564513        }
    565514
    566515        void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
    567516                // default handling of conflicts is to raise an error
    568                 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );
     517                addId( decl, OnConflict::error(), nullptr, deleteStmt );
    569518        }
    570519
     
    581530                        }
    582531                }
    583                 // does not need to be added to the table if both existing and added have a base that are the same
     532                // does not need to be added to the table if both existing and added have a base that are
     533                // the same
    584534                return true;
    585535        }
    586536
    587537        void Indexer::addType( NamedTypeDecl *decl ) {
    588                 debugPrint( "Adding type " << decl->name << std::endl );
    589                 makeWritable();
    590 
     538                ++*stats().add_calls;
    591539                const std::string &id = decl->name;
    592                 TypeTable::iterator existing = tables->typeTable.find( id );
    593                 if ( existing == tables->typeTable.end() ) {
    594                         NamedTypeDecl *parent = tables->base.lookupTypeAtScope( id, scope );
    595                         if ( ! parent || ! addedTypeConflicts( parent, decl ) ) {
    596                                 tables->typeTable.insert( existing, std::make_pair( id, decl ) );
    597                                 ++tables->size;
    598                         }
    599                 } else {
    600                         if ( ! addedTypeConflicts( existing->second, decl ) ) {
    601                                 existing->second = decl;
    602                         }
    603                 }
     540
     541                if ( ! typeTable ) {
     542                        typeTable = TypeTable::new_ptr();
     543                } else {
     544                        ++*stats().map_lookups;
     545                        auto existing = typeTable->find( id );
     546                        if ( existing != typeTable->end()
     547                                && existing->second.scope == scope
     548                                && addedTypeConflicts( existing->second.decl, decl ) ) return;
     549                }
     550               
     551                lazyInitScope();
     552                ++*stats().map_mutations;
     553                typeTable = typeTable->set( id, Scoped<NamedTypeDecl>{ decl, scope } );
    604554        }
    605555
     
    614564
    615565        void Indexer::addStruct( const std::string &id ) {
    616                 debugPrint( "Adding fwd decl for struct " << id << std::endl );
    617566                addStruct( new StructDecl( id ) );
    618567        }
    619568
    620569        void Indexer::addStruct( StructDecl *decl ) {
    621                 debugPrint( "Adding struct " << decl->name << std::endl );
    622                 makeWritable();
    623 
     570                ++*stats().add_calls;
    624571                const std::string &id = decl->name;
    625                 StructTable::iterator existing = tables->structTable.find( id );
    626                 if ( existing == tables->structTable.end() ) {
    627                         StructDecl *parent = tables->base.lookupStructAtScope( id, scope );
    628                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    629                                 tables->structTable.insert( existing, std::make_pair( id, decl ) );
    630                                 ++tables->size;
    631                         }
    632                 } else {
    633                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    634                                 existing->second = decl;
    635                         }
    636                 }
     572
     573                if ( ! structTable ) {
     574                        structTable = StructTable::new_ptr();
     575                } else {
     576                        ++*stats().map_lookups;
     577                        auto existing = structTable->find( id );
     578                        if ( existing != structTable->end() 
     579                                && existing->second.scope == scope
     580                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     581                }
     582
     583                lazyInitScope();
     584                ++*stats().map_mutations;
     585                structTable = structTable->set( id, Scoped<StructDecl>{ decl, scope } );
    637586        }
    638587
    639588        void Indexer::addEnum( EnumDecl *decl ) {
    640                 debugPrint( "Adding enum " << decl->name << std::endl );
    641                 makeWritable();
    642 
     589                ++*stats().add_calls;
    643590                const std::string &id = decl->name;
    644                 EnumTable::iterator existing = tables->enumTable.find( id );
    645                 if ( existing == tables->enumTable.end() ) {
    646                         EnumDecl *parent = tables->base.lookupEnumAtScope( id, scope );
    647                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    648                                 tables->enumTable.insert( existing, std::make_pair( id, decl ) );
    649                                 ++tables->size;
    650                         }
    651                 } else {
    652                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    653                                 existing->second = decl;
    654                         }
    655                 }
     591
     592                if ( ! enumTable ) {
     593                        enumTable = EnumTable::new_ptr();
     594                } else {
     595                        ++*stats().map_lookups;
     596                        auto existing = enumTable->find( id );
     597                        if ( existing != enumTable->end() 
     598                                && existing->second.scope == scope
     599                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     600                }
     601               
     602                lazyInitScope();
     603                ++*stats().map_mutations;
     604                enumTable = enumTable->set( id, Scoped<EnumDecl>{ decl, scope } );
    656605        }
    657606
    658607        void Indexer::addUnion( const std::string &id ) {
    659                 debugPrint( "Adding fwd decl for union " << id << std::endl );
    660608                addUnion( new UnionDecl( id ) );
    661609        }
    662610
    663611        void Indexer::addUnion( UnionDecl *decl ) {
    664                 debugPrint( "Adding union " << decl->name << std::endl );
    665                 makeWritable();
    666 
     612                ++*stats().add_calls;
    667613                const std::string &id = decl->name;
    668                 UnionTable::iterator existing = tables->unionTable.find( id );
    669                 if ( existing == tables->unionTable.end() ) {
    670                         UnionDecl *parent = tables->base.lookupUnionAtScope( id, scope );
    671                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    672                                 tables->unionTable.insert( existing, std::make_pair( id, decl ) );
    673                                 ++tables->size;
    674                         }
    675                 } else {
    676                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    677                                 existing->second = decl;
    678                         }
    679                 }
     614
     615                if ( ! unionTable ) {
     616                        unionTable = UnionTable::new_ptr();
     617                } else {
     618                        ++*stats().map_lookups;
     619                        auto existing = unionTable->find( id );
     620                        if ( existing != unionTable->end()
     621                                && existing->second.scope == scope
     622                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     623                }
     624
     625                lazyInitScope();
     626                ++*stats().map_mutations;
     627                unionTable = unionTable->set( id, Scoped<UnionDecl>{ decl, scope } );
    680628        }
    681629
    682630        void Indexer::addTrait( TraitDecl *decl ) {
    683                 debugPrint( "Adding trait " << decl->name << std::endl );
    684                 makeWritable();
    685 
     631                ++*stats().add_calls;
    686632                const std::string &id = decl->name;
    687                 TraitTable::iterator existing = tables->traitTable.find( id );
    688                 if ( existing == tables->traitTable.end() ) {
    689                         TraitDecl *parent = tables->base.lookupTraitAtScope( id, scope );
    690                         if ( ! parent || ! addedDeclConflicts( parent, decl ) ) {
    691                                 tables->traitTable.insert( existing, std::make_pair( id, decl ) );
    692                                 ++tables->size;
    693                         }
    694                 } else {
    695                         if ( ! addedDeclConflicts( existing->second, decl ) ) {
    696                                 existing->second = decl;
    697                         }
    698                 }
    699         }
    700 
    701         void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction handleConflicts ) {
     633
     634                if ( ! traitTable ) {
     635                        traitTable = TraitTable::new_ptr();
     636                } else {
     637                        ++*stats().map_lookups;
     638                        auto existing = traitTable->find( id );
     639                        if ( existing != traitTable->end()
     640                                && existing->second.scope == scope
     641                                && addedDeclConflicts( existing->second.decl, decl ) ) return;
     642                }
     643
     644                lazyInitScope();
     645                ++*stats().map_mutations;
     646                traitTable = traitTable->set( id, Scoped<TraitDecl>{ decl, scope } );
     647        }
     648
     649        void Indexer::addMembers( AggregateDecl * aggr, Expression * expr,
     650                        OnConflict handleConflicts ) {
    702651                for ( Declaration * decl : aggr->members ) {
    703652                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
     
    705654                                if ( dwt->name == "" ) {
    706655                                        Type * t = dwt->get_type()->stripReferences();
    707                                         if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) {
     656                                        if ( dynamic_cast<StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) {
    708657                                                Expression * base = expr->clone();
    709658                                                ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost?
     
    722671                                assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
    723672
    724                                 addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) {
    725                                         // on conflict, delete the identifier
    726                                         existing.deleteStmt = withStmt;
    727                                         return true;
    728                                 });
     673                                addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) );
    729674                        }
    730675                }
     
    748693                addIds( ftype->returnVals );
    749694                addIds( ftype->parameters );
    750         }
    751 
    752         void Indexer::enterScope() {
    753                 ++scope;
    754 
    755                 if ( doDebug ) {
    756                         std::cerr << "--- Entering scope " << scope << std::endl;
    757                 }
    758         }
    759 
    760         void Indexer::leaveScope() {
    761                 using std::cerr;
    762 
    763                 assert( scope > 0 && "cannot leave initial scope" );
    764                 if ( doDebug ) {
    765                         cerr << "--- Leaving scope " << scope << " containing" << std::endl;
    766                 }
    767                 --scope;
    768 
    769                 while ( tables && tables->scope > scope ) {
    770                         if ( doDebug ) {
    771                                 dump( tables->idTable, cerr );
    772                                 dump( tables->typeTable, cerr );
    773                                 dump( tables->structTable, cerr );
    774                                 dump( tables->enumTable, cerr );
    775                                 dump( tables->unionTable, cerr );
    776                                 dump( tables->traitTable, cerr );
    777                         }
    778 
    779                         // swap tables for base table until we find one at an appropriate scope
    780                         Indexer::Impl *base = newRef( tables->base.tables );
    781                         deleteRef( tables );
    782                         tables = base;
    783                 }
    784         }
    785 
    786         void Indexer::print( std::ostream &os, int indent ) const {
    787                 using std::cerr;
    788 
    789                 if ( tables ) {
    790                         os << "--- scope " << tables->scope << " ---" << std::endl;
    791 
    792                         os << "===idTable===" << std::endl;
    793                         dump( tables->idTable, os );
    794                         os << "===typeTable===" << std::endl;
    795                         dump( tables->typeTable, os );
    796                         os << "===structTable===" << std::endl;
    797                         dump( tables->structTable, os );
    798                         os << "===enumTable===" << std::endl;
    799                         dump( tables->enumTable, os );
    800                         os << "===unionTable===" << std::endl;
    801                         dump( tables->unionTable, os );
    802                         os << "===contextTable===" << std::endl;
    803                         dump( tables->traitTable, os );
    804 
    805                         tables->base.print( os, indent );
    806                 } else {
    807                         os << "--- end ---" << std::endl;
    808                 }
    809 
    810695        }
    811696
  • src/SymTab/Indexer.h

    r69c37cc rf343c6b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:38:55 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 17 16:09:12 2017
    13 // Update Count     : 8
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Fri Mar  8 13:55:00 2019
     13// Update Count     : 9
    1414//
    1515
    1616#pragma once
    1717
    18 #include <iosfwd>             // for ostream
    19 #include <list>               // for list
    20 #include <string>             // for string
    21 #include <functional>         // for function
     18#include <functional>              // for function
     19#include <list>                    // for list
     20#include <memory>                  // for shared_ptr, enable_shared_from_this
     21#include <string>                  // for string
    2222
    23 #include "SynTree/Visitor.h"  // for Visitor
    24 #include "SynTree/SynTree.h"  // for AST nodes
     23#include "Common/PersistentMap.h"  // for PersistentMap
     24#include "SynTree/SynTree.h"       // for AST nodes
    2525
    2626namespace ResolvExpr {
    27 class Cost;
     27        class Cost;
    2828}
    2929
    3030namespace SymTab {
    31         class Indexer {
    32           public:
     31        class Indexer : public std::enable_shared_from_this<SymTab::Indexer> {
     32        public:
    3333                explicit Indexer();
     34                virtual ~Indexer();
    3435
    35                 Indexer( const Indexer &that );
    36                 Indexer( Indexer &&that );
    37                 virtual ~Indexer();
    38                 Indexer& operator= ( const Indexer &that );
    39                 Indexer& operator= ( Indexer &&that );
    40 
    41                 // when using an indexer manually (e.g., within a mutator traversal), it is necessary to tell the indexer
    42                 // explicitly when scopes begin and end
     36                // when using an indexer manually (e.g., within a mutator traversal), it is necessary to
     37                // tell the indexer explicitly when scopes begin and end
    4338                void enterScope();
    4439                void leaveScope();
     
    5045                        /// non-null if this declaration is deleted
    5146                        BaseSyntaxNode * deleteStmt = nullptr;
     47                        /// scope of identifier
     48                        unsigned long scope = 0;
    5249
    5350                        // NOTE: shouldn't need either of these constructors, but gcc-4 does not properly support initializer lists with default members.
    5451                        IdData() = default;
    55                         IdData( DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ) {}
     52                        IdData(
     53                                DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt,
     54                                unsigned long scope )
     55                                : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ), scope( scope ) {}
     56                        IdData( const IdData& o, BaseSyntaxNode * deleteStmt )
     57                                : id( o.id ), baseExpr( o.baseExpr ), deleteStmt( deleteStmt ), scope( o.scope ) {}
    5658
    5759                        Expression * combine( ResolvExpr::Cost & cost ) const;
     
    8082                EnumDecl *globalLookupEnum( const std::string &id ) const;
    8183
    82                 void print( std::ostream &os, int indent = 0 ) const;
    83 
    84                 /// looks up a specific mangled ID at the given scope
    85                 IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope );
    86                 const IdData * lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
    87                 /// returns true if there exists a declaration with C linkage and the given name with a different mangled name
    88                 bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
    89                 /// returns true if there exists a declaration with C linkage and the given name with the same mangled name
    90                 bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const;
    91                 // equivalents to lookup functions that only look at tables at scope `scope` (which should be >= tables->scope)
    92                 NamedTypeDecl *lookupTypeAtScope( const std::string &id, unsigned long scope ) const;
    93                 StructDecl *lookupStructAtScope( const std::string &id, unsigned long scope ) const;
    94                 EnumDecl *lookupEnumAtScope( const std::string &id, unsigned long scope ) const;
    95                 UnionDecl *lookupUnionAtScope( const std::string &id, unsigned long scope ) const;
    96                 TraitDecl *lookupTraitAtScope( const std::string &id, unsigned long scope ) const;
    97 
    98                 typedef std::function<bool(IdData &, const std::string &)> ConflictFunction;
    99 
    10084                void addId( DeclarationWithType * decl, Expression * baseExpr = nullptr );
    10185                void addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt );
     
    11296                void addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt );
    11397
    114                 /// adds all of the members of the Aggregate (addWith helper)
    115                 void addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction );
    116 
    11798                /// convenience function for adding a list of Ids to the indexer
    11899                void addIds( const std::list< DeclarationWithType * > & decls );
     
    124105                void addFunctionType( FunctionType * ftype );
    125106
    126                 bool doDebug = false; ///< Display debugging trace?
    127107          private:
    128                 struct Impl;
     108                /// Wraps a Decl* with a scope
     109                template<typename Decl>
     110                struct Scoped {
     111                        Decl* decl;           ///< declaration
     112                        unsigned long scope;  ///< scope of this declaration
    129113
    130                 Impl *tables;         ///< Copy-on-write instance of table data structure
    131                 unsigned long scope;  ///< Scope index of this pointer
     114                        Scoped(Decl* d, unsigned long s) : decl(d), scope(s) {}
     115                };
    132116
    133                 /// Takes a new ref to a table (returns null if null)
    134                 static Impl *newRef( Impl *toClone );
    135                 /// Clears a ref to a table (does nothing if null)
    136                 static void deleteRef( Impl *toFree );
     117                using Ptr = std::shared_ptr<const Indexer>;
    137118
    138                 // Removes matching autogenerated constructors and destructors
    139                 // so that they will not be selected
    140                 // void removeSpecialOverrides( FunctionDecl *decl );
    141                 void removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const;
     119                using MangleTable = PersistentMap< std::string, IdData >;
     120                using IdTable = PersistentMap< std::string, MangleTable::Ptr >;
     121                using TypeTable = PersistentMap< std::string, Scoped<NamedTypeDecl> >;
     122                using StructTable = PersistentMap< std::string, Scoped<StructDecl> >;
     123                using EnumTable = PersistentMap< std::string, Scoped<EnumDecl> >;
     124                using UnionTable = PersistentMap< std::string, Scoped<UnionDecl> >;
     125                using TraitTable = PersistentMap< std::string, Scoped<TraitDecl> >;
    142126
    143                 /// Ensures that tables variable is writable (i.e. allocated, uniquely owned by this Indexer, and at the current scope)
    144                 void makeWritable();
     127                IdTable::Ptr idTable;          ///< identifier namespace
     128                TypeTable::Ptr typeTable;      ///< type namespace
     129                StructTable::Ptr structTable;  ///< struct namespace
     130                EnumTable::Ptr enumTable;      ///< enum namespace
     131                UnionTable::Ptr unionTable;    ///< union namespace
     132                TraitTable::Ptr traitTable;    ///< trait namespace
     133
     134                Ptr prevScope;                 ///< reference to indexer for parent scope
     135                unsigned long scope;           ///< Scope index of this indexer
     136                unsigned long repScope;        ///< Scope index of currently represented scope
     137
     138                /// Ensures that a proper backtracking scope exists before a mutation
     139                void lazyInitScope();
     140
     141                /// Gets the indexer at the given scope
     142                const Indexer* atScope( unsigned long scope ) const;
     143
     144                /// Removes matching autogenerated constructors and destructors so that they will not be
     145                /// selected. If returns false, passed decl should not be added.
     146                bool removeSpecialOverrides( IdData& decl, MangleTable::Ptr& mangleTable );
     147
     148                /// Options for handling identifier conflicts
     149                struct OnConflict {
     150                        enum {
     151                                Error,  ///< Throw a semantic error
     152                                Delete  ///< Delete the earlier version with the delete statement
     153                        } mode;
     154                        BaseSyntaxNode * deleteStmt;  ///< Statement that deletes this expression
     155
     156                private:
     157                        OnConflict() : mode(Error), deleteStmt(nullptr) {}
     158                        OnConflict( BaseSyntaxNode * d ) : mode(Delete), deleteStmt(d) {}
     159                public:
     160                        OnConflict( const OnConflict& ) = default;
     161
     162                        static OnConflict error() { return {}; }
     163                        static OnConflict deleteWith( BaseSyntaxNode * d ) { return { d }; }
     164                };
     165
     166                /// true if the existing identifier conflicts with the added identifier
     167                bool addedIdConflicts(
     168                        const IdData& existing, DeclarationWithType * added, OnConflict handleConflicts,
     169                        BaseSyntaxNode * deleteStmt );
    145170
    146171                /// common code for addId, addDeletedId, etc.
    147                 void addId( DeclarationWithType * decl, ConflictFunction, Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr );
     172                void addId(
     173                        DeclarationWithType * decl, OnConflict handleConflicts,
     174                        Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr );
     175
     176                /// adds all of the members of the Aggregate (addWith helper)
     177                void addMembers( AggregateDecl * aggr, Expression * expr, OnConflict handleConflicts );
     178
     179                /// returns true if there exists a declaration with C linkage and the given name with the same mangled name
     180                bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const;
     181                /// returns true if there exists a declaration with C linkage and the given name with a different mangled name
     182                bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName ) const;
    148183        };
    149184} // namespace SymTab
  • src/SynTree/Attribute.cc

    r69c37cc rf343c6b  
    2121#include "Expression.h"      // for Expression
    2222
    23 Attribute::Attribute( const Attribute &other ) : name( other.name ) {
     23Attribute::Attribute( const Attribute &other ) : BaseSyntaxNode( other ), name( other.name ) {
    2424        cloneAll( other.parameters, parameters );
    2525}
  • src/SynTree/BaseSyntaxNode.h

    r69c37cc rf343c6b  
    1818#include "Common/CodeLocation.h"
    1919#include "Common/Indenter.h"
     20#include "Common/Stats.h"
     21
    2022class Visitor;
    2123class Mutator;
     
    2325class BaseSyntaxNode {
    2426  public:
     27  static Stats::Counters::SimpleCounter* new_nodes;
     28
    2529        CodeLocation location;
     30
     31  BaseSyntaxNode() { ++*new_nodes; }
     32  BaseSyntaxNode( const BaseSyntaxNode& o ) : location(o.location) { ++*new_nodes; }
    2633
    2734        virtual ~BaseSyntaxNode() {}
  • src/SynTree/Constant.cc

    r69c37cc rf343c6b  
    2525Constant::Constant( Type * type, std::string rep, double val ) : type( type ), rep( rep ), val( val ) {}
    2626
    27 Constant::Constant( const Constant &other ) : rep( other.rep ), val( other.val ) {
     27Constant::Constant( const Constant &other ) : BaseSyntaxNode( other ), rep( other.rep ), val( other.val ) {
    2828        type = other.type->clone();
    2929}
  • src/SynTree/Declaration.h

    r69c37cc rf343c6b  
    211211                TypeDecl::Kind kind;
    212212                bool isComplete;
     213               
    213214                Data() : kind( (TypeDecl::Kind)-1 ), isComplete( false ) {}
    214215                Data( TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {}
    215216                Data( Kind kind, bool isComplete ) : kind( kind ), isComplete( isComplete ) {}
     217                Data( const Data& d1, const Data& d2 )
     218                : kind( d1.kind ), isComplete ( d1.isComplete || d2.isComplete ) {}
     219
    216220                bool operator==(const Data & other) const { return kind == other.kind && isComplete == other.isComplete; }
    217221                bool operator!=(const Data & other) const { return !(*this == other);}
  • src/SynTree/Statement.h

    r69c37cc rf343c6b  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar  8 14:53:02 2018
    13 // Update Count     : 78
     12// Last Modified On : Tue Mar 12 09:01:53 2019
     13// Update Count     : 83
    1414//
    1515
     
    1919#include <list>                    // for list
    2020#include <memory>                  // for allocator
    21 #include <vector>                        // for vector
     21#include <vector>                                  // for vector
    2222
    2323#include "BaseSyntaxNode.h"        // for BaseSyntaxNode
     
    4343        const std::list<Label> & get_labels() const { return labels; }
    4444
    45         virtual Statement *clone() const override = 0;
    46         virtual void accept( Visitor &v ) override = 0;
    47         virtual Statement *acceptMutator( Mutator &m ) override = 0;
    48         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     45        virtual Statement * clone() const override = 0;
     46        virtual void accept( Visitor & v ) override = 0;
     47        virtual Statement * acceptMutator( Mutator & m ) override = 0;
     48        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    4949};
    5050
     
    5555        CompoundStmt();
    5656        CompoundStmt( std::list<Statement *> stmts );
    57         CompoundStmt( const CompoundStmt &other );
     57        CompoundStmt( const CompoundStmt & other );
    5858        virtual ~CompoundStmt();
    5959
     
    6262        void push_front( Statement * stmt ) { kids.push_front( stmt ); }
    6363
    64         virtual CompoundStmt *clone() const override { return new CompoundStmt( *this ); }
    65         virtual void accept( Visitor &v ) override { v.visit( this ); }
    66         virtual CompoundStmt *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    67         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     64        virtual CompoundStmt * clone() const override { return new CompoundStmt( *this ); }
     65        virtual void accept( Visitor & v ) override { v.visit( this ); }
     66        virtual CompoundStmt * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     67        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    6868};
    6969
     
    7272        NullStmt( const std::list<Label> & labels = {} );
    7373
    74         virtual NullStmt *clone() const override { return new NullStmt( *this ); }
    75         virtual void accept( Visitor &v ) override { v.visit( this ); }
    76         virtual NullStmt *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    77         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     74        virtual NullStmt * clone() const override { return new NullStmt( *this ); }
     75        virtual void accept( Visitor & v ) override { v.visit( this ); }
     76        virtual NullStmt * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     77        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    7878};
    7979
    8080class ExprStmt : public Statement {
    8181  public:
    82         Expression *expr;
    83 
    84         ExprStmt( Expression *expr );
    85         ExprStmt( const ExprStmt &other );
     82        Expression * expr;
     83
     84        ExprStmt( Expression * expr );
     85        ExprStmt( const ExprStmt & other );
    8686        virtual ~ExprStmt();
    8787
    88         Expression *get_expr() { return expr; }
    89         void set_expr( Expression *newValue ) { expr = newValue; }
    90 
    91         virtual ExprStmt *clone() const override { return new ExprStmt( *this ); }
    92         virtual void accept( Visitor &v ) override { v.visit( this ); }
    93         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    94         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     88        Expression * get_expr() { return expr; }
     89        void set_expr( Expression * newValue ) { expr = newValue; }
     90
     91        virtual ExprStmt * clone() const override { return new ExprStmt( *this ); }
     92        virtual void accept( Visitor & v ) override { v.visit( this ); }
     93        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     94        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    9595};
    9696
     
    9898  public:
    9999        bool voltile;
    100         Expression *instruction;
     100        Expression * instruction;
    101101        std::list<Expression *> output, input;
    102102        std::list<ConstantExpr *> clobber;
    103103        std::list<Label> gotolabels;
    104104
    105         AsmStmt( bool voltile, Expression *instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels );
    106         AsmStmt( const AsmStmt &other );
     105        AsmStmt( bool voltile, Expression * instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels );
     106        AsmStmt( const AsmStmt & other );
    107107        virtual ~AsmStmt();
    108108
     
    114114        void set_output( const std::list<Expression *> & newValue ) { output = newValue; }
    115115        std::list<Expression *> & get_input() { return input; }
    116         void set_input( const std::list<Expression *> &newValue ) { input = newValue; }
     116        void set_input( const std::list<Expression *> & newValue ) { input = newValue; }
    117117        std::list<ConstantExpr *> & get_clobber() { return clobber; }
    118         void set_clobber( const std::list<ConstantExpr *> &newValue ) { clobber = newValue; }
     118        void set_clobber( const std::list<ConstantExpr *> & newValue ) { clobber = newValue; }
    119119        std::list<Label> & get_gotolabels() { return gotolabels; }
    120         void set_gotolabels( const std::list<Label> &newValue ) { gotolabels = newValue; }
     120        void set_gotolabels( const std::list<Label> & newValue ) { gotolabels = newValue; }
    121121
    122122        virtual AsmStmt * clone() const { return new AsmStmt( *this ); }
     
    141141class IfStmt : public Statement {
    142142  public:
    143         Expression *condition;
    144         Statement *thenPart;
    145         Statement *elsePart;
     143        Expression * condition;
     144        Statement * thenPart;
     145        Statement * elsePart;
    146146        std::list<Statement *> initialization;
    147147
    148         IfStmt( Expression *condition, Statement *thenPart, Statement *elsePart,
     148        IfStmt( Expression * condition, Statement * thenPart, Statement * elsePart,
    149149                        std::list<Statement *> initialization = std::list<Statement *>() );
    150         IfStmt( const IfStmt &other );
     150        IfStmt( const IfStmt & other );
    151151        virtual ~IfStmt();
    152152
    153         std::list<Statement *> &get_initialization() { return initialization; }
    154         Expression *get_condition() { return condition; }
    155         void set_condition( Expression *newValue ) { condition = newValue; }
    156         Statement *get_thenPart() { return thenPart; }
    157         void set_thenPart( Statement *newValue ) { thenPart = newValue; }
    158         Statement *get_elsePart() { return elsePart; }
    159         void set_elsePart( Statement *newValue ) { elsePart = newValue; }
    160 
    161         virtual IfStmt *clone() const override { return new IfStmt( *this ); }
    162         virtual void accept( Visitor &v ) override { v.visit( this ); }
    163         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    164         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     153        std::list<Statement *> & get_initialization() { return initialization; }
     154        Expression * get_condition() { return condition; }
     155        void set_condition( Expression * newValue ) { condition = newValue; }
     156        Statement * get_thenPart() { return thenPart; }
     157        void set_thenPart( Statement * newValue ) { thenPart = newValue; }
     158        Statement * get_elsePart() { return elsePart; }
     159        void set_elsePart( Statement * newValue ) { elsePart = newValue; }
     160
     161        virtual IfStmt * clone() const override { return new IfStmt( *this ); }
     162        virtual void accept( Visitor & v ) override { v.visit( this ); }
     163        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     164        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    165165};
    166166
     
    170170        std::list<Statement *> statements;
    171171
    172         SwitchStmt( Expression *condition, const std::list<Statement *> &statements );
    173         SwitchStmt( const SwitchStmt &other );
     172        SwitchStmt( Expression * condition, const std::list<Statement *> & statements );
     173        SwitchStmt( const SwitchStmt & other );
    174174        virtual ~SwitchStmt();
    175175
    176         Expression *get_condition() { return condition; }
    177         void set_condition( Expression *newValue ) { condition = newValue; }
     176        Expression * get_condition() { return condition; }
     177        void set_condition( Expression * newValue ) { condition = newValue; }
    178178
    179179        std::list<Statement *> & get_statements() { return statements; }
    180180
    181         virtual void accept( Visitor &v ) override { v.visit( this ); }
    182         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    183 
    184         virtual SwitchStmt *clone() const override { return new SwitchStmt( *this ); }
    185         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     181        virtual void accept( Visitor & v ) override { v.visit( this ); }
     182        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     183
     184        virtual SwitchStmt * clone() const override { return new SwitchStmt( *this ); }
     185        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    186186
    187187};
     
    192192        std::list<Statement *> stmts;
    193193
    194         CaseStmt( Expression *conditions, const std::list<Statement *> &stmts, bool isdef = false ) throw (SemanticErrorException);
    195         CaseStmt( const CaseStmt &other );
     194        CaseStmt( Expression * conditions, const std::list<Statement *> & stmts, bool isdef = false ) throw (SemanticErrorException);
     195        CaseStmt( const CaseStmt & other );
    196196        virtual ~CaseStmt();
    197197
     
    201201        void set_default(bool b) { _isDefault = b; }
    202202
    203         Expression * &get_condition() { return condition; }
    204         void set_condition( Expression *newValue ) { condition = newValue; }
    205 
    206         std::list<Statement *> &get_statements() { return stmts; }
    207         void set_statements( std::list<Statement *> &newValue ) { stmts = newValue; }
    208 
    209         virtual void accept( Visitor &v ) override { v.visit( this ); }
    210         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    211 
    212         virtual CaseStmt *clone() const override { return new CaseStmt( *this ); }
    213         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     203        Expression * & get_condition() { return condition; }
     204        void set_condition( Expression * newValue ) { condition = newValue; }
     205
     206        std::list<Statement *> & get_statements() { return stmts; }
     207        void set_statements( std::list<Statement *> & newValue ) { stmts = newValue; }
     208
     209        virtual void accept( Visitor & v ) override { v.visit( this ); }
     210        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     211
     212        virtual CaseStmt * clone() const override { return new CaseStmt( *this ); }
     213        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    214214  private:
    215215        bool _isDefault;
     
    218218class WhileStmt : public Statement {
    219219  public:
    220         Expression *condition;
    221         Statement *body;
     220        Expression * condition;
     221        Statement * body;
    222222        std::list<Statement *> initialization;
    223223        bool isDoWhile;
    224224
    225         WhileStmt( Expression *condition,
    226                Statement *body, std::list<Statement *> & initialization, bool isDoWhile = false );
    227         WhileStmt( const WhileStmt &other );
     225        WhileStmt( Expression * condition, Statement * body, std::list<Statement *> & initialization, bool isDoWhile = false );
     226        WhileStmt( const WhileStmt & other );
    228227        virtual ~WhileStmt();
    229228
    230         Expression *get_condition() { return condition; }
    231         void set_condition( Expression *newValue ) { condition = newValue; }
    232         Statement *get_body() { return body; }
    233         void set_body( Statement *newValue ) { body = newValue; }
     229        Expression * get_condition() { return condition; }
     230        void set_condition( Expression * newValue ) { condition = newValue; }
     231        Statement * get_body() { return body; }
     232        void set_body( Statement * newValue ) { body = newValue; }
    234233        bool get_isDoWhile() { return isDoWhile; }
    235234        void set_isDoWhile( bool newValue ) { isDoWhile = newValue; }
    236235
    237         virtual WhileStmt *clone() const override { return new WhileStmt( *this ); }
    238         virtual void accept( Visitor &v ) override { v.visit( this ); }
    239         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    240         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     236        virtual WhileStmt * clone() const override { return new WhileStmt( *this ); }
     237        virtual void accept( Visitor & v ) override { v.visit( this ); }
     238        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     239        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    241240};
    242241
     
    244243  public:
    245244        std::list<Statement *> initialization;
    246         Expression *condition;
    247         Expression *increment;
    248         Statement *body;
    249 
    250         ForStmt( std::list<Statement *> initialization,
    251              Expression *condition = 0, Expression *increment = 0, Statement *body = 0 );
    252         ForStmt( const ForStmt &other );
     245        Expression * condition;
     246        Expression * increment;
     247        Statement * body;
     248
     249        ForStmt( std::list<Statement *> initialization, Expression * condition = 0, Expression * increment = 0, Statement * body = 0 );
     250        ForStmt( const ForStmt & other );
    253251        virtual ~ForStmt();
    254252
    255         std::list<Statement *> &get_initialization() { return initialization; }
    256         Expression *get_condition() { return condition; }
    257         void set_condition( Expression *newValue ) { condition = newValue; }
    258         Expression *get_increment() { return increment; }
    259         void set_increment( Expression *newValue ) { increment = newValue; }
    260         Statement *get_body() { return body; }
    261         void set_body( Statement *newValue ) { body = newValue; }
    262 
    263         virtual ForStmt *clone() const override { return new ForStmt( *this ); }
    264         virtual void accept( Visitor &v ) override { v.visit( this ); }
    265         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    266         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     253        std::list<Statement *> & get_initialization() { return initialization; }
     254        Expression * get_condition() { return condition; }
     255        void set_condition( Expression * newValue ) { condition = newValue; }
     256        Expression * get_increment() { return increment; }
     257        void set_increment( Expression * newValue ) { increment = newValue; }
     258        Statement * get_body() { return body; }
     259        void set_body( Statement * newValue ) { body = newValue; }
     260
     261        virtual ForStmt * clone() const override { return new ForStmt( *this ); }
     262        virtual void accept( Visitor & v ) override { v.visit( this ); }
     263        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     264        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    267265};
    268266
     
    274272        const Label originalTarget;
    275273        Label target;
    276         Expression *computedTarget;
     274        Expression * computedTarget;
    277275        Type type;
    278276
    279277        BranchStmt( Label target, Type ) throw (SemanticErrorException);
    280         BranchStmt( Expression *computedTarget, Type ) throw (SemanticErrorException);
     278        BranchStmt( Expression * computedTarget, Type ) throw (SemanticErrorException);
    281279
    282280        Label get_originalTarget() { return originalTarget; }
     
    284282        void set_target( Label newValue ) { target = newValue; }
    285283
    286         Expression *get_computedTarget() { return computedTarget; }
     284        Expression * get_computedTarget() { return computedTarget; }
    287285        void set_target( Expression * newValue ) { computedTarget = newValue; }
    288286
    289287        Type get_type() { return type; }
    290         const char *get_typename() { return brType[ type ]; }
    291 
    292         virtual BranchStmt *clone() const override { return new BranchStmt( *this ); }
    293         virtual void accept( Visitor &v ) override { v.visit( this ); }
    294         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    295         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     288        const char * get_typename() { return brType[ type ]; }
     289
     290        virtual BranchStmt * clone() const override { return new BranchStmt( *this ); }
     291        virtual void accept( Visitor & v ) override { v.visit( this ); }
     292        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     293        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    296294  private:
    297         static const char *brType[];
     295        static const char * brType[];
    298296};
    299297
    300298class ReturnStmt : public Statement {
    301299  public:
    302         Expression *expr;
    303 
    304         ReturnStmt( Expression *expr );
    305         ReturnStmt( const ReturnStmt &other );
     300        Expression * expr;
     301
     302        ReturnStmt( Expression * expr );
     303        ReturnStmt( const ReturnStmt & other );
    306304        virtual ~ReturnStmt();
    307305
    308         Expression *get_expr() { return expr; }
    309         void set_expr( Expression *newValue ) { expr = newValue; }
    310 
    311         virtual ReturnStmt *clone() const override { return new ReturnStmt( *this ); }
    312         virtual void accept( Visitor &v ) override { v.visit( this ); }
    313         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    314         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     306        Expression * get_expr() { return expr; }
     307        void set_expr( Expression * newValue ) { expr = newValue; }
     308
     309        virtual ReturnStmt * clone() const override { return new ReturnStmt( *this ); }
     310        virtual void accept( Visitor & v ) override { v.visit( this ); }
     311        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     312        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    315313};
    316314
     
    324322
    325323        ThrowStmt( Kind kind, Expression * expr, Expression * target = nullptr );
    326         ThrowStmt( const ThrowStmt &other );
     324        ThrowStmt( const ThrowStmt & other );
    327325        virtual ~ThrowStmt();
    328326
     
    333331        void set_target( Expression * newTarget ) { target = newTarget; }
    334332
    335         virtual ThrowStmt *clone() const override { return new ThrowStmt( *this ); }
    336         virtual void accept( Visitor &v ) override { v.visit( this ); }
    337         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    338         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     333        virtual ThrowStmt * clone() const override { return new ThrowStmt( *this ); }
     334        virtual void accept( Visitor & v ) override { v.visit( this ); }
     335        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     336        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    339337};
    340338
     
    345343        FinallyStmt * finallyBlock;
    346344
    347         TryStmt( CompoundStmt *tryBlock, std::list<CatchStmt *> &handlers, FinallyStmt *finallyBlock = 0 );
    348         TryStmt( const TryStmt &other );
     345        TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock = 0 );
     346        TryStmt( const TryStmt & other );
    349347        virtual ~TryStmt();
    350348
    351         CompoundStmt *get_block() const { return block; }
    352         void set_block( CompoundStmt *newValue ) { block = newValue; }
     349        CompoundStmt * get_block() const { return block; }
     350        void set_block( CompoundStmt * newValue ) { block = newValue; }
    353351        std::list<CatchStmt *>& get_catchers() { return handlers; }
    354352
    355         FinallyStmt *get_finally() const { return finallyBlock; }
    356         void set_finally( FinallyStmt *newValue ) { finallyBlock = newValue; }
    357 
    358         virtual TryStmt *clone() const override { return new TryStmt( *this ); }
    359         virtual void accept( Visitor &v ) override { v.visit( this ); }
    360         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    361         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     353        FinallyStmt * get_finally() const { return finallyBlock; }
     354        void set_finally( FinallyStmt * newValue ) { finallyBlock = newValue; }
     355
     356        virtual TryStmt * clone() const override { return new TryStmt( *this ); }
     357        virtual void accept( Visitor & v ) override { v.visit( this ); }
     358        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     359        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    362360};
    363361
     
    367365
    368366        const Kind kind;
    369         Declaration *decl;
    370         Expression *cond;
    371         Statement *body;
    372 
    373         CatchStmt( Kind kind, Declaration *decl,
    374                    Expression *cond, Statement *body );
    375         CatchStmt( const CatchStmt &other );
     367        Declaration * decl;
     368        Expression * cond;
     369        Statement * body;
     370
     371        CatchStmt( Kind kind, Declaration * decl,
     372                   Expression * cond, Statement * body );
     373        CatchStmt( const CatchStmt & other );
    376374        virtual ~CatchStmt();
    377375
    378376        Kind get_kind() { return kind; }
    379         Declaration *get_decl() { return decl; }
    380         void set_decl( Declaration *newValue ) { decl = newValue; }
    381         Expression *get_cond() { return cond; }
    382         void set_cond( Expression *newCond ) { cond = newCond; }
    383         Statement *get_body() { return body; }
    384         void set_body( Statement *newValue ) { body = newValue; }
    385 
    386         virtual CatchStmt *clone() const override { return new CatchStmt( *this ); }
    387         virtual void accept( Visitor &v ) override { v.visit( this ); }
    388         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    389         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     377        Declaration * get_decl() { return decl; }
     378        void set_decl( Declaration * newValue ) { decl = newValue; }
     379        Expression * get_cond() { return cond; }
     380        void set_cond( Expression * newCond ) { cond = newCond; }
     381        Statement * get_body() { return body; }
     382        void set_body( Statement * newValue ) { body = newValue; }
     383
     384        virtual CatchStmt * clone() const override { return new CatchStmt( *this ); }
     385        virtual void accept( Visitor & v ) override { v.visit( this ); }
     386        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     387        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    390388};
    391389
    392390class FinallyStmt : public Statement {
    393391  public:
    394         CompoundStmt *block;
    395 
    396         FinallyStmt( CompoundStmt *block );
    397         FinallyStmt( const FinallyStmt &other );
     392        CompoundStmt * block;
     393
     394        FinallyStmt( CompoundStmt * block );
     395        FinallyStmt( const FinallyStmt & other );
    398396        virtual ~FinallyStmt();
    399397
    400         CompoundStmt *get_block() const { return block; }
    401         void set_block( CompoundStmt *newValue ) { block = newValue; }
    402 
    403         virtual FinallyStmt *clone() const override { return new FinallyStmt( *this ); }
    404         virtual void accept( Visitor &v ) override { v.visit( this ); }
    405         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    406         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     398        CompoundStmt * get_block() const { return block; }
     399        void set_block( CompoundStmt * newValue ) { block = newValue; }
     400
     401        virtual FinallyStmt * clone() const override { return new FinallyStmt( *this ); }
     402        virtual void accept( Visitor & v ) override { v.visit( this ); }
     403        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     404        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    407405};
    408406
     
    438436        } orelse;
    439437
    440         virtual WaitForStmt *clone() const override { return new WaitForStmt( *this ); }
    441         virtual void accept( Visitor &v ) override { v.visit( this ); }
    442         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    443         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     438        virtual WaitForStmt * clone() const override { return new WaitForStmt( *this ); }
     439        virtual void accept( Visitor & v ) override { v.visit( this ); }
     440        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     441        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    444442
    445443};
     
    464462class DeclStmt : public Statement {
    465463  public:
    466         Declaration *decl;
    467 
    468         DeclStmt( Declaration *decl );
    469         DeclStmt( const DeclStmt &other );
     464        Declaration * decl;
     465
     466        DeclStmt( Declaration * decl );
     467        DeclStmt( const DeclStmt & other );
    470468        virtual ~DeclStmt();
    471469
    472         Declaration *get_decl() const { return decl; }
    473         void set_decl( Declaration *newValue ) { decl = newValue; }
    474 
    475         virtual DeclStmt *clone() const override { return new DeclStmt( *this ); }
    476         virtual void accept( Visitor &v ) override { v.visit( this ); }
    477         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    478         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
    479 };
    480 
    481 
    482 /// represents an implicit application of a constructor or destructor. Qualifiers are replaced
    483 /// immediately before and after the call so that qualified objects can be constructed
    484 /// with the same functions as unqualified objects.
     470        Declaration * get_decl() const { return decl; }
     471        void set_decl( Declaration * newValue ) { decl = newValue; }
     472
     473        virtual DeclStmt * clone() const override { return new DeclStmt( *this ); }
     474        virtual void accept( Visitor & v ) override { v.visit( this ); }
     475        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     476        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
     477};
     478
     479
     480/// represents an implicit application of a constructor or destructor. Qualifiers are replaced immediately before and
     481/// after the call so that qualified objects can be constructed with the same functions as unqualified objects.
    485482class ImplicitCtorDtorStmt : public Statement {
    486483  public:
     
    492489        virtual ~ImplicitCtorDtorStmt();
    493490
    494         Statement *get_callStmt() const { return callStmt; }
     491        Statement * get_callStmt() const { return callStmt; }
    495492        void set_callStmt( Statement * newValue ) { callStmt = newValue; }
    496493
    497         virtual ImplicitCtorDtorStmt *clone() const override { return new ImplicitCtorDtorStmt( *this ); }
    498         virtual void accept( Visitor &v ) override { v.visit( this ); }
    499         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    500         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     494        virtual ImplicitCtorDtorStmt * clone() const override { return new ImplicitCtorDtorStmt( *this ); }
     495        virtual void accept( Visitor & v ) override { v.visit( this ); }
     496        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     497        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    501498};
    502499
  • src/main.cc

    r69c37cc rf343c6b  
    6565using namespace std;
    6666
    67 
    6867void NewPass(const char * const name) {
    6968        Stats::Heap::newPass(name);
    7069        using namespace Stats::Counters;
    71         static auto pass_visitor_group = build<CounterGroup>("Pass Visitor");
    72         auto pass = build<CounterGroup>(name, pass_visitor_group);
    73         pass_visitor_stats.depth = 0;
    74         pass_visitor_stats.avg = build<AverageCounter<double>>("Average Depth", pass);
    75         pass_visitor_stats.max = build<MaxCounter<double>>("Max Depth", pass);
     70       
     71        {
     72                static auto group = build<CounterGroup>("Pass Visitor");
     73                auto pass = build<CounterGroup>(name, group);
     74                pass_visitor_stats.depth = 0;
     75                pass_visitor_stats.avg = build<AverageCounter<double>>("Average Depth", pass);
     76                pass_visitor_stats.max = build<MaxCounter<double>>("Max Depth", pass);
     77        }
     78
     79        {
     80                static auto group = build<CounterGroup>("Syntax Node");
     81                auto pass = build<CounterGroup>(name, group);
     82                BaseSyntaxNode::new_nodes = build<SimpleCounter>("Allocs", pass);
     83        }
    7684}
    7785
  • tests/.expect/KRfunctions.x64.txt

    r69c37cc rf343c6b  
    8282    signed int _X1ai_2;
    8383    signed int _X1bi_2;
    84     signed int *(*_tmp_cp_ret2)(signed int _X1xi_1, signed int _X1yi_1);
    85     ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret2=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret2)));
    86     ((void)(_tmp_cp_ret2) /* ^?{} */);
     84    signed int *(*_tmp_cp_ret4)(signed int _X1xi_1, signed int _X1yi_1);
     85    ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
     86    ((void)(_tmp_cp_ret4) /* ^?{} */);
    8787    const signed int _X2f1Fi_iPiPi__2(signed int _X1ai_2, signed int *_X1bPi_2, signed int *_X1cPi_2){
    8888        __attribute__ ((unused)) const signed int _X10_retval_f1Ki_2;
  • tests/.expect/KRfunctions.x86.txt

    r69c37cc rf343c6b  
    8282    signed int _X1ai_2;
    8383    signed int _X1bi_2;
    84     signed int *(*_tmp_cp_ret2)(signed int _X1xi_1, signed int _X1yi_1);
    85     ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret2=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret2)));
    86     ((void)(_tmp_cp_ret2) /* ^?{} */);
     84    signed int *(*_tmp_cp_ret4)(signed int _X1xi_1, signed int _X1yi_1);
     85    ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
     86    ((void)(_tmp_cp_ret4) /* ^?{} */);
    8787    const signed int _X2f1Fi_iPiPi__2(signed int _X1ai_2, signed int *_X1bPi_2, signed int *_X1cPi_2){
    8888        __attribute__ ((unused)) const signed int _X10_retval_f1Ki_2;
  • tests/.expect/completeTypeError.txt

    r69c37cc rf343c6b  
    1 completeTypeError.cfa:33:1 error: No reasonable alternatives for expression Applying untyped:
    2   Name: *?
    3 ...to:
    4   Name: v
     1completeTypeError.cfa:34:1 error: Cannot choose between 2 alternatives for expression
     2Generated Cast of:
     3  Applying untyped:
     4    Name: *?
     5  ...to:
     6    Name: x
    57
    6 completeTypeError.cfa:34:1 error: No reasonable alternatives for expression Applying untyped:
    7   Name: *?
    8 ...to:
    9   Name: y
     8... to: nothing Alternatives are:
     9Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
     10     Application of
     11       Variable Expression: *?: forall
     12         DT: object type
     13         function
     14       ... with parameters
     15         intrinsic pointer to instance of type DT (not function type)
     16       ... returning
     17         _retval__operator_deref: reference to instance of type DT (not function type)
     18         ... with attributes:
     19           Attribute with name: unused
     20
     21
     22     ... to arguments
     23       Variable Expression: x: pointer to instance of struct A with body 0
     24
     25   ... to: nothing
     26 (types:
     27   void
     28 )
     29 Environment:( _80_4_DT ) -> instance of struct A with body 0 (no widening)
     30
     31
     32Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
     33     Application of
     34       Variable Expression: *?: forall
     35         DT: object type
     36         function
     37       ... with parameters
     38         intrinsic pointer to instance of type DT (not function type)
     39       ... returning
     40         _retval__operator_deref: reference to instance of type DT (not function type)
     41         ... with attributes:
     42           Attribute with name: unused
     43
     44
     45     ... to arguments
     46       Variable Expression: x: pointer to instance of struct B with body 1
     47
     48   ... to: nothing
     49 (types:
     50   void
     51 )
     52 Environment:( _80_4_DT ) -> instance of struct B with body 1 (no widening)
     53
     54
    1055
    1156completeTypeError.cfa:35:1 error: No reasonable alternatives for expression Applying untyped:
     
    2469  Name: v
    2570
    26 completeTypeError.cfa:58:1 error: No reasonable alternatives for expression Applying untyped:
     71completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped:
    2772  Name: baz
    2873...to:
    2974  Name: y
    3075
    31 completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped:
     76completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped:
    3277  Name: quux
    3378...to:
    3479  Name: y
    3580
    36 completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped:
    37   Name: *?
    38 ...to:
    39   Name: y
    40 
    41 completeTypeError.cfa:72:1 error: No resolvable alternatives for expression Applying untyped:
     81completeTypeError.cfa:72:1 error: No alternatives with satisfiable assertions for Applying untyped:
    4282  Name: baz
    4383...to:
    4484  Name: z
    4585
    46 Alternatives with failing assertions are:
     86   Unsatisfiable alternative:
    4787Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
    48      Variable Expression: baz: forall
    49        T: sized object type
    50        ... with assertions
    51          ?=?: pointer to function
    52          ... with parameters
    53            reference to instance of type T (not function type)
    54            instance of type T (not function type)
    55          ... returning
    56            _retval__operator_assign: instance of type T (not function type)
    57            ... with attributes:
    58              Attribute with name: unused
     88         Variable Expression: baz: forall
     89           T: sized object type
     90           ... with assertions
     91             ?=?: pointer to function
     92             ... with parameters
     93               reference to instance of type T (not function type)
     94               instance of type T (not function type)
     95             ... returning
     96               _retval__operator_assign: instance of type T (not function type)
     97               ... with attributes:
     98                 Attribute with name: unused
    5999
    60100
    61          ?{}: pointer to function
     101             ?{}: pointer to function
     102             ... with parameters
     103               reference to instance of type T (not function type)
     104             ... returning nothing
     105
     106             ?{}: pointer to function
     107             ... with parameters
     108               reference to instance of type T (not function type)
     109               instance of type T (not function type)
     110             ... returning nothing
     111
     112             ^?{}: pointer to function
     113             ... with parameters
     114               reference to instance of type T (not function type)
     115             ... returning nothing
     116
     117
     118           function
    62119         ... with parameters
    63            reference to instance of type T (not function type)
     120           pointer to instance of type T (not function type)
    64121         ... returning nothing
    65122
    66          ?{}: pointer to function
    67          ... with parameters
    68            reference to instance of type T (not function type)
    69            instance of type T (not function type)
    70          ... returning nothing
     123       ... to arguments
     124         Variable Expression: z: pointer to instance of type T (not function type)
    71125
    72          ^?{}: pointer to function
    73          ... with parameters
    74            reference to instance of type T (not function type)
    75          ... returning nothing
     126     (types:
     127       void
     128     )
     129     Environment:( _99_0_T ) -> instance of type T (not function type) (no widening)
     130
     131   Could not satisfy assertion:
     132?=?: pointer to function
     133     ... with parameters
     134       reference to instance of type _99_0_T (not function type)
     135       instance of type _99_0_T (not function type)
     136     ... returning
     137       _retval__operator_assign: instance of type _99_0_T (not function type)
     138       ... with attributes:
     139         Attribute with name: unused
    76140
    77141
    78        function
    79      ... with parameters
    80        pointer to instance of type T (not function type)
    81      ... returning nothing
    82 
    83    ... to arguments
    84      Variable Expression: z: pointer to instance of type T (not function type)
    85 
    86  (types:
    87    void
    88  )
    89  Environment:( _74_0_T ) -> instance of type T (not function type) (no widening)
    90 
    91 
    92 
  • tests/.expect/declarationSpecifier.x64.txt

    r69c37cc rf343c6b  
    698698signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    699699    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    700     signed int _tmp_cp_ret2;
    701     ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret2)) /* ?{} */);
    702     ((void)(_tmp_cp_ret2) /* ^?{} */);
     700    signed int _tmp_cp_ret4;
     701    ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
     702    ((void)(_tmp_cp_ret4) /* ^?{} */);
    703703    return _X12_retval_maini_1;
    704704}
  • tests/.expect/declarationSpecifier.x86.txt

    r69c37cc rf343c6b  
    698698signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    699699    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    700     signed int _tmp_cp_ret2;
    701     ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret2)) /* ?{} */);
    702     ((void)(_tmp_cp_ret2) /* ^?{} */);
     700    signed int _tmp_cp_ret4;
     701    ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
     702    ((void)(_tmp_cp_ret4) /* ^?{} */);
    703703    return _X12_retval_maini_1;
    704704}
  • tests/.expect/extension.x64.txt

    r69c37cc rf343c6b  
    186186    __extension__ signed int _X1ci_2;
    187187    ((void)(__extension__ _X1ai_2=(__extension__ _X1bi_2+__extension__ _X1ci_2)));
    188     signed int _tmp_cp_ret2;
    189     ((void)(((void)(_tmp_cp_ret2=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret2));
    190     ((void)(_tmp_cp_ret2) /* ^?{} */);
     188    signed int _tmp_cp_ret4;
     189    ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
     190    ((void)(_tmp_cp_ret4) /* ^?{} */);
    191191    __extension__ signed int _X4maryFi_i__2(signed int _X1pi_2){
    192192        __attribute__ ((unused)) signed int _X12_retval_maryi_2;
  • tests/.expect/extension.x86.txt

    r69c37cc rf343c6b  
    186186    __extension__ signed int _X1ci_2;
    187187    ((void)(__extension__ _X1ai_2=(__extension__ _X1bi_2+__extension__ _X1ci_2)));
    188     signed int _tmp_cp_ret2;
    189     ((void)(((void)(_tmp_cp_ret2=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret2));
    190     ((void)(_tmp_cp_ret2) /* ^?{} */);
     188    signed int _tmp_cp_ret4;
     189    ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
     190    ((void)(_tmp_cp_ret4) /* ^?{} */);
    191191    __extension__ signed int _X4maryFi_i__2(signed int _X1pi_2){
    192192        __attribute__ ((unused)) signed int _X12_retval_maryi_2;
  • tests/.expect/gccExtensions.x64.txt

    r69c37cc rf343c6b  
    171171signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    172172    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    173     signed int _tmp_cp_ret2;
    174     ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret2)) /* ?{} */);
    175     ((void)(_tmp_cp_ret2) /* ^?{} */);
     173    signed int _tmp_cp_ret4;
     174    ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
     175    ((void)(_tmp_cp_ret4) /* ^?{} */);
    176176    return _X12_retval_maini_1;
    177177}
  • tests/.expect/gccExtensions.x86.txt

    r69c37cc rf343c6b  
    171171signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    172172    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    173     signed int _tmp_cp_ret2;
    174     ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret2)) /* ?{} */);
    175     ((void)(_tmp_cp_ret2) /* ^?{} */);
     173    signed int _tmp_cp_ret4;
     174    ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
     175    ((void)(_tmp_cp_ret4) /* ^?{} */);
    176176    return _X12_retval_maini_1;
    177177}
  • tests/.expect/loopctrl.txt

    r69c37cc rf343c6b  
    191910 8 6 4 2
    2020
     211 2 3 4 5 6 7 8 9 10
     2210 9 8 7 6 5 4 3 2 1 0
    21232 4 6 8 10
    22242.1 3.8 5.5 7.2 8.9
     
    4244(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)
    4345(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)
     46
     470 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4
     480 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14
     490 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13
     500 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23
     51
     520 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4
     530 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14
     540 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13
     550 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23
     56
     570 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5
     580 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5
     590 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5
  • tests/.expect/math1.txt

    r69c37cc rf343c6b  
    1010expm1:1.71828 1.71828182845905 1.71828182845904524
    1111pow:1 1 1 0.273957+0.583701i 0.273957253830121+0.583700758758615i -0.638110484918098871+0.705394566961838155i
    12 \ 16 256
    13 \ 912673 256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
     1216 \ 2 = 256
     13912673 256 64 -64 0 0
     140.015625 -0.015625 18.3791736799526 0.264715-1.1922i
     150 0 18.3791736799526 0.264715-1.1922i
     1616
     174 16
  • tests/Makefile.am

    r69c37cc rf343c6b  
    2828timeouts=
    2929
    30 TEST_PY = python ${builddir}/test.py
     30TEST_PY = python3 ${builddir}/test.py
    3131
    3232# applies to both programs
     
    3636        -Wno-unused-function \
    3737        -quiet @CFA_FLAGS@ \
    38         -DIN_DIR="${srcdir}/.in/"
     38        -DIN_DIR="${abs_srcdir}/.in/"
    3939
    4040AM_CFLAGS += ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS}
    4141CC = @CFACC@
    4242
    43 PRETTY_PATH=cd ${srcdir} &&
     43PRETTY_PATH=mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
    4444
    4545.PHONY: list .validate
     
    4848
    4949avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa
    50 # automake doesn't know we still need C rules so pretend like we have a C program
    51 _dummy_hack_SOURCES = .dummy_hack.c
     50# automake doesn't know we still need C/CPP rules so pretend like we have a C program
     51_dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp
    5252
    5353#----------------------------------------------------------------------------------------------------------------
     
    7474        @echo "int main() { return 0; }" > ${@}
    7575
     76.dummy_hackxx.cpp:
     77        @echo "int bar() { return 0; }" > ${@}
     78
    7679concurrency :
    7780        @+${TEST_PY} --debug=${debug}  --install=${installed} -Iconcurrent
     
    7982#----------------------------------------------------------------------------------------------------------------
    8083
     84# Use for all tests, make sure the path are correct and all flags are added
     85CFACOMPILETEST=$(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) $($(shell echo "${@}_FLAGS" | sed 's/-\|\//_/g'))
     86
     87# Use for tests that either generate an executable, print directyl to stdout or the make command is expected to fail
     88CFATEST_STDOUT=$(CFACOMPILETEST) -o $(abspath ${@})
     89
     90# Use for tests where the make command is expecte to succeed but the expected.txt should be compared to stderr
     91CFATEST_STDERR=$(CFACOMPILETEST) 2> $(abspath ${@})
     92
     93#----------------------------------------------------------------------------------------------------------------
     94
    8195# implicit rule so not all test require a rule
    8296% : %.cfa $(CFACC)
    83         $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     97        $(CFATEST_STDOUT)
    8498
    85 declarationSpecifier: declarationSpecifier.cfa $(CFACC)
    86         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     99% : %.cpp
     100        $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    87101
    88 gccExtensions : gccExtensions.cfa $(CFACC)
    89         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     102#------------------------------------------------------------------------------
     103# TARGET WITH STANDARD RULE BUT CUSTOM FLAGS
     104#------------------------------------------------------------------------------
     105# Expected failures
     106declarationSpecifier_FLAGS= -CFA -XCFA -p
     107gccExtensions_FLAGS= -CFA -XCFA -p
     108extension_FLAGS= -CFA -XCFA -p
     109attributes_FLAGS= -CFA -XCFA -p
     110functions_FLAGS= -CFA -XCFA -p
     111KRfunctions_FLAGS= -CFA -XCFA -p
     112gmp_FLAGS= -lgmp
    90113
    91 extension : extension.cfa $(CFACC)
    92         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     114#------------------------------------------------------------------------------
     115# Expected failures
     116completeTypeError_FLAGS= -DERR1
    93117
    94 attributes : attributes.cfa $(CFACC)
    95         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     118#------------------------------------------------------------------------------
     119# CUSTOM TARGET
     120#------------------------------------------------------------------------------
     121typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
     122        $(CFATEST_STDOUT) -DERR1
    96123
    97 functions: functions.cfa $(CFACC)
    98         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     124alloc-ERROR: alloc.cfa $(CFACC)
     125        $(CFATEST_STDOUT) -DERR1
    99126
    100 KRfunctions : KRfunctions.cfa $(CFACC)
    101         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     127nested-types-ERR1: nested-types.cfa $(CFACC)
     128        $(CFATEST_STDOUT) -DERR1
    102129
    103 sched-ext-parse : sched-ext-parse.c $(CFACC)
    104         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     130nested-types-ERR2: nested-types.cfa $(CFACC)
     131        $(CFATEST_STDOUT) -DERR2
    105132
    106 gmp : gmp.cfa $(CFACC)
    107         $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     133raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
     134        $(CFATEST_STDOUT) -DERR1
     135
     136raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
     137        $(CFATEST_STDOUT) -DERR2
     138
     139raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
     140        $(CFATEST_STDOUT) -DERR1
     141
     142raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
     143        $(CFATEST_STDOUT) -DERR1
    108144
    109145#builtins
    110146builtins/sync: builtins/sync.cfa $(CFACC)
    111         $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
    112 
    113 #------------------------------------------------------------------------------
    114 
    115 #To make errors path independent we need to cd into the correct directories
    116 completeTypeError : completeTypeError.cfa $(CFACC)
    117         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    118 
    119 typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
    120         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    121 
    122 alloc-ERROR: alloc.cfa $(CFACC)
    123         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    124 
    125 fallthrough-ERROR: fallthrough.cfa $(CFACC)
    126         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    127 
    128 nested-types-ERR1: nested-types.cfa $(CFACC)
    129         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    130 
    131 nested-types-ERR2: nested-types.cfa $(CFACC)
    132         $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    133 
    134 # Constructor/destructor tests
    135 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
    136         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    137 
    138 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
    139         $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    140 
    141 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
    142         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    143 
    144 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
    145         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     147        $(CFATEST_STDERR) -fsyntax-only
    146148
    147149# Warnings
    148150warnings/self-assignment: warnings/self-assignment.cfa $(CFACC)
    149         $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
     151        $(CFATEST_STDERR) -fsyntax-only
  • tests/Makefile.in

    r69c37cc rf343c6b  
    107107CONFIG_CLEAN_FILES = config.py
    108108CONFIG_CLEAN_VPATH_FILES = test.py
    109 am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT)
     109am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT) .dummy_hackxx.$(OBJEXT)
    110110_dummy_hack_OBJECTS = $(am__dummy_hack_OBJECTS)
    111111_dummy_hack_LDADD = $(LDADD)
     
    155155am__v_CCLD_0 = @echo "  CCLD    " $@;
    156156am__v_CCLD_1 =
     157CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
     158        $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
     159LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
     160        $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
     161        $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
     162        $(AM_CXXFLAGS) $(CXXFLAGS)
     163AM_V_CXX = $(am__v_CXX_@AM_V@)
     164am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
     165am__v_CXX_0 = @echo "  CXX     " $@;
     166am__v_CXX_1 =
     167CXXLD = $(CXX)
     168CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
     169        $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
     170        $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
     171AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
     172am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
     173am__v_CXXLD_0 = @echo "  CXXLD   " $@;
     174am__v_CXXLD_1 =
    157175SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES)
    158176DIST_SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES)
     
    360378concurrent =
    361379timeouts =
    362 TEST_PY = python ${builddir}/test.py
     380TEST_PY = python3 ${builddir}/test.py
    363381
    364382# applies to both programs
    365383AM_CFLAGS = $(if $(test), 2> $(test), ) -g -Wall -Wno-unused-function \
    366         -quiet @CFA_FLAGS@ -DIN_DIR="${srcdir}/.in/" ${DEBUG_FLAGS} \
    367         ${INSTALL_FLAGS} ${ARCH_FLAGS}
    368 PRETTY_PATH = cd ${srcdir} &&
     384        -quiet @CFA_FLAGS@ -DIN_DIR="${abs_srcdir}/.in/" \
     385        ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS}
     386PRETTY_PATH = mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
    369387avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa
    370 # automake doesn't know we still need C rules so pretend like we have a C program
    371 _dummy_hack_SOURCES = .dummy_hack.c
     388# automake doesn't know we still need C/CPP rules so pretend like we have a C program
     389_dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp
     390
     391#----------------------------------------------------------------------------------------------------------------
     392
     393# Use for all tests, make sure the path are correct and all flags are added
     394CFACOMPILETEST = $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) $($(shell echo "${@}_FLAGS" | sed 's/-\|\//_/g'))
     395
     396# Use for tests that either generate an executable, print directyl to stdout or the make command is expected to fail
     397CFATEST_STDOUT = $(CFACOMPILETEST) -o $(abspath ${@})
     398
     399# Use for tests where the make command is expecte to succeed but the expected.txt should be compared to stderr
     400CFATEST_STDERR = $(CFACOMPILETEST) 2> $(abspath ${@})
     401
     402#------------------------------------------------------------------------------
     403# TARGET WITH STANDARD RULE BUT CUSTOM FLAGS
     404#------------------------------------------------------------------------------
     405# Expected failures
     406declarationSpecifier_FLAGS = -CFA -XCFA -p
     407gccExtensions_FLAGS = -CFA -XCFA -p
     408extension_FLAGS = -CFA -XCFA -p
     409attributes_FLAGS = -CFA -XCFA -p
     410functions_FLAGS = -CFA -XCFA -p
     411KRfunctions_FLAGS = -CFA -XCFA -p
     412gmp_FLAGS = -lgmp
     413
     414#------------------------------------------------------------------------------
     415# Expected failures
     416completeTypeError_FLAGS = -DERR1
    372417all: all-am
    373418
    374419.SUFFIXES:
    375 .SUFFIXES: .c .cfa .dummy_hack .lo .o .obj .validate
     420.SUFFIXES: .c .cfa .cpp .dummy_hack .dummy_hackxx .lo .o .obj .validate
    376421$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/src/cfa.make $(am__configure_deps)
    377422        @for dep in $?; do \
     
    409454.dummy_hack$(EXEEXT): $(_dummy_hack_OBJECTS) $(_dummy_hack_DEPENDENCIES) $(EXTRA__dummy_hack_DEPENDENCIES)
    410455        @rm -f .dummy_hack$(EXEEXT)
    411         $(AM_V_CCLD)$(LINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS)
     456        $(AM_V_CXXLD)$(CXXLINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS)
    412457avltree/$(am__dirstamp):
    413458        @$(MKDIR_P) avltree
     
    443488
    444489@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/.dummy_hack.Po@am__quote@
     490@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/.dummy_hackxx.Po@am__quote@
    445491
    446492.c.o:
     
    467513@AMDEP_TRUE@@am__fastdepCC_FALSE@       DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
    468514@am__fastdepCC_FALSE@   $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
     515
     516.cpp.o:
     517@am__fastdepCXX_TRUE@   $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
     518@am__fastdepCXX_TRUE@   $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
     519@am__fastdepCXX_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
     520@AMDEP_TRUE@@am__fastdepCXX_FALSE@      $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
     521@AMDEP_TRUE@@am__fastdepCXX_FALSE@      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
     522@am__fastdepCXX_FALSE@  $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
     523
     524.cpp.obj:
     525@am__fastdepCXX_TRUE@   $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
     526@am__fastdepCXX_TRUE@   $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
     527@am__fastdepCXX_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Po
     528@AMDEP_TRUE@@am__fastdepCXX_FALSE@      $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
     529@AMDEP_TRUE@@am__fastdepCXX_FALSE@      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
     530@am__fastdepCXX_FALSE@  $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
     531
     532.cpp.lo:
     533@am__fastdepCXX_TRUE@   $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
     534@am__fastdepCXX_TRUE@   $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
     535@am__fastdepCXX_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.Plo
     536@AMDEP_TRUE@@am__fastdepCXX_FALSE@      $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
     537@AMDEP_TRUE@@am__fastdepCXX_FALSE@      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
     538@am__fastdepCXX_FALSE@  $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
    469539
    470540mostlyclean-libtool:
     
    717787        @echo "int main() { return 0; }" > ${@}
    718788
     789.dummy_hackxx.cpp:
     790        @echo "int bar() { return 0; }" > ${@}
     791
    719792concurrency :
    720793        @+${TEST_PY} --debug=${debug}  --install=${installed} -Iconcurrent
     
    724797# implicit rule so not all test require a rule
    725798% : %.cfa $(CFACC)
    726         $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    727 
    728 declarationSpecifier: declarationSpecifier.cfa $(CFACC)
    729         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    730 
    731 gccExtensions : gccExtensions.cfa $(CFACC)
    732         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    733 
    734 extension : extension.cfa $(CFACC)
    735         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    736 
    737 attributes : attributes.cfa $(CFACC)
    738         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    739 
    740 functions: functions.cfa $(CFACC)
    741         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    742 
    743 KRfunctions : KRfunctions.cfa $(CFACC)
    744         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    745 
    746 sched-ext-parse : sched-ext-parse.c $(CFACC)
    747         $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    748 
    749 gmp : gmp.cfa $(CFACC)
    750         $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     799        $(CFATEST_STDOUT)
     800
     801% : %.cpp
     802        $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     803
     804#------------------------------------------------------------------------------
     805# CUSTOM TARGET
     806#------------------------------------------------------------------------------
     807typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
     808        $(CFATEST_STDOUT) -DERR1
     809
     810alloc-ERROR: alloc.cfa $(CFACC)
     811        $(CFATEST_STDOUT) -DERR1
     812
     813nested-types-ERR1: nested-types.cfa $(CFACC)
     814        $(CFATEST_STDOUT) -DERR1
     815
     816nested-types-ERR2: nested-types.cfa $(CFACC)
     817        $(CFATEST_STDOUT) -DERR2
     818
     819raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
     820        $(CFATEST_STDOUT) -DERR1
     821
     822raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
     823        $(CFATEST_STDOUT) -DERR2
     824
     825raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
     826        $(CFATEST_STDOUT) -DERR1
     827
     828raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
     829        $(CFATEST_STDOUT) -DERR1
    751830
    752831#builtins
    753832builtins/sync: builtins/sync.cfa $(CFACC)
    754         $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
    755 
    756 #------------------------------------------------------------------------------
    757 
    758 #To make errors path independent we need to cd into the correct directories
    759 completeTypeError : completeTypeError.cfa $(CFACC)
    760         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    761 
    762 typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
    763         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    764 
    765 alloc-ERROR: alloc.cfa $(CFACC)
    766         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    767 
    768 fallthrough-ERROR: fallthrough.cfa $(CFACC)
    769         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    770 
    771 nested-types-ERR1: nested-types.cfa $(CFACC)
    772         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    773 
    774 nested-types-ERR2: nested-types.cfa $(CFACC)
    775         $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    776 
    777 # Constructor/destructor tests
    778 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
    779         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    780 
    781 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
    782         $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    783 
    784 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
    785         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    786 
    787 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
    788         $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     833        $(CFATEST_STDERR) -fsyntax-only
    789834
    790835# Warnings
    791836warnings/self-assignment: warnings/self-assignment.cfa $(CFACC)
    792         $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
     837        $(CFATEST_STDERR) -fsyntax-only
    793838
    794839# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • tests/completeTypeError.cfa

    r69c37cc rf343c6b  
    55forall(dtype T | sized(T)) void quux(T *);
    66
    7 struct A; // incomplete
    8 struct B {}; // complete
     7struct A;       // incomplete
     8struct B {};    // complete
    99
    1010int main() {
    11         int *i;
    12         void *v;
     11        int * i;
     12        void * v;
    1313
    1414        A * x;
     
    1919        // okay
    2020        *i;
    21         *x; // picks B
     21        *y;
    2222        *z;
    2323        foo(i);
     
    3232        // bad
    3333        *v;
    34         *y;
     34        *x;     // ambiguous
    3535        foo(v);
    3636        baz(v);
     
    5252void qux(T * y) {
    5353        // okay
     54        *y;
    5455        bar(y);
    5556        qux(y);
     
    5859        baz(y);
    5960        quux(y);
    60         *y;
    6161}
    6262
  • tests/concurrent/examples/boundedBufferEXT.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed Apr 18 22:52:12 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 20 08:36:45 2019
    13 // Update Count     : 11
     12// Last Modified On : Fri Mar 22 13:41:33 2019
     13// Update Count     : 12
    1414//
    1515
     
    122122// Local Variables: //
    123123// tab-width: 4 //
    124 // compile-command: "cfa boundedBufferEXT.c" //
     124// compile-command: "cfa boundedBufferEXT.cfa" //
    125125// End: //
  • tests/concurrent/examples/boundedBufferINT.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Mon Oct 30 12:45:13 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 20 08:37:24 2019
    13 // Update Count     : 87
     12// Last Modified On : Fri Mar 22 13:41:52 2019
     13// Update Count     : 88
    1414//
    1515
     
    123123// Local Variables: //
    124124// tab-width: 4 //
    125 // compile-command: "cfa boundedBufferINT.c" //
     125// compile-command: "cfa boundedBufferINT.cfa" //
    126126// End: //
  • tests/concurrent/examples/datingService.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Mon Oct 30 12:56:20 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Feb 20 08:37:12 2019
    13 // Update Count     : 30
     12// Last Modified On : Fri Mar 22 13:41:39 2019
     13// Update Count     : 31
    1414//
    1515
     
    112112// Local Variables: //
    113113// tab-width: 4 //
    114 // compile-command: "cfa datingService.c" //
     114// compile-command: "cfa datingService.cfa" //
    115115// End: //
  • tests/concurrent/examples/quickSort.cfa

    r69c37cc rf343c6b  
    1111// Created On       : Wed Dec  6 12:15:52 2017
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Wed Feb 20 08:38:24 2019
    14 // Update Count     : 169
     13// Last Modified On : Fri Mar 22 13:42:01 2019
     14// Update Count     : 170
    1515//
    1616
     
    180180// Local Variables: //
    181181// tab-width: 4 //
    182 // compile-command: "cfa quickSort.c" //
     182// compile-command: "cfa quickSort.cfa" //
    183183// End: //
  • tests/concurrent/waitfor/parse2.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed Aug 30 17:53:29 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Aug 30 17:55:17 2017
    13 // Update Count     : 2
     12// Last Modified On : Fri Mar 22 13:42:11 2019
     13// Update Count     : 3
    1414//
    1515
     
    246246// Local Variables: //
    247247// tab-width: 4 //
    248 // compile-command: "cfa waitfor.c" //
     248// compile-command: "cfa waitfor.cfa" //
    249249// End: //
  • tests/config.py.in

    r69c37cc rf343c6b  
    1 #!/usr/bin/env python
     1#!/usr/bin/env python3
    22# encoding: utf-8
    33"""
  • tests/coroutine/.expect/fmtLines.txt

    r69c37cc rf343c6b  
    1616difi  ed B  y :   Pete  r A. 
    1717 Buh  r//   Last   Mod  ifie 
    18 d On   : T  ue D  ec 1  1 2
    19 :31:  12 2  018/  / Up  date 
    20  Cou  nt       :   32/  /#in 
     18d On   : F  ri M  ar 2  2 1
     19:41:  03 2  019/  / Up  date 
     20 Cou  nt       :   33/  /#in 
    2121clud  e <f  stre  am.h  fa># 
    2222incl  ude   <cor  outi  ne.h 
     
    7676th:   4 //  // c  ompi  le-c 
    7777omma  nd:   "cfa   fmt  Line 
    78 s.c"   ///  / En  d: /  /
     78s.cf  a" /  ///   End:   //
  • tests/coroutine/.in/fmtLines.txt

    r69c37cc rf343c6b  
    1010// Created On       : Sun Sep 17 21:56:15 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec 11 23:31:12 2018
    13 // Update Count     : 32
     12// Last Modified On : Fri Mar 22 13:41:03 2019
     13// Update Count     : 33
    1414//
    1515
     
    6464// Local Variables: //
    6565// tab-width: 4 //
    66 // compile-command: "cfa fmtLines.c" //
     66// compile-command: "cfa fmtLines.cfa" //
    6767// End: //
  • tests/coroutine/fibonacci.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Thu Jun  8 07:29:37 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec 11 21:57:33 2018
    13 // Update Count     : 25
     12// Last Modified On : Fri Mar 22 13:40:35 2019
     13// Update Count     : 26
    1414//
    1515
     
    4545// Local Variables: //
    4646// tab-width: 4 //
    47 // compile-command: "cfa fibonacci.c" //
     47// compile-command: "cfa fibonacci.cfa" //
    4848// End: //
  • tests/coroutine/fibonacci_1.cfa

    r69c37cc rf343c6b  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // fibonacci_1.c -- 1-state finite-state machine: precomputed first two states returning f(n - 2)
     7// fibonacci_1.cfa -- 1-state finite-state machine: precomputed first two states returning f(n - 1)
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Thu Apr 26 23:20:08 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec 11 21:57:54 2018
    13 // Update Count     : 14
     12// Last Modified On : Thu Mar 21 08:10:45 2019
     13// Update Count     : 25
    1414//
    1515
     
    1717#include <coroutine.hfa>
    1818
    19 coroutine Fibonacci { int ret; };                                               // used for communication
     19coroutine Fibonacci { int fn1; };                                               // used for communication
    2020
    2121void main( Fibonacci & fib ) with( fib ) {                              // called on first resume
    22         int fn, fn1 = 1, fn2 = 0;                                                       // precompute first two states
     22        int fn;
     23        [fn1, fn] = [0, 1];                                                                     // precompute first two states
    2324        for () {
    24                 ret = fn2;
    25                 fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;                  // general case
    2625                suspend();                                                                              // restart last resume
     26                [fn1, fn] = [fn, fn1 + fn];                                             // general case
    2727        } // for
    2828}
     
    3030int next( Fibonacci & fib ) with( fib ) {
    3131        resume( fib );                                                                          // restart last suspend
    32         return ret;
     32        return fn1;
    3333}
    3434
     
    4242// Local Variables: //
    4343// tab-width: 4 //
    44 // compile-command: "cfa fibonacci_1.c" //
     44// compile-command: "cfa fibonacci_1.cfa" //
    4545// End: //
  • tests/coroutine/fmtLines.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Sun Sep 17 21:56:15 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Dec 22 18:27:00 2018
    13 // Update Count     : 57
     12// Last Modified On : Fri Mar 22 13:41:16 2019
     13// Update Count     : 58
    1414//
    1515
     
    6363// Local Variables: //
    6464// tab-width: 4 //
    65 // compile-command: "cfa fmtLines.c" //
     65// compile-command: "cfa fmtLines.cfa" //
    6666// End: //
  • tests/coroutine/pingpong.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed Sep 20 11:55:23 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec 11 21:58:06 2018
    13 // Update Count     : 29
     12// Last Modified On : Tue Mar 26 17:54:14 2019
     13// Update Count     : 35
    1414//
    1515
     
    2020        const char * name;
    2121        /* const */ unsigned int N;
    22         PingPong * part;
     22        PingPong & part;
    2323};
    2424
    2525void ?{}( PingPong & this, const char * name, unsigned int N, PingPong & part ) {
    26         (this.__cor){name};
    27         this.name = name;
    28         this.N = N;
    29         this.part = &part;
     26        this.[name, N] = [name, N];  &this.part = &part;
    3027}
    3128void ?{}( PingPong & this, const char * name, unsigned int N ) {
    32         this{ name, N, *(PingPong *)0 };
     29        this{ name, N, *0p };                                                           // call first constructor
    3330}
    3431void cycle( PingPong & pingpong ) {
     
    3633}
    3734void partner( PingPong & this, PingPong & part ) {
    38         this.part = &part;
     35        &this.part = &part;
    3936        resume( this );
    4037}
    41 void main( PingPong & pingpong ) {                                              // ping's starter ::main, pong's starter ping
    42         for ( pingpong.N ) {                                                            // N ping-pongs
    43                 sout | pingpong.name;
    44                 cycle( *pingpong.part );
     38void main( PingPong & pingpong ) with(pingpong) {               // ping's starter ::main, pong's starter ping
     39        for ( N ) {                                                                                     // N ping-pongs
     40                sout | name;
     41                cycle( part );
    4542        } // for
    4643}
     
    5350// Local Variables: //
    5451// tab-width: 4 //
    55 // compile-command: "cfa pingpong.c" //
     52// compile-command: "cfa pingpong.cfa" //
    5653// End: //
  • tests/coroutine/prodcons.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Mon Sep 18 12:23:39 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 12 23:04:49 2018
    13 // Update Count     : 53
     12// Last Modified On : Fri Mar 22 13:41:10 2019
     13// Update Count     : 54
    1414//
    1515
     
    9191// Local Variables: //
    9292// tab-width: 4 //
    93 // compile-command: "cfa prodcons.c" //
     93// compile-command: "cfa prodcons.cfa" //
    9494// End: //
  • tests/coroutine/runningTotal.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed Dec  6 08:05:27 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec 11 21:59:00 2018
    13 // Update Count     : 4
     12// Last Modified On : Fri Mar 22 13:40:49 2019
     13// Update Count     : 5
    1414//
    1515
     
    4848// Local Variables: //
    4949// tab-width: 4 //
    50 // compile-command: "cfa runningTotal.c" //
     50// compile-command: "cfa runningTotal.cfa" //
    5151// End: //
  • tests/forall.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed May  9 08:48:15 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Nov  6 17:53:43 2018
    13 // Update Count     : 31
     12// Last Modified On : Tue Mar 19 08:29:38 2019
     13// Update Count     : 32
    1414//
    1515
     
    5353        right = temp;
    5454}
    55 
    56 void ?{}( int & c, zero_t ) { c = 0; }                                  // not in prelude
    5755
    5856trait sumable( otype T ) {
  • tests/function-operator.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Fri Aug 25 15:21:11 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec  4 21:37:09 2018
    13 // Update Count     : 9
     12// Last Modified On : Thu Apr 11 18:27:45 2019
     13// Update Count     : 10
    1414//
    1515
     
    6262
    6363// test ?()(T, ...) -- ?() with function call-by-reference
    64 forall(otype Generator, otype GenRet | { GenRet ?()(Generator &); }, dtype Iter, otype T| Iterator(Iter, T) | Assignable(T, GenRet))
     64forall(otype Generator, otype GenRet | { GenRet ?()(Generator &); }, dtype Iter, otype T | Iterator(Iter, T) | Assignable(T, GenRet))
    6565void generate(Iter first, Iter last, Generator & gen) {
    6666        int i = 0;
  • tests/io2.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed Mar  2 16:56:02 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 21 08:20:14 2018
    13 // Update Count     : 112
     12// Last Modified On : Thu Apr 18 08:03:30 2019
     13// Update Count     : 113
    1414//
    1515
     
    9797        sout | 1 | sepOff | 2 | 3;                                                      // locally turn off implicit separator
    9898        sout | sepOn | sepOn | 1 | 2 | 3 | sepOn | sepOff | sepOn | '\n' | nonl; // no separator at start/end of line
    99         sout | 1 | 2 | 3 | "\n\n" | sepOn | nonl;                                       // no separator at start of next line
     99        sout | 1 | 2 | 3 | "\n\n" | sepOn | nonl;                       // no separator at start of next line
    100100        sout | 1 | 2 | 3;
    101101        sout | nl;
  • tests/loopctrl.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Wed Aug  8 18:32:59 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb 21 08:54:47 2019
    13 // Update Count     : 86
     12// Last Modified On : Sat Apr 13 11:03:09 2019
     13// Update Count     : 104
    1414//
    1515
     
    5656        for ( ui; 10u -~= 2u ~ 2u ) { sout | ui; }                      sout | nl | nl;
    5757
     58        // @ means do nothing
     59        for ( i; 1 ~ @ ) {
     60          if ( i > 10 ) break;
     61                sout | i;
     62        }                                                                                                       sout | nl;
     63        for ( i; 10 -~ @ ) {
     64          if ( i < 0 ) break;
     65                sout | i;
     66        }                                                                                                       sout | nl;
    5867        for ( i; 2 ~ @ ~ 2 ) {
    5968          if ( i > 10 ) break;
     
    94103        for ( s; (S){10,10} -~ (S){0} ~ (S){1} ) { sout | s; } sout | nl;
    95104        for ( s; (S){10,10} -~= (S){0} ) { sout | s; }           sout | nl;
    96         for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { sout | s; } sout | nl;
     105        for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { sout | s; } sout | nl | nl;
     106
     107        for ( i; 10 : j; -5 ~ @ ) { sout | i | j; } sout | nl;
     108        for ( i; 10 : j; -5 -~ @ ) { sout | i | j; } sout | nl;
     109        for ( i; 10 : j; -5 ~ @ ~ 2 ) { sout | i | j; } sout | nl;
     110        for ( i; 10 : j; -5 -~ @ ~ 2 ) { sout | i | j; } sout | nl | nl;
     111
     112        for ( j; -5 ~ @ : i; 10 ) { sout | i | j; } sout | nl;
     113        for ( j; -5 -~ @ : i; 10 ) { sout | i | j; } sout | nl;
     114        for ( j; -5 ~ @ ~ 2 : i; 10 ) { sout | i | j; } sout | nl;
     115        for ( j; -5 -~ @ ~ 2 : i; 10 ) { sout | i | j; } sout | nl | nl;
     116
     117        for ( j; -5 -~ @ ~ 2 : i; 10 : k; 1.5 ~ @ ) { sout | i | j | k; } sout | nl;
     118        for ( j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 10 ) { sout | i | j | k; } sout | nl;
     119        for ( k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 10 ) { sout | i | j | k; } sout | nl;
    97120}
    98121
  • tests/math1.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Fri Apr 22 14:59:21 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 12 16:28:49 2018
    13 // Update Count     : 89
     12// Last Modified On : Mon Mar 25 22:56:47 2019
     13// Update Count     : 109
    1414//
    1515
     
    4949        unsigned int e = 2;
    5050    b \= e;
    51     sout | "\\" | b | b \ e;
    52     sout | "\\" | 'a' \ 3u | 2 \ 8u | 4 \ 3u | -4 \ 3u | nonl;
     51    sout | b | "\\" | e | "= " | b \ e;
     52    sout | 'a' \ 3 | 2 \ 8 | 4 \ 3 | -4 \ 3 | 4 \ -3 | -4 \ -3;
     53        sout | 4.0 \ -3 | -4.0 \ -3 | 4.0 \ 2.1 | (1.0f+2.0fi) \ (3.0f+2.0fi);
    5354        sout | 4 \ -3 | -4 \ -3 | 4.0 \ 2.1 | (1.0f+2.0fi) \ (3.0f+2.0fi);
     55
     56        struct S { int i; };
     57        double ?*?( double d, S s ) { return d * s.i; }
     58        double ?/?( double d, S s ) { return d / s.i; }
     59        S ?\?( S s, unsigned long y ) { return (S){ s.i \ y }; }
     60        ofstream & ?|?( ofstream & os, S s ) { return os | s.i; }
     61        void ?|?( ofstream & os, S s ) { (ofstream &)(os | s); nl( os ); }
     62        S s = { 4 };
     63        S x = s \ 2;
     64        sout | x;
     65        sout | s.i | s \ 2u;
    5466} // main
    5567
  • tests/pybin/settings.py

    r69c37cc rf343c6b  
    1 from __future__ import print_function
    2 
    31import os
     2import subprocess
    43import sys
    5 import tools
     4from . import tools
    65
    76try :
     
    3938        def __init__(self, arch):
    4039                try:
    41                         canonical_host = Architecture.makeCanonical( config.HOSTARCH )
     40                        canonical_host = Architecture.make_canonical( config.HOSTARCH )
    4241                except KeyError:
    4342                        print("Unkown host architecture %s" % config.HOSTARCH, file=sys.stderr)
     
    4645                if arch:
    4746                        try:
    48                                 arch = Architecture.makeCanonical( arch )
     47                                arch = Architecture.make_canonical( arch )
    4948                        except KeyError:
    5049                                print("Unkown architecture %s" % arch, file=sys.stderr)
     
    7776
    7877        @classmethod
    79         def makeCanonical(_, arch):
     78        def make_canonical(_, arch):
    8079                return Architecture.KnownArchitectures[arch]
    8180
     
    8483        def __init__(self, value):
    8584                self.string = "debug" if value else "no debug"
    86                 self.flags  = """DEBUG_FLAGS="%s" """ % ("-debug -O0" if value else "-nodebug -O2")
     85                self.flags  = """DEBUG_FLAGS=%s""" % ("-debug -O0" if value else "-nodebug -O2")
    8786
    8887class Install:
    8988        def __init__(self, value):
    9089                self.string = "installed" if value else "in-tree"
    91                 self.flags  = """INSTALL_FLAGS="%s" """ % ("" if value else "-in-tree")
     90                self.flags  = """INSTALL_FLAGS=%s""" % ("" if value else "-in-tree")
    9291
    9392class Timeouts:
     
    112111        global install
    113112        global timeout
     113        global output_width
    114114
    115         dry_run    = options.dry_run
    116         generating = options.regenerate_expected
    117         make       = 'make'
    118         debug        = Debug(options.debug)
    119         install    = Install(options.install)
    120         arch       = Architecture(options.arch)
    121         timeout    = Timeouts(options.timeout, options.global_timeout)
     115        dry_run      = options.dry_run
     116        generating   = options.regenerate_expected
     117        make         = ['make']
     118        debug        = Debug(options.debug)
     119        install      = Install(options.install)
     120        arch         = Architecture(options.arch)
     121        timeout      = Timeouts(options.timeout, options.global_timeout)
     122        output_width = 24
    122123
    123124
    124 def updateMakeCmd(force, jobs):
     125def update_make_cmd(force, jobs):
    125126        global make
    126127
    127         make = "make" if not force else ("make -j%i" % jobs)
     128        make = ['make'] if not force else ['make', "-j%i" % jobs]
    128129
    129130def validate():
    130131        errf = os.path.join(BUILDDIR, ".validate.err")
    131         make_ret, _ = tools.make( ".validate", error_file = errf, redirects  = "2> /dev/null 1> /dev/null", )
     132        make_ret, out = tools.make( ".validate", error_file = errf, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
    132133        if make_ret != 0:
    133134                with open (errf, "r") as myfile:
     
    139140
    140141        tools.rm(errf)
     142
     143def prep_output(tests):
     144        global output_width
     145        output_width = max(map(lambda t: len(t.target()), tests))
  • tests/pybin/test_run.py

    r69c37cc rf343c6b  
    44
    55import pybin.settings
    6 import datetime
    7 
    8 from string import Template
    9 
    10 class DeltaTemplate(Template):
    11     delimiter = "%"
    12 
    13 def strfdelta(tdelta, fmt):
    14     d["H"], rem = divmod(tdelta.seconds, 3600)
    15     d["M"], d["S"] = divmod(rem, 60)
    16     t = DeltaTemplate(fmt)
    17     return t.substitute(**d)
    186
    197# Test class that defines what a test is
  • tests/pybin/tools.py

    r69c37cc rf343c6b  
    1 from __future__ import print_function
    2 
    31import __main__
    42import argparse
     3import contextlib
    54import fileinput
    65import multiprocessing
     
    109import signal
    1110import stat
     11import subprocess
    1212import sys
     13import tempfile
    1314import time
     15import types
    1416
    1517from pybin import settings
    16 from subprocess import Popen, PIPE, STDOUT
    1718
    1819################################################################################
     
    2122
    2223# helper functions to run terminal commands
    23 def sh(cmd, print2stdout = True, input = None):
    24         # add input redirection if needed
    25         if input and os.path.isfile(input):
    26                 cmd += " < %s" % input
     24def sh(*cmd, timeout = False, output = None, input = None, error = subprocess.STDOUT):
     25        cmd = list(cmd)
    2726
    2827        # if this is a dry_run, only print the commands that would be ran
    2928        if settings.dry_run :
    30                 print("cmd: %s" % cmd)
     29                cmd = "{} cmd: {}".format(os.getcwd(), ' '.join(cmd))
     30                if output and not isinstance(output, int):
     31                        cmd += " > "
     32                        cmd += output
     33
     34                if error and not isinstance(error, int):
     35                        cmd += " 2> "
     36                        cmd += error
     37
     38                if input and not isinstance(input, int) and os.path.isfile(input):
     39                        cmd += " < "
     40                        cmd += input
     41
     42                print(cmd)
    3143                return 0, None
    3244
    33         # otherwise create a pipe and run the desired command
    34         else :
    35                 proc = Popen(cmd, stdout=None if print2stdout else PIPE, stderr=STDOUT, shell=True)
    36                 out, err = proc.communicate()
    37                 return proc.returncode, out
     45        with contextlib.ExitStack() as onexit:
     46                # add input redirection if needed
     47                input = openfd(input, 'r', onexit, True)
     48
     49                # add output redirection if needed
     50                output = openfd(output, 'w', onexit, False)
     51
     52                # add error redirection if needed
     53                error = openfd(error, 'w', onexit, False)
     54
     55                # run the desired command
     56                try:
     57                        proc = subprocess.run(
     58                                cmd,
     59                                stdin =input,
     60                                stdout=output,
     61                                stderr=error,
     62                                timeout=settings.timeout.single if timeout else None
     63                        )
     64                        return proc.returncode, proc.stdout.decode("utf-8") if proc.stdout else None
     65                except subprocess.TimeoutExpired:
     66                        return 124, str(None)
    3867
    3968def is_ascii(fname):
     
    4574                return False
    4675
    47         code, out = sh("file %s" % fname, print2stdout = False)
     76        code, out = sh("file %s" % fname, output=subprocess.PIPE)
    4877        if code != 0:
    4978                return False
     
    5685        return match.group(1).startswith("ASCII text")
    5786
     87def is_exe(fname):
     88        return os.path.isfile(fname) and os.access(fname, os.X_OK)
     89
     90def openfd(file, mode, exitstack, checkfile):
     91        if not file:
     92                return file
     93
     94        if isinstance(file, int):
     95                return file
     96
     97        if checkfile and not os.path.isfile(file):
     98                return None
     99
     100        file = open(file, mode)
     101        exitstack.push(file)
     102        return file
     103
    58104# Remove 1 or more files silently
    59105def rm( files ):
    60         if isinstance( files, basestring ):
    61                 sh("rm -f %s > /dev/null 2>&1" % files )
    62         else:
    63                 for file in files:
    64                         sh("rm -f %s > /dev/null 2>&1" % file )
     106        if isinstance(files, str ): files = [ files ]
     107        for file in files:
     108                sh( 'rm', '-f', file, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
    65109
    66110# Create 1 or more directory
    67111def mkdir( files ):
    68         if isinstance( files, basestring ):
    69                 sh("mkdir -p %s" % os.path.dirname(files) )
    70         else:
    71                 for file in files:
    72                         sh("mkdir -p %s" % os.path.dirname(file) )
     112        if isinstance(files, str ): files = [ files ]
     113        for file in files:
     114                p = os.path.normpath( file )
     115                d = os.path.dirname ( p )
     116                sh( 'mkdir', '-p', d, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
    73117
    74118
     
    80124# diff two files
    81125def diff( lhs, rhs ):
    82         # diff the output of the files
    83         diff_cmd = ("diff --text "
    84 #                               "--ignore-all-space "
    85 #                               "--ignore-blank-lines "
    86                                 "--old-group-format='\t\tmissing lines :\n"
    87                                 "%%<' \\\n"
    88                                 "--new-group-format='\t\tnew lines :\n"
    89                                 "%%>' \\\n"
    90                                 "--unchanged-group-format='%%=' \\"
    91                                 "--changed-group-format='\t\texpected :\n"
    92                                 "%%<"
    93                                 "\t\tgot :\n"
    94                                 "%%>\n' \\\n"
    95                                 "--new-line-format='\t\t%%dn\t%%L' \\\n"
    96                                 "--old-line-format='\t\t%%dn\t%%L' \\\n"
    97                                 "--unchanged-line-format='' \\\n"
    98                                 "%s %s")
    99 
    100126        # fetch return code and error from the diff command
    101         return sh(diff_cmd % (lhs, rhs), False)
     127        return sh(
     128                '''diff''',
     129                '''--text''',
     130                '''--old-group-format=\t\tmissing lines :\n%<''',
     131                '''--new-line-format=\t\t%dn\t%L''',
     132                '''--new-group-format=\t\tnew lines : \n%>''',
     133                '''--old-line-format=\t\t%dn\t%L''',
     134                '''--unchanged-group-format=%=''',
     135                '''--changed-group-format=\t\texpected :\n%<\t\tgot :\n%>''',
     136                '''--unchanged-line-format=''',
     137                lhs,
     138                rhs,
     139                output=subprocess.PIPE
     140        )
    102141
    103142# call make
    104 def make(target, flags = '', redirects = '', error_file = None, silent = False):
    105         test_param = """test="%s" """ % (error_file) if error_file else ''
    106         cmd = ' '.join([
    107                 settings.make,
    108                 '-s' if silent else '',
     143def make(target, *, flags = '', output = None, error = None, error_file = None, silent = False):
     144        test_param = """test="%s" """ % (error_file) if error_file else None
     145        cmd = [
     146                *settings.make,
     147                '-s' if silent else None,
    109148                test_param,
    110149                settings.arch.flags,
     
    112151                settings.install.flags,
    113152                flags,
    114                 target,
    115                 redirects
    116         ])
    117         return sh(cmd)
     153                target
     154        ]
     155        cmd = [s for s in cmd if s]
     156        return sh(*cmd, output=output, error=error)
    118157
    119158def which(program):
    120     import os
    121     def is_exe(fpath):
    122         return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
    123 
    124159    fpath, fname = os.path.split(program)
    125160    if fpath:
     
    134169    return None
    135170
    136 def run(exe, output, input):
    137         ret, _ = sh("timeout %d %s > %s 2>&1" % (settings.timeout.single, exe, output), input = input)
    138         return ret
     171@contextlib.contextmanager
     172def tempdir():
     173        cwd = os.getcwd()
     174        with tempfile.TemporaryDirectory() as temp:
     175                os.chdir(temp)
     176                try:
     177                        yield temp
     178                finally:
     179                        os.chdir(cwd)
    139180
    140181################################################################################
     
    143184# move a file
    144185def mv(source, dest):
    145         ret, _ = sh("mv %s %s" % (source, dest))
     186        ret, _ = sh("mv", source, dest)
    146187        return ret
    147188
    148189# cat one file into the other
    149190def cat(source, dest):
    150         ret, _ = sh("cat %s > %s" % (source, dest))
     191        ret, _ = sh("cat", source, output=dest)
    151192        return ret
    152193
     
    163204
    164205# helper function to check if a files contains only a specific string
    165 def fileContainsOnly(file, text) :
     206def file_contains_only(file, text) :
    166207        with open(file) as f:
    167208                ff = f.read().strip()
    168209                result = ff == text.strip()
    169210
    170                 return result;
    171 
    172 # check whether or not a file is executable
    173 def fileIsExecutable(file) :
    174         try :
    175                 fileinfo = os.stat(file)
    176                 return bool(fileinfo.st_mode & stat.S_IXUSR)
    177         except Exception as inst:
    178                 print(type(inst))    # the exception instance
    179                 print(inst.args)     # arguments stored in .args
    180                 print(inst)
    181                 return False
     211                return result
    182212
    183213# transform path to canonical form
    184 def canonicalPath(path):
     214def canonical_path(path):
    185215        abspath = os.path.abspath(__main__.__file__)
    186216        dname = os.path.dirname(abspath)
     
    188218
    189219# compare path even if form is different
    190 def pathCmp(lhs, rhs):
    191         return canonicalPath( lhs ) == canonicalPath( rhs )
     220def path_cmp(lhs, rhs):
     221        return canonical_path( lhs ) == canonical_path( rhs )
    192222
    193223# walk all files in a path
    194 def pathWalk( op ):
    195         def step(_, dirname, names):
     224def path_walk( op ):
     225        dname = settings.SRCDIR
     226        for dirname, _, names in os.walk(dname):
    196227                for name in names:
    197228                        path = os.path.join(dirname, name)
    198229                        op( path )
    199230
    200         # Start the walk
    201         dname = settings.SRCDIR
    202         os.path.walk(dname, step, '')
    203 
    204231################################################################################
    205232#               system
    206233################################################################################
    207234# count number of jobs to create
    208 def jobCount( options, tests ):
     235def job_count( options, tests ):
    209236        # check if the user already passed in a number of jobs for multi-threading
    210237        if not options.jobs:
     
    228255        return min( options.jobs, len(tests) ), force
    229256
    230 # setup a proper processor pool with correct signal handling
    231 def setupPool(jobs):
    232         original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
    233         pool = multiprocessing.Pool(jobs)
    234         signal.signal(signal.SIGINT, original_sigint_handler)
    235 
    236         return pool
    237 
    238 # handle signals in scope
    239 class SignalHandling():
    240         def __enter__(self):
    241                 # enable signal handling
    242                 signal.signal(signal.SIGINT, signal.SIG_DFL)
    243 
    244         def __exit__(self, type, value, traceback):
    245                 # disable signal handling
    246                 signal.signal(signal.SIGINT, signal.SIG_IGN)
    247 
    248 
    249257# enable core dumps for all the test children
    250258resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))
     
    261269                return False
    262270        raise argparse.ArgumentTypeError(msg)
    263         return False
    264271
    265272def fancy_print(text):
    266273        column = which('column')
    267274        if column:
    268                 cmd = "%s 2> /dev/null" % column
    269                 proc = Popen(cmd, stdin=PIPE, stderr=None, shell=True)
    270                 proc.communicate(input=text + "\n")
     275                subprocess.run(column, input=bytes(text + "\n", "UTF-8"))
    271276        else:
    272277                print(text)
    273278
    274279
    275 def coreInfo(path):
     280def core_info(path):
     281        if not os.path.isfile(path):
     282                return 1, "ERR Executable path is wrong"
     283
    276284        cmd   = os.path.join(settings.SRCDIR, "pybin/print-core.gdb")
    277285        if not os.path.isfile(cmd):
    278286                return 1, "ERR Printing format for core dumps not found"
    279287
    280         dname = os.path.dirname(path)
    281         core  = os.path.join(dname, "core" )
    282         if not os.path.isfile(path):
    283                 return 1, "ERR Executable path is wrong"
     288        core  = os.path.join(os.getcwd(), "core" )
    284289
    285290        if not os.path.isfile(core):
    286291                return 1, "ERR No core dump"
    287292
    288         return sh("gdb -n %s %s -batch -x %s" % (path, core, cmd), print2stdout=False)
     293        return sh('gdb', '-n', path, core, '-batch', '-x', cmd, output=subprocess.PIPE)
    289294
    290295class Timed:
  • tests/raii/init_once.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Tue Jun 14 15:43:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul  9 11:30:29 2016
    13 // Update Count     : 3
     12// Last Modified On : Fri Mar 22 13:41:26 2019
     13// Update Count     : 4
    1414//
    1515
     
    192192// Local Variables: //
    193193// tab-width: 4 //
    194 // compile-command: "cfa init_once.c" //
     194// compile-command: "cfa init_once.cfa" //
    195195// End: //
  • tests/rational.cfa

    r69c37cc rf343c6b  
    1010// Created On       : Mon Mar 28 08:43:12 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec  4 21:46:42 2018
    13 // Update Count     : 69
     12// Last Modified On : Wed Mar 27 07:37:17 2019
     13// Update Count     : 80
    1414//
    1515
     
    1919#include <fstream.hfa>
    2020
    21 // UNNECESSARY, FIX ME
    22 void ?{}( int & this ) { this = 0; }
    23 void ?{}( int & this, zero_t ) { this = 0; }
    24 void ?{}( int & this, one_t ) { this = 1; }
    2521double convert( int i ) { return (double)i; }
    2622int convert( double d ) { return (int)d; }
     
    5854        sout | a * b;
    5955        sout | a / b;
     56//      sout | a \ 2 | b \ 2; // FIX ME
     57//      sout | a \ -2 | b \ -2;
    6058
    6159        sout | "conversion";
  • tests/test.py

    r69c37cc rf343c6b  
    1 #!/usr/bin/python
    2 from __future__ import print_function
     1#!/usr/bin/python3
    32
    43from pybin.tools import *
     
    98import re
    109import sys
     10import tempfile
    1111import time
    1212
     
    1515################################################################################
    1616
    17 def findTests():
     17def find_tests():
    1818        expected = []
    1919
    20         def matchTest(path):
     20        def match_test(path):
    2121                match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path)
    2222                if match :
     
    2828                                expected.append(test)
    2929
    30         pathWalk( matchTest )
     30        path_walk( match_test )
    3131
    3232        return expected
    3333
    3434# reads the directory ./.expect and indentifies the tests
    35 def listTests( includes, excludes ):
     35def list_tests( includes, excludes ):
    3636        # tests directly in the .expect folder will always be processed
    37         test_list = findTests()
     37        test_list = find_tests()
    3838
    3939        # if we have a limited number of includes, filter by them
     
    5252
    5353# from the found tests, filter all the valid tests/desired tests
    54 def validTests( options ):
     54def valid_tests( options ):
    5555        tests = []
    5656
     
    5959        if options.regenerate_expected :
    6060                for testname in options.tests :
    61                         testname = canonicalPath( testname )
     61                        testname = canonical_path( testname )
    6262                        if Test.valid_name(testname):
    63                                 found = [test for test in allTests if canonicalPath( test.target() ) == testname]
     63                                found = [test for test in all_tests if canonical_path( test.target() ) == testname]
    6464                                tests.append( found[0] if len(found) == 1 else Test.from_target(testname) )
    6565                        else :
     
    6969                # otherwise we only need to validate that all tests are present in the complete list
    7070                for testname in options.tests:
    71                         test = [t for t in allTests if pathCmp( t.target(), testname )]
     71                        test = [t for t in all_tests if path_cmp( t.target(), testname )]
    7272
    7373                        if test :
     
    7979
    8080# parses the option
    81 def getOptions():
     81def parse_args():
    8282        # create a parser with the arguments for the tests script
    8383        parser = argparse.ArgumentParser(description='Script which runs cforall tests')
     
    102102                print('ERROR: invalid arguments', file=sys.stderr)
    103103                parser.print_help(sys.stderr)
    104                 sys.exit(1)
     104                sys.exit(1)
    105105
    106106        # script must have at least some tests to run or be listing
     
    112112        # check that exactly one of the booleans is set to true
    113113        if not sum( (listing, all_tests, some_tests, some_dirs) ) > 0 :
    114                 print('ERROR: must have option \'--all\', \'--list\', \'--include\', \'-I\' or non-empty test list', file=sys.stderr)
     114                print('''ERROR: must have option '--all', '--list', '--include', '-I' or non-empty test list''', file=sys.stderr)
    115115                parser.print_help()
    116116                sys.exit(1)
     
    124124        return val == 0 or settings.dry_run
    125125
    126 def isExe(file):
    127         return settings.dry_run or fileIsExecutable(file)
    128 
    129 def noRule(file, target):
    130         return not settings.dry_run and fileContainsOnly(file, "make: *** No rule to make target `%s'.  Stop." % target)
     126def no_rule(file, target):
     127        return not settings.dry_run and file_contains_only(file, "make: *** No rule to make target `%s'.  Stop." % target)
    131128
    132129# logic to run a single test and return the result (No handling of printing or other test framework logic)
     
    145142        # build, skipping to next test on error
    146143        with Timed() as comp_dur:
    147                 make_ret, _ = make( test.target(),      redirects  = ("2> %s 1> /dev/null" % out_file), error_file = err_file )
    148 
    149         # if the make command succeds continue otherwise skip to diff
     144                make_ret, _ = make( test.target(), output=subprocess.DEVNULL, error=out_file, error_file = err_file )
     145
    150146        run_dur = None
    151         if success(make_ret):
    152                 with Timed() as run_dur:
    153                         if isExe(exe_file):
    154                                 # run test
    155                                 retcode = run(exe_file, out_file, in_file)
     147        # run everything in a temp directory to make sure core file are handled properly
     148        with tempdir():
     149                # if the make command succeds continue otherwise skip to diff
     150                if success(make_ret):
     151                        with Timed() as run_dur:
     152                                if settings.dry_run or is_exe(exe_file):
     153                                        # run test
     154                                        retcode, _ = sh(exe_file, output=out_file, input=in_file, timeout=True)
     155                                else :
     156                                        # simply cat the result into the output
     157                                        retcode = cat(exe_file, out_file)
     158                else:
     159                        retcode = mv(err_file, out_file)
     160
     161                if success(retcode):
     162                        if settings.generating :
     163                                # if we are ounly generating the output we still need to check that the test actually exists
     164                                if no_rule(out_file, test.target()) :
     165                                        retcode = 1
     166                                        error = "\t\tNo make target for test %s!" % test.target()
     167                                        rm(out_file)
     168                                else:
     169                                        error = None
    156170                        else :
    157                                 # simply cat the result into the output
    158                                 retcode = cat(exe_file, out_file)
    159         else:
    160                 retcode = mv(err_file, out_file)
    161 
    162         if success(retcode):
    163                 if settings.generating :
    164                         # if we are ounly generating the output we still need to check that the test actually exists
    165                         if noRule(out_file, test.target()) :
    166                                 retcode = 1
    167                                 error = "\t\tNo make target for test %s!" % test.target()
    168                                 rm(out_file)
    169                         else:
    170                                 error = None
    171                 else :
    172                         # fetch return code and error from the diff command
    173                         retcode, error = diff(cmp_file, out_file)
    174 
    175         else:
    176                 with open (out_file, "r") as myfile:
    177                         error = myfile.read()
    178 
    179                 ret, info = coreInfo(exe_file)
    180                 error = error + info
     171                                # fetch return code and error from the diff command
     172                                retcode, error = diff(cmp_file, out_file)
     173
     174                else:
     175                        with open (out_file, "r") as myfile:
     176                                error = myfile.read()
     177
     178                        ret, info = core_info(exe_file)
     179                        error = error + info if error else info
    181180
    182181
     
    189188# run a single test and handle the errors, outputs, printing, exception handling, etc.
    190189def run_test_worker(t) :
    191 
    192         with SignalHandling():
     190        try :
    193191                # print formated name
    194                 name_txt = "%24s  " % t.name
     192                name_txt = '{0:{width}}  '.format(t.target(), width=settings.output_width)
    195193
    196194                retcode, error, duration = run_single_test(t)
     
    200198
    201199                #print result with error if needed
    202                 text = name_txt + result_txt
     200                text = '\t' + name_txt + result_txt
    203201                out = sys.stdout
    204202                if error :
    205                         text = text + "\n" + error
     203                        text = text + '\n' + error
    206204                        out = sys.stderr
    207205
     
    210208                sys.stderr.flush()
    211209
    212         return retcode != TestResult.SUCCESS
     210                return retcode != TestResult.SUCCESS
     211        except KeyboardInterrupt:
     212                False
    213213
    214214# run the given list of tests with the given parameters
    215215def run_tests(tests, jobs) :
    216216        # clean the sandbox from previous commands
    217         make('clean', redirects = '> /dev/null 2>&1')
     217        make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL)
    218218
    219219        # create the executor for our jobs and handle the signal properly
    220         pool = setupPool(jobs)
     220        pool = multiprocessing.Pool(jobs)
    221221
    222222        # for each test to run
     
    233233
    234234        # clean the workspace
    235         make('clean', redirects = '> /dev/null 2>&1')
     235        make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL)
    236236
    237237        for failed in results:
     
    248248
    249249        # parse the command line arguments
    250         options = getOptions()
     250        options = parse_args()
    251251
    252252        # init global settings
     
    254254
    255255        # fetch the liest of all valid tests
    256         allTests = listTests( options.include, options.exclude )
     256        all_tests = list_tests( options.include, options.exclude )
    257257
    258258
    259259        # if user wants all tests than no other treatement of the test list is required
    260260        if options.all or options.list or options.list_comp or options.include :
    261                 tests = allTests
     261                tests = all_tests
    262262
    263263        #otherwise we need to validate that the test list that was entered is valid
    264264        else :
    265                 tests = validTests( options )
     265                tests = valid_tests( options )
    266266
    267267        # make sure we have at least some test to run
     
    281281        elif options.list :
    282282                print("Listing for %s:%s"% (settings.arch.string, settings.debug.string))
    283                 fancy_print("\n".join(map(lambda t: "%s" % (t.toString()), tests)))
     283                fancy_print("\n".join(map(lambda t: t.toString(), tests)))
    284284
    285285        else :
    286286                # check the build configuration works
     287                settings.prep_output(tests)
    287288                settings.validate()
    288289
    289                 options.jobs, forceJobs = jobCount( options, tests )
    290                 settings.updateMakeCmd(forceJobs, options.jobs)
    291 
    292                 print('%s (%s:%s) on %i cores' % (
    293                         'Regenerate tests' if settings.generating else 'Running',
     290                options.jobs, forceJobs = job_count( options, tests )
     291                settings.update_make_cmd(forceJobs, options.jobs)
     292
     293                print('%s %i tests on %i cores (%s:%s)' % (
     294                        'Regenerating' if settings.generating else 'Running',
     295                        len(tests),
     296                        options.jobs,
    294297                        settings.arch.string,
    295                         settings.debug.string,
    296                         options.jobs
     298                        settings.debug.string
    297299                ))
    298300
Note: See TracChangeset for help on using the changeset viewer.