Changes in / [f343c6b:69c37cc]


Ignore:
Files:
14 added
49 deleted
92 edited

Legend:

Unmodified
Added
Removed
  • benchmark/Makefile.am

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

    rf343c6b r69c37cc  
    371371
    372372# applies to both programs
    373 AM_CFLAGS = -O2 -Wall -Wextra -Werror -I$(srcdir) -lrt -pthread
    374 AM_CFAFLAGS = -quiet -nodebug -in-tree
    375 AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14
     373AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread
     374AM_CFAFLAGS = -quiet -in-tree -nodebug
     375AM_UPPFLAGS = -quiet -nodebug -multi
    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         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)
     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)
    409409testdir = $(top_srcdir)/tests
    410410all: all-am
     
    799799        $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/fetch_add.c
    800800
    801 tls-fetch_add$(EXEEXT):
    802         $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000  $(srcdir)/tls-fetch_add.c
    803 
    804801@WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre$(EXEEXT):
    805802@WITH_LIBFIBRE_TRUE@    $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp  -I$(LIBFIBRE_DIR) -lfibre
  • configure

    rf343c6b r69c37cc  
    1673816738
    1673916739#==============================================================================
    16740 ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile longrun_tests/Makefile tools/Makefile tools/prettyprinter/Makefile"
     16740ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile tests/preempt_longrun/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     "longrun_tests/Makefile") CONFIG_FILES="$CONFIG_FILES longrun_tests/Makefile" ;;
     17878    "tests/preempt_longrun/Makefile") CONFIG_FILES="$CONFIG_FILES tests/preempt_longrun/Makefile" ;;
    1787917879    "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
    1788017880    "tools/prettyprinter/Makefile") CONFIG_FILES="$CONFIG_FILES tools/prettyprinter/Makefile" ;;
  • configure.ac

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

    rf343c6b r69c37cc  
    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 
    23652349@article{design,
    23662350    keywords    = {Smalltalk, designing classes},
     
    23702354    journal     = joop,
    23712355    year        = 1988,
    2372     volume      = 1,
    2373     number      = 2,
    2374     pages       = {22-35},
     2356    volume      = 1, number = 2, pages = {22-35},
    23752357    comment     = {
    23762358        Abstract classes represent standard protocols.  ``It is better to
     
    38073789    optaddress  = {Waterloo, Ontario, Canada, N2L 3G1},
    38083790    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},
    38213791}
    38223792
  • doc/papers/concurrency/Paper.tex

    rf343c6b r69c37cc  
    215215{}
    216216\lstnewenvironment{Go}[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}}
     217{\lstset{#1}}
    221218{}
    222219
     
    231228}
    232229
    233 \title{\texorpdfstring{Advanced Control-flow and Concurrency in \protect\CFA}{Advanced Control-flow in Cforall}}
     230\title{\texorpdfstring{Advanced Control-flow in \protect\CFA}{Advanced Control-flow in Cforall}}
    234231
    235232\author[1]{Thierry Delisle}
     
    245242\abstract[Summary]{
    246243\CFA is a modern, polymorphic, non-object-oriented, backwards-compatible extension of the C programming language.
    247 This paper discusses some advanced control-flow and concurrency/parallelism features in \CFA, along with the supporting runtime.
    248 These 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.
    250 A 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.
    251 These features also integrate with the \CFA polymorphic type-system and exception handling, while respecting the expectations and style of C programmers.
     244This paper discusses the advanced control-flow features in \CFA, which include concurrency and parallelism, and its supporting runtime system.
     245These 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.
     247A 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.
     248All features respect the expectations of C programmers, while being fully integrate with the \CFA polymorphic type-system and other language features.
    252249Experimental results show comparable performance of the new features with similar mechanisms in other concurrent programming-languages.
    253250}%
     
    264261\section{Introduction}
    265262
    266 This paper discusses the design of language-level control-flow and concurrency/parallelism extensions in \CFA and its runtime.
     263This paper discusses the design of advanced, high-level control-flow extensions (especially concurrency and parallelism) in \CFA and its runtime.
    267264\CFA is a modern, polymorphic, non-object-oriented\footnote{
    268265\CFA has features often associated with object-oriented programming languages, such as constructors, destructors, virtuals and simple inheritance.
    269266However, 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.},
    270267backwards-compatible extension of the C programming language~\cite{Moss18}.
    271 Within the \CFA framework, new control-flow features are created from scratch.
    272 ISO \Celeven defines only a subset of the \CFA extensions, where the overlapping features are concurrency~\cite[\S~7.26]{C11}.
    273 However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}.
    274 Furthermore, \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;
    275 no high-level language concurrency features are defined.
    276 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 C11 concurrency approach.
    277 Finally, 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}.
     268Within the \CFA framework, new control-flow features were created from scratch.
     269ISO \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}.
     270Furthermore, \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;
     271no high-level language concurrency features exist.
     272Interestingly, 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.
     273Finally, 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}.
    278274
    279275In contrast, there has been a renewed interest during the past decade in user-level (M:N, green) threading in old and new programming languages.
     
    288284
    289285A 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.
    290 This 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}.
     286This 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}.
    291287The consequence is that a language must be cognizant of these features and provide sufficient tools to program around any safety issues.
    292288For example, C created the @volatile@ qualifier to provide correct execution for @setjmp@/@logjmp@ (concurrency came later).
    293 The 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}.
     289The 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}.
    294290
    295291While 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.
    296292Essentially, using low-level explicit locks is the concurrent equivalent of assembler programming.
    297 Just as most assembler programming is replaced with high-level programming, explicit locks can be replaced with high-level concurrency in a programming language.
    298 Then the goal is for the compiler to check for correct usage and follow any complex coding conventions implicitly.
     293Just 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.
     294The goal is to get the compiler to check for correct usage and follow any complex coding conventions implicitly.
    299295The drawback is that language constructs may preclude certain specialized techniques, therefore introducing inefficiency or inhibiting concurrency.
    300296For 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.
     
    303299As stated, this observation applies to non-concurrent forms of complex control-flow, like exception handling and coroutines.
    304300
    305 Adapting 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.
     301Adapting the programming language allows matching the control-flow model with the programming-language style, versus adapting to one general (sound) library/paradigm.
    306302For 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++}.
    307303It 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.
     
    311307however, 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.}
    312308Finally, 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.
    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.
    315 The 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 
    318 Most 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.
    319 As a result, there is a significant learning curve to move to these languages, and C legacy-code must be rewritten.
    320 While \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.
    321 Hence, 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 
    324 We 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.
    325 The detailed contributions of this work are:
     309
     310\CFA embraces language extensions and user-level threading to provide advanced control-flow and concurrency.
     311We attempt to show the \CFA extensions and runtime are demonstrably better than those proposed for \CC and other concurrent, imperative programming languages.
     312The contributions of this work are:
    326313\begin{itemize}
    327314\item
     
    628615
    629616
    630 \section{Coroutines: Stepping Stone}
    631 \label{coroutine}
    632 
     617\section{Coroutines: A Stepping Stone}\label{coroutine}
     618
     619Advanced 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).
    633620Coroutines are generalized routines allowing execution to be temporarily suspended and later resumed.
    634621Hence, 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.
     
    654641\centering
    655642\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}
    676643\begin{lrbox}{\myboxA}
    677644\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    678 #define FIB_INIT { 0, 1 }
    679 typedef struct { int fn1, fn; } Fib;
     645`int f1, f2, state = 1;`   // single global variables
     646int 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}
     655int main() {
     656
     657        for ( int i = 0; i < 10; i += 1 ) {
     658                printf( "%d\n", fib() );
     659        }
     660}
     661\end{cfa}
     662\end{lrbox}
     663
     664\newbox\myboxB
     665\begin{lrbox}{\myboxB}
     666\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     667#define FIB_INIT `{ 0, 1 }`
     668typedef struct { int f2, f1; } Fib;
    680669int fib( Fib * f ) {
    681670
    682         int ret = f->fn1;
    683         f->fn1 = f->fn;
    684         f->fn = ret + f->fn;
     671        int ret = f->f2;
     672        int fn = f->f1 + f->f2;
     673        f->f2 = f->f1; f->f1 = fn;
     674
    685675        return ret;
    686676}
    687 
    688 
    689 
    690677int main() {
    691678        Fib f1 = FIB_INIT, f2 = FIB_INIT;
    692679        for ( int i = 0; i < 10; i += 1 ) {
    693                 printf( "%d %d\n",
    694                                 fib( &f1 ), fib( &f2 ) );
     680                printf( "%d %d\n", fib( &f1 ), fib( &f2 ) );
    695681        }
    696682}
     
    698684\end{lrbox}
    699685
     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; };
     698void 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}
     706int next( Fib & fib ) with( fib ) {
     707        `resume( fib );`
     708        return fn;
     709}
     710int main() {
     711        Fib f1, f2;
     712        for ( int i = 1; i <= 10; i += 1 ) {
     713                sout | next( f1 ) | next( f2 );
     714        }
     715}
     716\end{cfa}
     717\end{lrbox}
    700718\newbox\myboxB
    701719\begin{lrbox}{\myboxB}
    702720\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    703 `coroutine` Fib { int fn1; };
    704 void main( Fib & fib ) with( fib ) {
    705         int fn;
    706         [fn1, fn] = [0, 1];
    707         for () {
    708                 `suspend();`
    709                 [fn1, fn] = [fn, fn1 + fn];
     721`coroutine` Fib { int ret; };
     722void 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();`
    710728        }
    711729}
    712 int ?()( Fib & fib ) with( fib ) {
    713         `resume( fib );`  return fn1;
    714 }
    715 int main() {
    716         Fib f1, f2;
    717         for ( 10 ) {
    718                 sout | f1() | f2();
    719 }
     730int next( Fib & fib ) with( fib ) {
     731        `resume( fib );`
     732        return ret;
     733}
     734
     735
     736
     737
    720738
    721739
    722740\end{cfa}
    723741\end{lrbox}
    724 
    725 \newbox\myboxC
    726 \begin{lrbox}{\myboxC}
    727 \begin{python}[aboveskip=0pt,belowskip=0pt]
    728 
    729 def 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 
    740 f1 = Fib()
    741 f2 = Fib()
    742 for i in range( 10 ):
    743         print( next( f1 ), next( f2 ) )
    744 
    745 
    746 
    747 \end{python}
    748 \end{lrbox}
    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}
     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}
    805747\end{figure}
    806748
     
    842784\begin{lrbox}{\myboxA}
    843785\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    844 `coroutine` Fmt {
    845         char ch;   // communication variables
    846         int g, b;   // needed in destructor
     786`coroutine` Format {
     787        char ch;   // used for communication
     788        int g, b;  // global because used in destructor
    847789};
    848 void 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
     790void 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
    852794                                `suspend();`
    853                                 sout | ch; } // print character
    854                         sout | "  "; } // block separator
    855                 sout | nl; }  // group separator
    856 }
    857 void ?{}( Fmt & fmt ) { `resume( fmt );` } // prime
    858 void ^?{}( Fmt & fmt ) with( fmt ) { // destructor
    859         if ( g != 0 || b != 0 ) // special case
    860                 sout | nl; }
    861 void send( Fmt & fmt, char c ) { fmt.ch = c; `resume( fmt )`; }
     795                                sout | ch;              // separator
     796                        }
     797                        sout | "  ";               // separator
     798                }
     799                sout | nl;
     800        }
     801}
     802void ?{}( Format & fmt ) { `resume( fmt );` }
     803void ^?{}( Format & fmt ) with( fmt ) {
     804        if ( g != 0 || b != 0 ) sout | nl;
     805}
     806void format( Format & fmt ) {
     807        `resume( fmt );`
     808}
    862809int main() {
    863         Fmt fmt;
    864         sout | nlOff;   // turn off auto newline
    865         for ( 41 )
    866                 send( fmt, 'a' );
     810        Format fmt;
     811        eof: for ( ;; ) {
     812                sin | fmt.ch;
     813          if ( eof( sin ) ) break eof;
     814                format( fmt );
     815        }
    867816}
    868817\end{cfa}
     
    871820\newbox\myboxB
    872821\begin{lrbox}{\myboxB}
    873 \begin{python}[aboveskip=0pt,belowskip=0pt]
    874 
    875 
    876 
    877 def 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 
    893 fmt = Fmt()
    894 `next( fmt )`                    # prime
    895 for i in range( 41 ):
    896         `fmt.send( 'a' );`      # send to yield
    897 
    898 \end{python}
     822\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     823struct Format {
     824        char ch;
     825        int g, b;
     826};
     827void 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}
     844int 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}
    899855\end{lrbox}
    900 \subfloat[\CFA]{\label{f:CFAFmt}\usebox\myboxA}
     856\subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA}
    901857\qquad
    902 \subfloat[Python]{\label{f:CFmt}\usebox\myboxB}
    903 \caption{Output formatting text}
     858\subfloat[C Linearized]{\label{f:CFmt}\usebox\myboxB}
     859\caption{Formatting text into lines of 5 blocks of 4 characters.}
    904860\label{f:fmt-line}
    905861\end{figure}
     
    922878void main( Prod & prod ) with( prod ) {
    923879        // 1st resume starts here
    924         for ( i; N ) {
     880        for ( int i = 0; i < N; i += 1 ) {
    925881                int p1 = random( 100 ), p2 = random( 100 );
    926882                sout | p1 | " " | p2;
     
    938894}
    939895void start( Prod & prod, int N, Cons &c ) {
    940         &prod.c = &c; // reassignable reference
     896        &prod.c = &c;
    941897        prod.[N, receipt] = [N, 0];
    942898        `resume( prod );`
     
    953909        Prod & p;
    954910        int p1, p2, status;
    955         bool done;
     911        _Bool done;
    956912};
    957913void ?{}( Cons & cons, Prod & p ) {
    958         &cons.p = &p; // reassignable reference
     914        &cons.p = &p;
    959915        cons.[status, done ] = [0, false];
    960916}
     
    1013969The program main restarts after the resume in @start@.
    1014970@start@ returns and the program main terminates.
    1015 
    1016 One \emph{killer} application for a coroutine is device drivers, which at one time caused 70\%-85\% of failures in Windows/Linux~\cite{Swift05}.
    1017 Many 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}
    1022 where a network message begins with the control character STX and ends with an ETX, followed by a 2-byte cyclic-redundancy check.
    1023 Control characters may appear in a message if preceded by an ESC.
    1024 Because 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}
    1028 enum Status { CONT, MSG, ESTX, ELNTH, ECRC };
    1029 `coroutine` Driver {
    1030         Status status;
    1031         char * msg, byte;
    1032 };
    1033 void ?{}( Driver & d, char * m ) { d.msg = m; }         $\C[3.0in]{// constructor}$
    1034 Status next( Driver & d, char b ) with( d ) {           $\C{// 'with' opens scope}$
    1035         byte = b; `resume( d );` return status;
    1036 }
    1037 void 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}
    1070971
    1071972
  • doc/proposals/vtable.md

    rf343c6b r69c37cc  
    1010other languages. They will mostly contain function pointers although they
    1111should be able to store anything that goes into a trait.
    12 
    13 I also include notes on a sample implementation, which primarly exists to show
    14 there is a resonable implementation. The code samples for that are in a slight
    15 psudo-code to help avoid name mangling and keeps some CFA features while they
    16 would actually be writen in C.
    1712
    1813Trait Instances
     
    4742before.
    4843
    49 For traits to be used this way they should meet two requirements. First they
    50 should only have a single polymorphic type and each assertion should use that
    51 type once as a parameter. Extentions may later loosen these requirements.
     44Internally a trait object is a pair of pointers. One to an underlying object
     45and the other to the vtable. All calls on an trait are implemented by looking
     46up the matching function pointer and passing the underlying object and the
     47remaining arguments to it.
    5248
    53 If a trait object is used it should generate a series of implicate functions
    54 each of which implements one of the functions required by the trait. So for
    55 combiner there is an implicate:
    56 
    57     void combine(trait combiner & this, int);
    58 
    59 This function is the one actually called at the end
    60 
    61 The main use case for trait objects is that they can be stored. They can be
    62 passed 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 
    80 Currently these traits are limited to 1 trait parameter and functions should
    81 have exactly 1 parameter. We cannot abstract away pairs of types and still
    82 pass them into normal functions, which take them seperately.
    83 
    84 The second is required the because we need to get the vtable from somewhere.
    85 If there are 0 trait objects than no vtable is avalible, if we have more than
    86 1 than the vtables give conflicting answers on what underlying function to
    87 call. And even then the underlying type assumes a concrete type.
    88 
    89 This loop can sort of be broken by using the trait object directly in the
    90 signature. 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
    97 A simple way to implement trait objects is by a pair of pointers. One to the
    98 underlying 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 
    110 The functions that run on the trait object would generally be generated using
    111 the following pattern:
    112 
    113     void draw(Surface & surface, drawable & traitObj) {
    114         return traitObj.vtable->draw(surface, traitObj.object);
    115     }
    116 
    117 There may have to be special cases for things like copy construction, that
    118 might require a more sigificant wrapper. On the other hand moving could be
    119 implemented by moving the pointers without any need to refer to the base
    120 object.
    121 
    122 ### Extention: Multiple Trait Parameters
    123 Currently, this gives traits two independent uses. They use the same syntax,
    124 except for limits boxable traits have, and yet don't really mix. The most
    125 natural way to do this is to allow trait instances to pick one parameter
    126 that they are generic over, the others they choose types to implement.
    127 
    128 The two ways to do the selection, the first is do it at the trait definition.
    129 Each trait picks out a single parameter which it can box (here the `virtual`
    130 qualifier). When you create an instance of a trait object you provide
    131 arguments 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 
    139 The second is to do it at the instaniation point. A placeholder (here the
    140 keyword `virtual`) is used to explicately skip over the parameter that will be
    141 abstracted 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 
    149 Using both (first to set the default, second as a local override) would also
    150 work, although might be exessively complicated.
    151 
    152 This is useful in cases where you want to use a generic type, but leave part
    153 of 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 
    160 Which allows you to fold values without putting them in a container. If they
    161 are already in a container this is exessive, but if they are generated over
    162 time this gives you a simple interface. This could for instance be used in
    163 a profile, where T changes for each profiling statistic and you can plug in
    164 multiple profilers for any run by adding them to an array.
     49Trait objects can be moved by moving the pointers. Almost all other operations
     50require some functions to be implemented on the underlying type. Depending on
     51what is in the virtual table a trait type could be a dtype or otype.
    16552
    16653Hierarchy
     
    20390the pointer to it.
    20491
    205 Exception 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 
    228 Ast 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
    270 The type id may be as little as:
    271 
    272     struct typeid {
    273         struct typeid const * const parent;
    274     };
    275 
    276 Some linker magic would have to be used to ensure exactly one copy of each
    277 structure for each type exists in memory. There seem to be spectial once
    278 sections that support this and it should be easier than generating unique
    279 ids across compilation units.
    280 
    281 The structure could be extended to contain any additional type information.
    282 
    283 There are two general designs for vtables with type ids. The first is to put
    284 the type id at the top of the vtable, this is the most compact and efficient
    285 solution but only works if we have exactly 1 vtable for each type. The second
    286 is to put a pointer to the type id in each vtable. This has more overhead but
    287 allows 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
    302 To convert from a pointer to a type higher on the hierarchy to one lower on
    303 the hierarchy a check is used to make sure that the underlying type is also
    304 of that lower type.
    305 
    306 The proposed syntax for this is:
    307 
    308     trait SubType * new_value = (virtual trait SubType *)super_type;
    309 
    310 It will return the same pointer if it does point to the subtype and null if
    311 it does not, doing the check and conversion in one operation.
    312 
    31392### Inline vtables
    31493Since the structures here are usually made to be turned into trait objects
    31594it might be worth it to have fields on them to store the virtual table
    316 pointer. 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
    318 pointer.
     95pointer. This would have to be declared on the trait as an assertion, but if
     96it is the trait object could be a single pointer.
    31997
    320 There are also three options for where the pointer to the vtable. It could be
    321 anywhere, a fixed location for each trait or always at the front. For the per-
    322 trait solution an extention to specify what it is (example `vtable[0];`) which
    323 could also be used to combine it with others. So these options can be combined
    324 to allow access to all three options.
     98It is trivial to do if the field with the virtual table pointer is fixed.
     99Otherwise some trickery with pointing to the field and storing the offset in
     100the virtual table to recover the main object would have to be used.
    325101
    326102### Virtual Tables as Types
    327 Here we consider encoding plus the implementation of functions on it to be a
    328 type. Which is to say in the type hierarchy structures aren't concrete types
    329 anymore, instead they are parent types to vtables, which combine the encoding
    330 and implementation.
     103Here we consider encoding plus the implementation of functions on it. Which
     104is to say in the type hierarchy structures aren't concrete types anymore,
     105instead they are parent types to vtables, which combine the encoding and
     106implementation.
    331107
    332108Resolution Scope
     
    347123other.
    348124
    349 Some syntax would have to be added to specify the resolution point. To ensure
    350 a single instance there may have to be two variants, one forward declaration
    351 and one to create the instance. With some compiler magic the forward
    352 declaration maybe enough.
    353 
    354     extern trait combiner(struct summation) vtable;
    355     trait combiner(struct summation) vtable;
    356 
    357 Or (with the same variants):
    358 
    359     vtable combiner(struct summation);
    360 
    361 The extern variant promises that the vtable will exist while the normal one
    362 is where the resolution actually happens.
     125Some syntax would have to be added. All resolutions can be found at compile
     126time and a single vtable created for each type at compilation time.
    363127
    364128### Explicit Resolution Points:
     
    376140However this also means that stack-allocated functions can end up in the
    377141vtable.
    378 
    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 
    385 The extern difference is the same before. The name (sum in the samples) is
    386 used at the binding site to say which one is picked. The default keyword can
    387 be 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.)
    393 The object being bound is required. The name of the vtable is optional if
    394 there is exactly one vtable name marked with default.
    395 
    396 These could also be placed inside functions. In which case both the name and
    397 the default keyword might be optional. If the name is ommited in an assignment
    398 the closest vtable is choosen (returning to the global default rule if no
    399 approprate local vtable is in scope).
    400142
    401143### Site Based Resolution:
  • doc/user/user.tex

    rf343c6b r69c37cc  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sun Apr 14 11:02:34 2019
    14 %% Update Count     : 3443
     13%% Last Modified On : Tue Dec 11 23:19:26 2018
     14%% Update Count     : 3400
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    508508
    509509As for \Index{division}, there are exponentiation operators for integral and floating types, including the builtin \Index{complex} types.
    510 Integral 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).
    511 Overflow from large exponents or negative exponents return zero.
    512 Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative.
    513 \begin{cfa}
    514 sout | 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);
    516 1 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i
    517 \end{cfa}
    518 Note, ©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.
     510Unsigned 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).
     511Signed 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$.
     512Hence, 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.
     513Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the base cannot be negative.
     514\begin{cfa}
     515sout | 2 ®\® 8u | 4 ®\® 3u | -4 ®\® 3u | 4 ®\® -3 | -4 ®\® -3 | 4.0 ®\® 2.1 | (1.0f+2.0fi) ®\® (3.0f+2.0fi);
     516256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
     517\end{cfa}
    519518Parenthesis are necessary for complex constants or the expression is parsed as ©1.0f+®(®2.0fi \ 3.0f®)®+2.0fi©.
    520 The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation version is available.
    521 \begin{cfa}
    522 forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } )
    523 OT ?®\®?( OT ep, unsigned int y );
    524 forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } )
    525 OT ?®\®?( OT ep, unsigned long int y );
    526 \end{cfa}
    527 The user type ©T© must define multiplication, one, ©1©, and, ©*©.
     519The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation versions are available.
     520For returning an integral value, the user type ©T© must define multiplication, ©*©, and one, ©1©;
     521for returning a floating value, an additional divide of type ©T© into a ©double© returning a ©double© (©double ?/?( double, T )©) is necessary for negative exponents.
    528522
    529523
     
    555549\subsection{Loop Control}
    556550
    557 The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}).
    558 \begin{itemize}
    559 \item
     551The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges.
    560552An empty conditional implies ©1©.
    561 \item
    562 The up-to range ©~©\index{~@©~©} means exclusive range [M,N).
    563 \item
    564 The up-to range ©~=©\index{~=@©~=©} means inclusive range [M,N].
    565 \item
    566 The down-to range ©-~©\index{-~@©-~©} means exclusive range [N,M).
    567 \item
    568 The down-to range ©-~=©\index{-~=@©-~=©} means inclusive range [N,M].
    569 \item
    570 ©@© means put nothing in this field.
    571 \item
     553The up-to range ©~©\index{~@©~©} means exclusive range [M,N);
     554the up-to range ©~=©\index{~=@©~=©} means inclusive range [M,N].
     555The down-to range ©-~©\index{-~@©-~©} means exclusive range [N,M);
     556the down-to range ©-~=©\index{-~=@©-~=©} means inclusive range [N,M].
    572557©0© is the implicit start value;
    573 \item
    574558©1© is the implicit increment value.
    575 \item
    576559The up-to range uses ©+=© for increment;
    577 \item
    578 The down-to range uses ©-=© for decrement.
    579 \item
     560the down-to range uses ©-=© for decrement.
    580561The 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}
    584562\begin{cquote}
    585 \begin{tabular}{@{}l|l@{}}
    586 \multicolumn{1}{c|}{loop control} & \multicolumn{1}{c}{output} \\
     563\begin{tabular}{@{}ll|l@{}}
     564\multicolumn{2}{c|}{loop control} & \multicolumn{1}{c}{output} \\
    587565\hline
    588566\begin{cfa}
    589 sout | nlOff;
    590 while ®()® { sout | "empty"; break; } sout | nl;
    591 do { sout | "empty"; break; } while ®()®; sout | nl;
    592 for ®()® { sout | "empty"; break; } sout | nl;
    593 for ( ®0® ) { sout | "A"; } sout | "zero" | nl;
    594 for ( ®1® ) { sout | "A"; } sout | nl;
    595 for ( ®10® ) { sout | "A"; } sout | nl;
    596 for ( ®1 ~= 10 ~ 2® ) { sout | "B"; } sout | nl;
    597 for ( ®10 -~= 1 ~ 2® ) { sout | "C"; } sout | nl;
    598 for ( ®0.5 ~ 5.5® ) { sout | "D"; } sout | nl;
    599 for ( ®5.5 -~ 0.5® ) { sout | "E"; } sout | nl;
    600 for ( ®i; 10® ) { sout | i; } sout | nl;
    601 for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; } sout | nl;
    602 for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; } sout | nl;
    603 for ( ®i; 0.5 ~ 5.5® ) { sout | i; } sout | nl;
    604 for ( ®i; 5.5 -~ 0.5® ) { sout | i; } sout | nl;
    605 for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; } sout | nl;
    606 for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; } sout | nl;
     567while ®()® { sout | "empty"; break; }
     568do { sout | "empty"; break; } while ®()®;
     569for ®()® { sout | "empty"; break; }
     570for ( ®0® ) { sout | "A"; }
     571for ( ®1® ) { sout | "A"; }
     572for ( ®10® ) { sout | "A"; }
     573for ( ®1 ~= 10 ~ 2® ) { sout | "B"; }
     574for ( ®10 -~= 1 ~ 2® ) { sout | "C"; }
     575for ( ®0.5 ~ 5.5® ) { sout | "D"; }
     576for ( ®5.5 -~ 0.5® ) { sout | "E"; }
     577for ( ®i; 10® ) { sout | i; }
     578for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; }
     579for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; }
     580for ( ®i; 0.5 ~ 5.5® ) { sout | i; }
     581for ( ®i; 5.5 -~ 0.5® ) { sout | i; }
     582for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; }
     583for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; }
    607584enum { N = 10 };
    608 for ( ®N® ) { sout | "N"; } sout | nl;
    609 for ( ®i; N® ) { sout | i; } sout | nl;
    610 for ( ®i; N -~ 0® ) { sout | i; } sout | nl;
     585for ( ®N® ) { sout | "N"; }
     586for ( ®i; N® ) { sout | i; }
     587for ( ®i; N -~ 0® ) { sout | i; }
    611588const int start = 3, comp = 10, inc = 2;
    612 for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; } sout | nl;
    613 for ( ®i; 1 ~ @® ) { if ( i > 10 ) break;
    614         sout | i; } sout | nl;
    615 for ( ®i; 10 -~ @® ) { if ( i < 0 ) break;
    616         sout | i; } sout | nl;
    617 for ( ®i; 2 ~ @ ~ 2® ) { if ( i > 10 ) break;
    618         sout | i; } sout | nl;
    619 for ( ®i; 2.1 ~ @ ~ @® ) { if ( i > 10.5 ) break;
    620         sout | i; i += 1.7; } sout | nl;
    621 for ( ®i; 10 -~ @ ~ 2® ) { if ( i < 0 ) break;
    622         sout | i; } sout | nl;
    623 for ( ®i; 12.1 ~ @ ~ @® ) { if ( i < 2.5 ) break;
    624         sout | i; i -= 1.7; } sout | nl;
    625 for ( ®i; 5 : j; -5 ~ @® ) { sout | i | j; } sout | nl;
    626 for ( ®i; 5 : j; -5 -~ @® ) { sout | i | j; } sout | nl;
    627 for ( ®i; 5 : j; -5 ~ @ ~ 2® ) { sout | i | j; } sout | nl;
    628 for ( ®i; 5 : j; -5 -~ @ ~ 2® ) { sout | i | j; } sout | nl;
    629 for ( ®j; -5 ~ @ : i; 5® ) { sout | i | j; } sout | nl;
    630 for ( ®j; -5 -~ @ : i; 5® ) { sout | i | j; } sout | nl;
    631 for ( ®j; -5 ~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl;
    632 for ( ®j; -5 -~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl;
    633 for ( ®j; -5 -~ @ ~ 2 : i; 5 : k; 1.5 ~ @® ) {
    634         sout | i | j | k; } sout | nl;
    635 for ( ®j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 5® ) {
    636         sout | i | j | k; } sout | nl;
    637 for ( ®k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 5® ) {
    638         sout | i | j | k; } sout | nl;
     589for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; }
    639590\end{cfa}
    640591&
    641592\begin{cfa}
    642 
     593sout | nl;
     594sout | nl;
     595sout | nl;
     596sout | "zero" | nl;
     597sout | nl;
     598sout | nl;
     599sout | nl;
     600sout | nl;
     601sout | nl;
     602sout | nl;
     603sout | nl;
     604sout | nl;
     605sout | nl;
     606sout | nl;
     607sout | nl;
     608sout | nl;
     609sout | nl | nl;
     610
     611sout | nl;
     612sout | nl;
     613sout | nl | nl;
     614
     615sout | nl;
     616\end{cfa}
     617&
     618\begin{cfa}
    643619empty
    644620empty
     
    664640
    6656413 6 9
    666 
    667 1 2 3 4 5 6 7 8 9 10
    668 
    669 10 9 8 7 6 5 4 3 2 1 0
    670 
    671 2 4 6 8 10
    672 
    673 2.1 3.8 5.5 7.2 8.9
    674 
    675 10 8 6 4 2 0
    676 
    677 12.1 10.4 8.7 7 5.3 3.6
    678 0 -5 1 -4 2 -3 3 -2 4 -1
    679 0 -5 1 -6 2 -7 3 -8 4 -9
    680 0 -5 1 -3 2 -1 3 1 4 3
    681 0 -5 1 -7 2 -9 3 -11 4 -13
    682 0 -5 1 -4 2 -3 3 -2 4 -1
    683 0 -5 1 -6 2 -7 3 -8 4 -9
    684 0 -5 1 -3 2 -1 3 1 4 3
    685 0 -5 1 -7 2 -9 3 -11 4 -13
    686 
    687 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    688 
    689 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    690 
    691 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5
    692642\end{cfa}
    693643\end{tabular}
    694644\end{cquote}
    695 \caption{Loop Control Examples}
    696 \label{f:LoopControlExamples}
    697 \end{figure}
    698645
    699646
     
    13731320\end{cfa}
    13741321Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}).
    1375 While 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}
    1377 In 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}
     1322While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice.
    13791323
    13801324\CFA provides its own type, variable and routine declarations, using a different syntax.
  • libcfa/configure

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

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

    rf343c6b r69c37cc  
    1010// Created On       : Fri Jul 21 16:21:03 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 26 23:10:36 2019
    13 // Update Count     : 95
     12// Last Modified On : Sun Mar 10 10:52:50 2019
     13// Update Count     : 31
    1414//
    1515
     
    1818typedef unsigned long long __cfaabi_abi_exception_type_t;
    1919
    20 #include <limits.h>                                                                             // CHAR_BIT
    2120#include "../src/virtual.h"
    2221#include "../src/exception.h"
     
    2726// increment/decrement unification
    2827
    29 static inline {
    30         forall( dtype DT | { DT & ?+=?( DT &, one_t ); } )
    31         DT & ++?( DT & x ) { return x += 1; }
     28static inline forall( dtype T | { T & ?+=?( T &, one_t ); } )
     29T & ++? ( T & x ) { return x += 1; }
    3230
    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; }
     31static inline forall( dtype T | sized(T) | { void ?{}( T &, T ); void ^?{}( T & ); T & ?+=?( T &, one_t ); } )
     32T & ?++ ( T & x ) { T tmp = x; x += 1; return tmp; }
    3533
    36         forall( dtype DT | { DT & ?-=?( DT &, one_t ); } )
    37         DT & --?( DT & x ) { return x -= 1; }
     34static inline forall( dtype T | { T & ?-=?( T &, one_t ); } )
     35T & --? ( T & x ) { return x -= 1; }
    3836
    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
     37static inline forall( dtype T | sized(T) | { void ?{}( T &, T ); void ^?{}( T & ); T & ?-=?( T &, one_t ); } )
     38T & ?-- ( T & x ) { T tmp = x; x -= 1; return tmp; }
    4239
    4340// universal typed pointer constant
    44 // Compiler issue: there is a problem with anonymous types that do not have a size.
    45 static inline forall( dtype DT | sized(DT) ) DT * intptr( uintptr_t addr ) { return (DT *)addr; }
     41
     42static inline forall( dtype T ) T * intptr( uintptr_t addr ) { return (T *)addr; }
    4643
    4744// exponentiation operator implementation
     
    5653} // extern "C"
    5754
    58 static 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
     55static inline float ?\?( float x, float y ) { return powf( x, y ); }
     56static inline double ?\?( double x, double y ) { return pow( x, y ); }
     57static inline long double ?\?( long double x, long double y ) { return powl( x, y ); }
     58static inline float _Complex ?\?( float _Complex x, _Complex float y ) { return cpowf(x, y ); }
     59static inline double _Complex ?\?( double _Complex x, _Complex double y ) { return cpow( x, y ); }
     60static inline long double _Complex ?\?( long double _Complex x, _Complex long double y ) { return cpowl( x, y ); }
    6661
    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
     62static 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} // ?\?
    7072
    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
     73static inline forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } )
     74T ?\?( 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} // ?\?
    8283
    83 static 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
     84// unsigned computation may be faster and larger
     85static 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} // ?\?
    9095
    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__()
     96static 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} // ?\?
    97100
    98 static 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
     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.
    102105
    103 #undef __CFA_BASE_COMP_1__
    104 #undef __CFA_BASE_COMP_2__
    105 #undef __CFA_EXP_OVERFLOW__
     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// } // ?\?
    106111
    107 static 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
     112static inline long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; }
     113static inline unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; }
     114static inline int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; }
     115static inline unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; }
    113116
    114117// Local Variables: //
  • libcfa/prelude/prelude-gen.cc

    rf343c6b r69c37cc  
    1010// Created On       : Sat Feb 16 08:44:58 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr  2 17:18:24 2019
    13 // Update Count     : 37
     12// Last Modified On : Fri Mar  8 16:00:22 2019
     13// Update Count     : 26
    1414//
    1515
     
    118118        { "?!=?", false, "signed int", Normal, "" },
    119119        { "?=?", true, "", Normal, "" }, // void * LHS, zero_t RHS ???
    120 //      { "*?", false, "&", Normal, " | sized(DT)" }, // & ???
    121         { "*?", false, "&", Normal, "" }, // & ???
     120        { "*?", false, "&", Normal, " | sized(DT)" }, // & ???
    122121
    123122        { "?-?", false, "ptrdiff_t", Normal, " | sized(DT)" },
     
    209208                cout << "void ?{} (" << type << " &);" << endl;
    210209                cout << "void ?{} (" << type << " &, " << type << ");" << endl;
    211                 cout << type << " ?=? (" << type << " &, " << type << ")";
     210                cout << type << "  ?=? (" << type << " &, " << type << ")";
    212211                if ( do_volatile ) {
    213                         cout << ", ?=?(volatile " << type << " &, " << type << ")";
     212                        cout << ",  ?=?(volatile " << type << " &, " << type << ")";
    214213                }
    215214                cout << ";" << endl;
     
    218217
    219218        otype("zero_t");
    220         cout << endl;
    221219        otype("one_t");
    222         cout << endl;
    223220        otype("_Bool", true);
    224221        cout << endl;
     
    228225                cout << "void ?{}(" << type.name << " &, " << type.name << ");" << endl;
    229226                cout << "void ?{}(" << type.name << " &, zero_t);" << endl;
    230                 cout << "void ?{}(" << type.name << " &, one_t);" << endl;
    231227                cout << "void ^?{}(" << type.name << " &);" << endl;
    232228                cout << endl;
  • libcfa/src/Makefile.am

    rf343c6b r69c37cc  
    7474
    7575prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    76         ${AM_V_GEN}$(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
     76        ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -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         $(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
     80        @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
    8181
    8282
  • libcfa/src/Makefile.in

    rf343c6b r69c37cc  
    926926
    927927prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@
    928         ${AM_V_GEN}$(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
     928        ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -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         $(CFACOMPILE) -quiet -in-tree -XCFA -l ${<} -c -o ${@}
     932        @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@}
    933933
    934934#----------------------------------------------------------------------------------------------------------------
  • libcfa/src/concurrency/CtxSwitch-x86_64.S

    rf343c6b r69c37cc  
    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 
    14590.text
    14691        .align 2
  • libcfa/src/concurrency/coroutine.cfa

    rf343c6b r69c37cc  
    3535
    3636extern "C" {
    37       void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
     37      void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) __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_thread )->curr_cor;
     86            coroutine_desc * src = TL_GET( this_coroutine );
    8787            coroutine_desc * dst = &this;
    8888
     
    115115// Wrapper for co
    116116void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
    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
     117      // Safety note : This could cause some false positives due to preemption
    119118      verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
    120119      disable_interrupts();
     
    124123
    125124      // set new coroutine that task is executing
    126       TL_GET( this_thread )->curr_cor = dst;
     125      kernelTLS.this_coroutine = dst;
    127126
    128127      // context switch to specified coroutine
     
    135134
    136135      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 
    140139      if( unlikely(src->cancellation != NULL) ) {
    141             _CtxCoroutine_Unwind(src->cancellation, src);
     140            _CtxCoroutine_Unwind(src->cancellation);
    142141      }
    143142} //ctxSwitchDirect
     
    198197      }
    199198
    200       void __leave_coroutine( coroutine_desc * src ) {
     199      void __leave_coroutine() {
     200            coroutine_desc * src = TL_GET( this_coroutine ); // optimization
    201201            coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter;
    202202
  • libcfa/src/concurrency/coroutine.hfa

    rf343c6b r69c37cc  
    4646//-----------------------------------------------------------------------------
    4747// Public coroutine API
    48 static inline void suspend(void);
     48static inline void suspend();
    4949
    5050forall(dtype T | is_coroutine(T))
     
    7171
    7272// Suspend implementation inlined for performance
    73 static inline void suspend(void) {
     73static inline void suspend() {
    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_thread )->curr_cor;
     79        coroutine_desc * src = TL_GET( this_coroutine );
    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_thread )->curr_cor;
     101        coroutine_desc * src = TL_GET( this_coroutine );
    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_thread )->curr_cor;
     131        coroutine_desc * src = TL_GET( this_coroutine );
    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 
    214148// Local Variables: //
    215149// mode: c //
  • libcfa/src/concurrency/invoke.c

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

    rf343c6b r69c37cc  
    5050
    5151                extern thread_local struct KernelThreadData {
     52                        struct coroutine_desc * volatile this_coroutine;
    5253                        struct thread_desc    * volatile this_thread;
    5354                        struct processor      * volatile this_processor;
     
    6061                } kernelTLS __attribute__ ((tls_model ( "initial-exec" )));
    6162        }
     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
    6267        #endif
    6368
     
    165170                        struct thread_desc * prev;
    166171                } node;
    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 
     172     };
     173
     174     #ifdef __cforall
     175     extern "Cforall" {
    175176                static inline thread_desc * & get_next( thread_desc & this ) {
    176177                        return this.next;
     
    231232        extern void CtxInvokeStub( void );
    232233        void CtxSwitch( void * from, void * to ) asm ("CtxSwitch");
    233         // void CtxStore ( void * this ) asm ("CtxStore");
    234         // void CtxRet   ( void * dst  ) asm ("CtxRet");
    235234
    236235        #if   defined( __i386 )
  • libcfa/src/concurrency/kernel.cfa

    rf343c6b r69c37cc  
    6060        NULL,
    6161        NULL,
     62        NULL,
    6263        { 1, false, false }
    6364};
     
    262263static void returnToKernel() {
    263264        coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner);
    264         coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor;
     265        coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor = kernelTLS.this_coroutine;
    265266        ThreadCtxSwitch(thrd_cor, proc_cor);
    266267}
     
    306307        processor * proc = (processor *) arg;
    307308        kernelTLS.this_processor = proc;
     309        kernelTLS.this_coroutine = NULL;
    308310        kernelTLS.this_thread    = NULL;
    309311        kernelTLS.preemption_state.[enabled, disable_count] = [false, 1];
     
    319321
    320322        //Set global state
     323        kernelTLS.this_coroutine = get_coroutine(proc->runner);
    321324        kernelTLS.this_thread    = NULL;
    322325
     
    348351// KERNEL_ONLY
    349352void kernel_first_resume(processor * this) {
    350         coroutine_desc * src = mainThread->curr_cor;
     353        coroutine_desc * src = kernelTLS.this_coroutine;
    351354        coroutine_desc * dst = get_coroutine(this->runner);
    352355
     
    363366        // set state of current coroutine to inactive
    364367        src->state = src->state == Halted ? Halted : Inactive;
     368
     369        // set new coroutine that task is executing
     370        kernelTLS.this_coroutine = dst;
    365371
    366372        // SKULLDUGGERY normally interrupts are enable before leaving a coroutine ctxswitch.
     
    593599        kernelTLS.this_processor = mainProcessor;
    594600        kernelTLS.this_thread    = mainThread;
     601        kernelTLS.this_coroutine = &mainThread->self_cor;
    595602
    596603        // Enable preemption
     
    713720                __cfaabi_dbg_bits_write( abort_text, len );
    714721
    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 );
     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 );
    717724                        __cfaabi_dbg_bits_write( abort_text, len );
    718725                }
  • libcfa/src/concurrency/thread.cfa

    rf343c6b r69c37cc  
    7575        coroutine_desc* thrd_c = get_coroutine(this);
    7676        thread_desc   * thrd_h = get_thread   (this);
    77         thrd_c->last = TL_GET( this_thread )->curr_cor;
     77        thrd_c->last = TL_GET( this_coroutine );
    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;
    8384        CtxStart(&this, CtxInvokeThread);
    8485        assert( thrd_c->last->stack.context );
     
    9192extern "C" {
    9293        // KERNEL ONLY
    93         void __finish_creation(coroutine_desc * thrd_c) {
     94        void __finish_creation(void) {
     95                coroutine_desc* thrd_c = kernelTLS.this_coroutine;
    9496                ThreadCtxSwitch( thrd_c, thrd_c->last );
    9597        }
     
    118120        // set new coroutine that the processor is executing
    119121        // and context switch to it
     122        kernelTLS.this_coroutine = dst;
    120123        assert( src->stack.context );
    121124        CtxSwitch( src->stack.context, dst->stack.context );
     125        kernelTLS.this_coroutine = src;
    122126
    123127        // set state of new coroutine to active
  • libcfa/src/fstream.cfa

    rf343c6b r69c37cc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Apr 20 12:03:43 2019
    13 // Update Count     : 311
     12// Last Modified On : Mon Dec 24 18:33:38 2018
     13// Update Count     : 304
    1414//
    1515
     
    2323#include <complex.h>                                                                    // creal, cimag
    2424#include <assert.h>
    25 #include <errno.h>                                                                              // errno
    2625
    2726#define IO_MSG "I/O error: "
     
    3332        os.nlOnOff = nlOnOff;
    3433        os.prt = prt;
    35         os.sawNL = false;
    3634        sepSet( os, separator );
    3735        sepSetCur( os, sepGet( os ) );
     
    107105        #ifdef __CFA_DEBUG__
    108106        if ( file == 0 ) {
    109                 abort( IO_MSG "open output file \"%s\", %s", name, strerror( errno ) );
     107                fprintf( stderr, IO_MSG "open output file \"%s\", ", name );
     108                perror( 0 );
     109                exit( EXIT_FAILURE );
    110110        } // if
    111111        #endif // __CFA_DEBUG__
     
    121121
    122122        if ( fclose( (FILE *)(os.file) ) == EOF ) {
    123                 abort( IO_MSG "close output %s", strerror( errno ) );
     123                perror( IO_MSG "close output" );
    124124        } // if
    125125} // close
     
    127127ofstream & write( ofstream & os, const char * data, size_t size ) {
    128128        if ( fail( os ) ) {
    129                 abort( "attempt write I/O on failed stream\n" );
     129                fprintf( stderr, "attempt write I/O on failed stream\n" );
     130                exit( EXIT_FAILURE );
    130131        } // if
    131132
    132133        if ( fwrite( data, 1, size, (FILE *)(os.file) ) != size ) {
    133                 abort( IO_MSG "write %s", strerror( errno ) );
     134                perror( IO_MSG "write" );
     135                exit( EXIT_FAILURE );
    134136        } // if
    135137        return os;
     
    142144        if ( len == EOF ) {
    143145                if ( ferror( (FILE *)(os.file) ) ) {
    144                         abort( "invalid write\n" );
     146                        fprintf( stderr, "invalid write\n" );
     147                        exit( EXIT_FAILURE );
    145148                } // if
    146149        } // if
     
    163166void ?{}( ifstream & is, void * file ) {
    164167        is.file = file;
    165         is.nlOnOff = false;
    166168}
    167169
     
    175177        open( is, name, "r" );
    176178}
    177 
    178 void nlOn( ifstream & os ) { os.nlOnOff = true; }
    179 void nlOff( ifstream & os ) { os.nlOnOff = false; }
    180 bool getANL( ifstream & os ) { return os.nlOnOff; }
    181179
    182180int fail( ifstream & is ) {
     
    189187
    190188void open( ifstream & is, const char * name, const char * mode ) {
    191         FILE * file = fopen( name, mode );
     189        FILE *file = fopen( name, mode );
    192190        #ifdef __CFA_DEBUG__
    193191        if ( file == 0 ) {
    194                 abort( IO_MSG "open input file \"%s\", %s\n", name, strerror( errno ) );
     192                fprintf( stderr, IO_MSG "open input file \"%s\", ", name );
     193                perror( 0 );
     194                exit( EXIT_FAILURE );
    195195        } // if
    196196        #endif // __CFA_DEBUG__
     
    206206
    207207        if ( fclose( (FILE *)(is.file) ) == EOF ) {
    208                 abort( IO_MSG "close input %s", strerror( errno ) );
     208                perror( IO_MSG "close input" );
    209209        } // if
    210210} // close
     
    212212ifstream & read( ifstream & is, char * data, size_t size ) {
    213213        if ( fail( is ) ) {
    214                 abort( "attempt read I/O on failed stream\n" );
     214                fprintf( stderr, "attempt read I/O on failed stream\n" );
     215                exit( EXIT_FAILURE );
    215216        } // if
    216217
    217218        if ( fread( data, size, 1, (FILE *)(is.file) ) == 0 ) {
    218                 abort( IO_MSG "read %s", strerror( errno ) );
     219                perror( IO_MSG "read" );
     220                exit( EXIT_FAILURE );
    219221        } // if
    220222        return is;
     
    223225ifstream &ungetc( ifstream & is, char c ) {
    224226        if ( fail( is ) ) {
    225                 abort( "attempt ungetc I/O on failed stream\n" );
     227                fprintf( stderr, "attempt ungetc I/O on failed stream\n" );
     228                exit( EXIT_FAILURE );
    226229        } // if
    227230
    228231        if ( ungetc( c, (FILE *)(is.file) ) == EOF ) {
    229                 abort( IO_MSG "ungetc %s", strerror( errno ) );
     232                perror( IO_MSG "ungetc" );
     233                exit( EXIT_FAILURE );
    230234        } // if
    231235        return is;
     
    239243        if ( len == EOF ) {
    240244                if ( ferror( (FILE *)(is.file) ) ) {
    241                         abort( "invalid read\n" );
     245                        fprintf( stderr, "invalid read\n" );
     246                        exit( EXIT_FAILURE );
    242247                } // if
    243248        } // if
  • libcfa/src/fstream.hfa

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

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

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

    rf343c6b r69c37cc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Apr 20 14:02:43 2019
    13 // Update Count     : 617
     12// Last Modified On : Mon Mar  4 20:57:24 2019
     13// Update Count     : 593
    1414//
    1515
     
    396396
    397397        istype & ?|?( istype & is, char & c ) {
    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
     398                fmt( is, "%c", &c );                                                    // must pass pointer through varg to fmt
    405399                return is;
    406400        } // ?|?
     
    504498                return is;
    505499        } // 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
    516500} // distribution
    517501
  • libcfa/src/iostream.hfa

    rf343c6b r69c37cc  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Apr 20 12:04:07 2019
    13 // Update Count     : 226
     12// Last Modified On : Tue Feb 26 16:57:22 2019
     13// Update Count     : 221
    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)
    154151        int fail( istype & );
    155152        int eof( istype & );
     
    190187
    191188        // manipulators
    192         istype & nlOn( istype & );
    193         istype & nlOff( istype & );
    194189        istype & ?|?( istype &, istype & (*)( istype & ) );
    195190        istype & nl( istype & is );
  • libcfa/src/rational.cfa

    rf343c6b r69c37cc  
    1010// Created On       : Wed Apr  6 17:54:28 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar 28 17:33:03 2019
    13 // Update Count     : 181
     12// Last Modified On : Sun Dec 23 22:56:49 2018
     13// Update Count     : 170
    1414//
    1515
     
    3535        static RationalImpl simplify( RationalImpl & n, RationalImpl & d ) {
    3636                if ( d == (RationalImpl){0} ) {
    37                         abort( "Invalid rational number construction: denominator cannot be equal to 0.\n" );
     37                        serr | "Invalid rational number construction: denominator cannot be equal to 0.";
     38                        exit( EXIT_FAILURE );
    3839                } // exit
    3940                if ( d < (RationalImpl){0} ) { d = -d; n = -n; } // move sign to numerator
     
    5354        void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ) {
    5455                RationalImpl t = simplify( n, d );                              // simplify
    55                 r.[numerator, denominator] = [n / t, d / t];
     56                r.numerator = n / t;
     57                r.denominator = d / t;
    5658        } // rational
    5759
     
    7678                RationalImpl prev = r.numerator;
    7779                RationalImpl t = gcd( abs( n ), r.denominator ); // simplify
    78                 r.[numerator, denominator] = [n / t, r.denominator / t];
     80                r.numerator = n / t;
     81                r.denominator = r.denominator / t;
    7982                return prev;
    8083        } // numerator
     
    8386                RationalImpl prev = r.denominator;
    8487                RationalImpl t = simplify( r.numerator, d );    // simplify
    85                 r.[numerator, denominator] = [r.numerator / t, d / t];
     88                r.numerator = r.numerator / t;
     89                r.denominator = d / t;
    8690                return prev;
    8791        } // denominator
     
    116120
    117121        Rational(RationalImpl) +?( Rational(RationalImpl) r ) {
    118                 return (Rational(RationalImpl)){ r.numerator, r.denominator };
     122                Rational(RationalImpl) t = { r.numerator, r.denominator };
     123                return t;
    119124        } // +?
    120125
    121126        Rational(RationalImpl) -?( Rational(RationalImpl) r ) {
    122                 return (Rational(RationalImpl)){ -r.numerator, r.denominator };
     127                Rational(RationalImpl) t = { -r.numerator, r.denominator };
     128                return t;
    123129        } // -?
    124130
    125131        Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    126132                if ( l.denominator == r.denominator ) {                 // special case
    127                         return (Rational(RationalImpl)){ l.numerator + r.numerator, l.denominator };
     133                        Rational(RationalImpl) t = { l.numerator + r.numerator, l.denominator };
     134                        return t;
    128135                } else {
    129                         return (Rational(RationalImpl)){ l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator };
     136                        Rational(RationalImpl) t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator };
     137                        return t;
    130138                } // if
    131139        } // ?+?
     
    133141        Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    134142                if ( l.denominator == r.denominator ) {                 // special case
    135                         return (Rational(RationalImpl)){ l.numerator - r.numerator, l.denominator };
     143                        Rational(RationalImpl) t = { l.numerator - r.numerator, l.denominator };
     144                        return t;
    136145                } else {
    137                         return (Rational(RationalImpl)){ l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator };
     146                        Rational(RationalImpl) t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator };
     147                        return t;
    138148                } // if
    139149        } // ?-?
    140150
    141151        Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    142                 return (Rational(RationalImpl)){ l.numerator * r.numerator, l.denominator * r.denominator };
     152                Rational(RationalImpl) t = { l.numerator * r.numerator, l.denominator * r.denominator };
     153                return t;
    143154        } // ?*?
    144155
    145156        Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ) {
    146157                if ( r.numerator < (RationalImpl){0} ) {
    147                         r.[numerator, denominator] = [-r.numerator, -r.denominator];
     158                        r.numerator = -r.numerator;
     159                        r.denominator = -r.denominator;
    148160                } // if
    149                 return (Rational(RationalImpl)){ l.numerator * r.denominator, l.denominator * r.numerator };
     161                Rational(RationalImpl) t = { l.numerator * r.denominator, l.denominator * r.numerator };
     162                return t;
    150163        } // ?/?
    151164
     
    154167        forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } )
    155168        istype & ?|?( istype & is, Rational(RationalImpl) & r ) {
     169                RationalImpl t;
    156170                is | r.numerator | r.denominator;
    157                 RationalImpl t = simplify( r.numerator, r.denominator );
     171                t = simplify( r.numerator, r.denominator );
    158172                r.numerator /= t;
    159173                r.denominator /= t;
     
    171185        } // distribution
    172186} // distribution
    173 
    174 forall( otype RationalImpl | arithmetic( RationalImpl ) | { RationalImpl ?\?( RationalImpl, unsigned long ); } )
    175 Rational(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 }
    182187
    183188// conversion
  • libcfa/src/rational.hfa

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

    rf343c6b r69c37cc  
    1010// Created On       : Mon Jul  4 23:25:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 25 08:00:08 2019
    13 // Update Count     : 15
     12// Last Modified On : Tue Jul  5 20:39:51 2016
     13// Update Count     : 12
    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
    2918} // extern "C"
    3019
  • libcfa/src/stdlib.hfa

    rf343c6b r69c37cc  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 24 17:35:43 2019
    13 // Update Count     : 352
     12// Last Modified On : Mon Dec 17 15:37:45 2018
     13// Update Count     : 346
    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
    4249        T * calloc( size_t dim ) {
    4350                return (T *)(void *)calloc( dim, sizeof(T) );   // C calloc
     
    6976        T * alloc( char fill ) {
    7077                T * ptr = (T *)(void *)malloc( (size_t)sizeof(T) );     // C malloc
    71                 return (T *)memset( ptr, (int)fill, sizeof(T) ); // initialize with fill value
     78                return (T *)memset( ptr, (int)fill, sizeof(T) );        // initial with fill value
    7279        } // alloc
    7380
     
    7784
    7885        T * alloc( size_t dim, char fill ) {
    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
     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
    8188        } // alloc
    8289
  • src/Common/PassVisitor.cc

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

    rf343c6b r69c37cc  
    3737                        class SimpleCounter {
    3838                        public:
    39                                 inline void operator++() {}
    4039                                inline void operator++(int) {}
    4140                                inline void operator+=(size_t) {}
     
    8584                                virtual void print(std::ostream & os) override { os << count; }
    8685
    87                                 inline void operator++()             { if(!enabled) return; count++;        }
    8886                                inline void operator++(int)          { if(!enabled) return; count++;        }
    8987                                inline void operator+=(size_t value) { if(!enabled) return; count += value; }
  • src/ControlStruct/ForExprMutator.cc

    rf343c6b r69c37cc  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 11 22:26:52 2019
    13 // Update Count     : 14
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Aug 18 10:22:00 2017
     13// Update Count     : 12
    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

    rf343c6b r69c37cc  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 11 22:26:02 2019
    13 // Update Count     : 159
     11// Last Modified By : Rob Schluntz
     12// Last Modified On : Tue Jul 28 13:32:43 2015
     13// Update Count     : 156
    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 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 ) {
     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 ) {
    8080                assert( definition != 0 );
    8181                assert( llabel.size() > 0 );
     
    100100                } // for
    101101
    102                 // produce one of the labels attached to this statement to be temporarily used as the canonical label
     102                // produce one of the labels attached to this statement to be
     103                // temporarily used as the canonical label
    103104                return labelTable[ llabel.front() ]->get_label();
    104105        }
     
    116117
    117118        // Builds a table that maps a label to its defining statement.
    118         std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) {
     119        std::map<Label, Statement * > *LabelFixer::resolveJumps() throw ( SemanticErrorException ) {
    119120                std::map< Label, Statement * > *ret = new std::map< Label, Statement * >();
    120121                for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) {
  • src/ControlStruct/LabelGenerator.cc

    rf343c6b r69c37cc  
    99// Author           : Rodolfo G. Esteves
    1010// Created On       : Mon May 18 07:44:20 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 11 22:23:20 2019
    13 // Update Count     : 15
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Aug 14 14:14:00 2015
     13// Update Count     : 14
    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
    3132                return labelGenerator;
    3233        }
     
    3738                if ( stmt && ! stmt->get_labels().empty() ) {
    3839                        os << "_" << stmt->get_labels().front() << "__";
    39                 } // if
     40                }
    4041                std::string ret = os.str();
    4142                Label l( ret );
  • src/Parser/ParseNode.h

    rf343c6b r69c37cc  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 15 14:22:39 2019
    13 // Update Count     : 874
     12// Last Modified On : Wed Feb 13 17:36:49 2019
     13// Update Count     : 867
    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(); }
    134135        template<typename T>
    135136        bool isExpressionType() const { return nullptr != dynamic_cast<T>(expr.get()); }
    136137
    137138        Expression * build() const { return const_cast<ExpressionNode *>(this)->expr.release(); }
    138 
    139         std::unique_ptr<Expression> expr;                                       // public because of lifetime implications
    140139  private:
    141140        bool extension = false;
     141        std::unique_ptr<Expression> expr;
    142142}; // ExpressionNode
    143143
  • src/Parser/lex.ll

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

    rf343c6b r69c37cc  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 15 15:02:56 2019
    13 // Update Count     : 4290
     12// Last Modified On : Thu Feb 21 08:45:07 2019
     13// Update Count     : 4232
    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->expr.get());
     187        ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->get_expr());
    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->expr.get()) ) {
     200        if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->get_expr()) ) {
    201201                return forCtrl( type, new string( identifier->name ), start, compop, comp, inc );
    202         } else if ( CommaExpr * commaExpr = dynamic_cast<CommaExpr *>(index->expr.get()) ) {
     202        } else if ( CommaExpr * commaExpr = dynamic_cast<CommaExpr *>(index->get_expr()) ) {
    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 COERCE                                              // CFA
     267%token FORALL MUTEX VIRTUAL                                                             // 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
    798797        | '(' COROUTINE '&' ')' cast_expression                         // CFA
    799798                { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); }
     
    807806        | '(' VIRTUAL type_no_function ')' cast_expression      // CFA
    808807                { $$ = 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; }
    815808//      | '(' type_no_function ')' tuple
    816809//              { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
    817         ;
    818 
    819 qualifier_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 
    826 cast_modifier:
    827         '-'
    828         | '+'
    829810        ;
    830811
     
    11641145        for_control_expression
    11651146        | for_control_expression_list ':' for_control_expression
    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                 }
     1147                { $$ = $3; }
    11841148        ;
    11851149
     
    11911155        | declaration comma_expression_opt ';' comma_expression_opt // C99, declaration has ';'
    11921156                { $$ = new ForCtrl( $1, $2, $4 ); }
    1193 
    11941157        | comma_expression                                                                      // CFA
    11951158                { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
     
    12061169        | comma_expression ';' comma_expression inclexcl comma_expression '~' comma_expression // CFA
    12071170                { $$ = 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" ) ) ) ); }
    12141171        | comma_expression ';' comma_expression '~' '@' '~' comma_expression // CFA
    12151172                { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, $7 ); }
  • src/ResolvExpr/AlternativeFinder.cc

    rf343c6b r69c37cc  
    258258                        // - necessary pre-requisite to pruning
    259259                        AltList candidates;
    260                         std::list<std::string> errors;
    261260                        for ( unsigned i = 0; i < alternatives.size(); ++i ) {
    262                                 resolveAssertions( alternatives[i], indexer, candidates, errors );
     261                                resolveAssertions( alternatives[i], indexer, candidates );
    263262                        }
    264263                        // fail early if none such
    265264                        if ( mode.failFast && candidates.empty() ) {
    266265                                std::ostringstream stream;
    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                                 }
     266                                stream << "No resolvable alternatives for expression " << expr << "\n"
     267                                       << "Alternatives with failing assertions are:\n";
     268                                printAlts( alternatives, stream, 1 );
    273269                                SemanticError( expr->location, stream.str() );
    274270                        }
  • src/ResolvExpr/ResolveAssertions.cc

    rf343c6b r69c37cc  
    2020#include <list>                     // for list
    2121#include <memory>                   // for unique_ptr
    22 #include <sstream>                  // for ostringstream
    23 #include <string>                   // for string
     22#include <string>
    2423#include <unordered_map>            // for unordered_map, unordered_multimap
    2524#include <utility>                  // for move
     
    2827#include "Alternative.h"            // for Alternative, AssertionItem, AssertionList
    2928#include "Common/FilterCombos.h"    // for filterCombos
    30 #include "Common/Indenter.h"        // for Indenter
    3129#include "Common/utility.h"         // for sort_mins
    3230#include "ResolvExpr/RenameVars.h"  // for renameTyVars
     
    9997                        return { item, item.matches[i] };
    10098                }
    101 
    102                 const DeclarationWithType* get_decl() const { return cache->at(key).deferIds[0].decl; }
    10399
    104100                // sortable by key
     
    368364        static const int recursionLimit = /* 10 */ 4;
    369365
    370         void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out, std::list<std::string>& errors ) {
     366        void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out ) {
    371367                // finish early if no assertions to resolve
    372368                if ( alt.need.empty() ) {
     
    389385                                for ( auto& assn : resn.need ) {
    390386                                        // fail early if any assertion is not resolvable
    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                                         }
     387                                        if ( ! resolveAssertion( assn, resn, assnCache ) ) goto nextResn;
    402388                                }
    403389
     
    418404                                                resn.deferred,
    419405                                                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                                         }
    435406                                        // sort by cost
    436407                                        CandidateCost coster{ resn.indexer };
  • src/ResolvExpr/ResolveAssertions.h

    rf343c6b r69c37cc  
    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, std::list<std::string>& errors );
     26        void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out );
    2727} // namespace ResolvExpr
    2828
  • src/ResolvExpr/TypeEnvironment.cc

    rf343c6b r69c37cc  
    386386        }
    387387
    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 ) {
     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 ) {
    391389
    392390                auto class1 = internal_lookup( var1->get_name() );
     
    430428                                        class1->set_type( common );
    431429                                }
    432                                 class1->data.isComplete |= data.isComplete;
    433430                                env.erase( class2 );
    434431                        } else return false;
     
    438435                                class1->vars.insert( class2->vars.begin(), class2->vars.end() );
    439436                                class1->allowWidening = widen1;
    440                                 class1->data.isComplete |= data.isComplete;
    441437                                env.erase( class2 );
    442438                        } else {
    443439                                class2->vars.insert( class1->vars.begin(), class1->vars.end() );
    444440                                class2->allowWidening = widen2;
    445                                 class2->data.isComplete |= data.isComplete;
    446441                                env.erase( class1 );
    447442                        } // if
     
    450445                        class1->vars.insert( var2->get_name() );
    451446                        class1->allowWidening = widen1;
    452                         class1->data.isComplete |= data.isComplete;
    453447                } else if ( class2 != env.end() ) {
    454448                        // var1 unbound, add to class2
    455449                        class2->vars.insert( var1->get_name() );
    456450                        class2->allowWidening = widen2;
    457                         class2->data.isComplete |= data.isComplete;
    458451                } else {
    459452                        // neither var bound, create new class
  • src/ResolvExpr/TypeEnvironment.h

    rf343c6b r69c37cc  
    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, TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
     141                bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const 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

    rf343c6b r69c37cc  
    172172                bool isopen2 = var2 && ( entry2 != openVars.end() );
    173173
    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                         }
     174                if ( isopen1 && isopen2 && entry1->second == entry2->second ) {
     175                        result = env.bindVarToVar( var1, var2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );
    182176                } else if ( isopen1 ) {
    183177                        result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer );
  • src/SymTab/Indexer.cc

    rf343c6b r69c37cc  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:37:33 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Fri Mar  8 13:55:00 2019
    13 // Update Count     : 21
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Aug 17 16:08:40 2017
     13// Update Count     : 20
    1414//
    1515
     
    1717
    1818#include <cassert>                 // for assert, strict_dynamic_cast
     19#include <iostream>                // for operator<<, basic_ostream, ostream
    1920#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
    2524
    2625#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
    2726#include "Common/SemanticError.h"  // for SemanticError
    2827#include "Common/utility.h"        // for cloneAll
    29 #include "Common/Stats/Counter.h"  // for counters
    30 #include "GenPoly/GenPoly.h"       // for getFunctionType
     28#include "Common/Stats/Counter.h" // for counters
     29#include "GenPoly/GenPoly.h"
    3130#include "InitTweak/InitTweak.h"   // for isConstructor, isCopyFunction, isC...
    3231#include "Mangler.h"               // for Mangler
     
    4039#include "SynTree/Type.h"          // for Type, StructInstType, UnionInstType
    4140
     41#define debugPrint(x) if ( doDebug ) { std::cerr << x; }
     42
    4243namespace SymTab {
    4344
    4445        // Statistics block
    4546        namespace {
    46                 static inline auto stats() {
     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() {
    4764                        using namespace Stats::Counters;
    4865                        static auto group   = build<CounterGroup>("Indexers");
     
    5067                                SimpleCounter * count;
    5168                                AverageCounter<double> * size;
    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;
     69                                AverageCounter<double> * depth_a;
     70                                MaxCounter<size_t> * depth_m;
    6071                        } ret = {
    6172                                .count   = build<SimpleCounter>("Count", group),
    6273                                .size    = build<AverageCounter<double>>("Average Size", 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)
     74                                .depth_a = build<AverageCounter<double>>("Average Depth", group),
     75                                .depth_m = build<MaxCounter<size_t>>("Max Depth", group),
    7176                        };
    7277                        return ret;
     
    7479        }
    7580
    76         Indexer::Indexer()
    77         : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(),
    78           prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; }
     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        }
    79248
    80249        Indexer::~Indexer() {
    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;
     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;
    109282        }
    110283
    111284        void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const {
    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                 }
     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 );
    122312        }
    123313
    124314        NamedTypeDecl *Indexer::lookupType( const std::string &id ) const {
    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;
     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 );
    130319        }
    131320
    132321        StructDecl *Indexer::lookupStruct( const std::string &id ) const {
    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;
     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 );
     326        }
     327
     328        NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
     329                return lookupTypeAtScope( id, 0 );
     330        }
     331
     332        StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
     333                return lookupStructAtScope( id, 0 );
     334        }
     335
     336        UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
     337                return lookupUnionAtScope( id, 0 );
     338        }
     339
     340        EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
     341                return lookupEnumAtScope( id, 0 );
    138342        }
    139343
    140344        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;
     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 );
    146349        }
    147350
    148351        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;
     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 );
    154356        }
    155357
    156358        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;
    172         }
    173 
    174         NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const {
    175                 return atScope( 0 )->lookupType( id );
    176         }
    177 
    178         StructDecl *Indexer::globalLookupStruct( const std::string &id ) const {
    179                 return atScope( 0 )->lookupStruct( id );
    180         }
    181 
    182         UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const {
    183                 return atScope( 0 )->lookupUnion( id );
    184         }
    185 
    186         EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const {
    187                 return atScope( 0 )->lookupEnum( id );
     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 );
    188468        }
    189469
     
    207487        }
    208488
    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
     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
    215491                assert( (isObject( added ) && isObject( existing.id ) )
    216492                        || ( isFunction( added ) && isFunction( existing.id ) ) );
    217493
    218                 if ( LinkageSpec::isOverridable( existing.id->linkage ) ) {
     494                if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) {
    219495                        // new definition shadows the autogenerated one, even at the same scope
    220496                        return false;
    221                 } else if ( LinkageSpec::isMangled( added->linkage )
    222                                 || ResolvExpr::typesCompatible(
    223                                         added->get_type(), existing.id->get_type(), Indexer() ) ) {
     497                } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) {
    224498
    225499                        // it is a conflict if one declaration is deleted and the other is not
    226500                        if ( deleteStmt && ! existing.deleteStmt ) {
    227                                 if ( handleConflicts.mode == OnConflict::Error ) {
    228                                         SemanticError( added, "deletion of defined identifier " );
    229                                 }
    230                                 return true;
     501                                return handleConflicts( existing, "deletion of defined identifier " );
    231502                        } else if ( ! deleteStmt && existing.deleteStmt ) {
    232                                 if ( handleConflicts.mode == OnConflict::Error ) {
    233                                         SemanticError( added, "definition of deleted identifier " );
    234                                 }
    235                                 return true;
     503                                return handleConflicts( existing, "definition of deleted identifier " );
    236504                        }
    237505
    238506                        if ( isDefinition( added ) && isDefinition( existing.id ) ) {
    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;
     507                                if ( isFunction( added ) ) {
     508                                        return handleConflicts( existing, "duplicate function definition for " );
     509                                } else {
     510                                        return handleConflicts( existing, "duplicate object definition for " );
     511                                } // if
    246512                        } // if
    247513                } else {
    248                         if ( handleConflicts.mode == OnConflict::Error ) {
    249                                 SemanticError( added, "duplicate definition for " );
    250                         }
    251                         return true;
     514                        return handleConflicts( existing, "duplicate definition for " );
    252515                } // if
    253516
     
    255518        }
    256519
    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                                         }
    358                                 } else {
    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
    432                 return true;
    433         }
    434 
    435         void Indexer::addId(
    436                         DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr,
    437                         BaseSyntaxNode * deleteStmt ) {
    438                 ++*stats().add_calls;
     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
    439525                const std::string &name = decl->name;
    440                 if ( name == "" ) return;
    441                
    442526                std::string mangleName;
    443527                if ( LinkageSpec::isOverridable( decl->linkage ) ) {
    444                         // mangle the name without including the appropriate suffix, so overridable routines
    445                         // are placed into the same "bucket" as their user defined versions.
     528                        // mangle the name without including the appropriate suffix, so overridable routines are placed into the
     529                        // same "bucket" as their user defined versions.
    446530                        mangleName = Mangler::mangle( decl, false );
    447531                } else {
     
    449533                } // if
    450534
    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 ) ) {
     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 ) ) {
     543                                SemanticError( decl, "conflicting overload of C function " );
     544                        }
     545                } else {
    454546                        // Check that a Cforall declaration doesn't override any C declaration
    455                         if ( hasCompatibleCDecl( name, mangleName ) ) {
     547                        if ( hasCompatibleCDecl( name, mangleName, scope ) ) {
    456548                                SemanticError( decl, "Cforall declaration hides C function " );
    457549                        }
    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 ) ) {
    462                                 SemanticError( decl, "conflicting overload of C function " );
    463                         }
    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) ) );
     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;
    508559        }
    509560
    510561        void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) {
    511562                // default handling of conflicts is to raise an error
    512                 addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
     563                addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr );
    513564        }
    514565
    515566        void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) {
    516567                // default handling of conflicts is to raise an error
    517                 addId( decl, OnConflict::error(), nullptr, deleteStmt );
     568                addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt );
    518569        }
    519570
     
    530581                        }
    531582                }
    532                 // does not need to be added to the table if both existing and added have a base that are
    533                 // the same
     583                // does not need to be added to the table if both existing and added have a base that are the same
    534584                return true;
    535585        }
    536586
    537587        void Indexer::addType( NamedTypeDecl *decl ) {
    538                 ++*stats().add_calls;
     588                debugPrint( "Adding type " << decl->name << std::endl );
     589                makeWritable();
     590
    539591                const std::string &id = decl->name;
    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 } );
     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                }
    554604        }
    555605
     
    564614
    565615        void Indexer::addStruct( const std::string &id ) {
     616                debugPrint( "Adding fwd decl for struct " << id << std::endl );
    566617                addStruct( new StructDecl( id ) );
    567618        }
    568619
    569620        void Indexer::addStruct( StructDecl *decl ) {
    570                 ++*stats().add_calls;
     621                debugPrint( "Adding struct " << decl->name << std::endl );
     622                makeWritable();
     623
    571624                const std::string &id = decl->name;
    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 } );
     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                }
    586637        }
    587638
    588639        void Indexer::addEnum( EnumDecl *decl ) {
    589                 ++*stats().add_calls;
     640                debugPrint( "Adding enum " << decl->name << std::endl );
     641                makeWritable();
     642
    590643                const std::string &id = decl->name;
    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 } );
     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                }
    605656        }
    606657
    607658        void Indexer::addUnion( const std::string &id ) {
     659                debugPrint( "Adding fwd decl for union " << id << std::endl );
    608660                addUnion( new UnionDecl( id ) );
    609661        }
    610662
    611663        void Indexer::addUnion( UnionDecl *decl ) {
    612                 ++*stats().add_calls;
     664                debugPrint( "Adding union " << decl->name << std::endl );
     665                makeWritable();
     666
    613667                const std::string &id = decl->name;
    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 } );
     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                }
    628680        }
    629681
    630682        void Indexer::addTrait( TraitDecl *decl ) {
    631                 ++*stats().add_calls;
     683                debugPrint( "Adding trait " << decl->name << std::endl );
     684                makeWritable();
     685
    632686                const std::string &id = decl->name;
    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 ) {
     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 ) {
    651702                for ( Declaration * decl : aggr->members ) {
    652703                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
     
    654705                                if ( dwt->name == "" ) {
    655706                                        Type * t = dwt->get_type()->stripReferences();
    656                                         if ( dynamic_cast<StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) {
     707                                        if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) {
    657708                                                Expression * base = expr->clone();
    658709                                                ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost?
     
    671722                                assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() );
    672723
    673                                 addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) );
     724                                addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) {
     725                                        // on conflict, delete the identifier
     726                                        existing.deleteStmt = withStmt;
     727                                        return true;
     728                                });
    674729                        }
    675730                }
     
    693748                addIds( ftype->returnVals );
    694749                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
    695810        }
    696811
  • src/SymTab/Indexer.h

    rf343c6b r69c37cc  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 21:38:55 2015
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Fri Mar  8 13:55:00 2019
    13 // Update Count     : 9
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Thu Aug 17 16:09:12 2017
     13// Update Count     : 8
    1414//
    1515
    1616#pragma once
    1717
    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
     18#include <iosfwd>             // for ostream
     19#include <list>               // for list
     20#include <string>             // for string
     21#include <functional>         // for function
    2222
    23 #include "Common/PersistentMap.h"  // for PersistentMap
    24 #include "SynTree/SynTree.h"       // for AST nodes
     23#include "SynTree/Visitor.h"  // for Visitor
     24#include "SynTree/SynTree.h"  // for AST nodes
    2525
    2626namespace ResolvExpr {
    27         class Cost;
     27class Cost;
    2828}
    2929
    3030namespace SymTab {
    31         class Indexer : public std::enable_shared_from_this<SymTab::Indexer> {
    32         public:
     31        class Indexer {
     32          public:
    3333                explicit Indexer();
     34
     35                Indexer( const Indexer &that );
     36                Indexer( Indexer &&that );
    3437                virtual ~Indexer();
     38                Indexer& operator= ( const Indexer &that );
     39                Indexer& operator= ( Indexer &&that );
    3540
    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
     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
    3843                void enterScope();
    3944                void leaveScope();
     
    4550                        /// non-null if this declaration is deleted
    4651                        BaseSyntaxNode * deleteStmt = nullptr;
    47                         /// scope of identifier
    48                         unsigned long scope = 0;
    4952
    5053                        // NOTE: shouldn't need either of these constructors, but gcc-4 does not properly support initializer lists with default members.
    5154                        IdData() = default;
    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 ) {}
     55                        IdData( DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ) {}
    5856
    5957                        Expression * combine( ResolvExpr::Cost & cost ) const;
     
    8280                EnumDecl *globalLookupEnum( const std::string &id ) const;
    8381
     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
    84100                void addId( DeclarationWithType * decl, Expression * baseExpr = nullptr );
    85101                void addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt );
     
    96112                void addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt );
    97113
     114                /// adds all of the members of the Aggregate (addWith helper)
     115                void addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction );
     116
    98117                /// convenience function for adding a list of Ids to the indexer
    99118                void addIds( const std::list< DeclarationWithType * > & decls );
     
    105124                void addFunctionType( FunctionType * ftype );
    106125
     126                bool doDebug = false; ///< Display debugging trace?
    107127          private:
    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
     128                struct Impl;
    113129
    114                         Scoped(Decl* d, unsigned long s) : decl(d), scope(s) {}
    115                 };
     130                Impl *tables;         ///< Copy-on-write instance of table data structure
     131                unsigned long scope;  ///< Scope index of this pointer
    116132
    117                 using Ptr = std::shared_ptr<const Indexer>;
     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 );
    118137
    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> >;
     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;
    126142
    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 );
     143                /// Ensures that tables variable is writable (i.e. allocated, uniquely owned by this Indexer, and at the current scope)
     144                void makeWritable();
    170145
    171146                /// common code for addId, addDeletedId, etc.
    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;
     147                void addId( DeclarationWithType * decl, ConflictFunction, Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr );
    183148        };
    184149} // namespace SymTab
  • src/SynTree/Attribute.cc

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

    rf343c6b r69c37cc  
    1818#include "Common/CodeLocation.h"
    1919#include "Common/Indenter.h"
    20 #include "Common/Stats.h"
    21 
    2220class Visitor;
    2321class Mutator;
     
    2523class BaseSyntaxNode {
    2624  public:
    27   static Stats::Counters::SimpleCounter* new_nodes;
    28 
    2925        CodeLocation location;
    30 
    31   BaseSyntaxNode() { ++*new_nodes; }
    32   BaseSyntaxNode( const BaseSyntaxNode& o ) : location(o.location) { ++*new_nodes; }
    3326
    3427        virtual ~BaseSyntaxNode() {}
  • src/SynTree/Constant.cc

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

    rf343c6b r69c37cc  
    211211                TypeDecl::Kind kind;
    212212                bool isComplete;
    213                
    214213                Data() : kind( (TypeDecl::Kind)-1 ), isComplete( false ) {}
    215214                Data( TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {}
    216215                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 
    220216                bool operator==(const Data & other) const { return kind == other.kind && isComplete == other.isComplete; }
    221217                bool operator!=(const Data & other) const { return !(*this == other);}
  • src/SynTree/Statement.h

    rf343c6b r69c37cc  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 12 09:01:53 2019
    13 // Update Count     : 83
     12// Last Modified On : Thu Mar  8 14:53:02 2018
     13// Update Count     : 78
    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, Statement * body, std::list<Statement *> & initialization, bool isDoWhile = false );
    226         WhileStmt( const WhileStmt & other );
     225        WhileStmt( Expression *condition,
     226               Statement *body, std::list<Statement *> & initialization, bool isDoWhile = false );
     227        WhileStmt( const WhileStmt &other );
    227228        virtual ~WhileStmt();
    228229
    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; }
     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; }
    233234        bool get_isDoWhile() { return isDoWhile; }
    234235        void set_isDoWhile( bool newValue ) { isDoWhile = newValue; }
    235236
    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;
     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;
    240241};
    241242
     
    243244  public:
    244245        std::list<Statement *> initialization;
    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 );
     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 );
    251253        virtual ~ForStmt();
    252254
    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;
     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;
    265267};
    266268
     
    272274        const Label originalTarget;
    273275        Label target;
    274         Expression * computedTarget;
     276        Expression *computedTarget;
    275277        Type type;
    276278
    277279        BranchStmt( Label target, Type ) throw (SemanticErrorException);
    278         BranchStmt( Expression * computedTarget, Type ) throw (SemanticErrorException);
     280        BranchStmt( Expression *computedTarget, Type ) throw (SemanticErrorException);
    279281
    280282        Label get_originalTarget() { return originalTarget; }
     
    282284        void set_target( Label newValue ) { target = newValue; }
    283285
    284         Expression * get_computedTarget() { return computedTarget; }
     286        Expression *get_computedTarget() { return computedTarget; }
    285287        void set_target( Expression * newValue ) { computedTarget = newValue; }
    286288
    287289        Type get_type() { return type; }
    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;
     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;
    294296  private:
    295         static const char * brType[];
     297        static const char *brType[];
    296298};
    297299
    298300class ReturnStmt : public Statement {
    299301  public:
    300         Expression * expr;
    301 
    302         ReturnStmt( Expression * expr );
    303         ReturnStmt( const ReturnStmt & other );
     302        Expression *expr;
     303
     304        ReturnStmt( Expression *expr );
     305        ReturnStmt( const ReturnStmt &other );
    304306        virtual ~ReturnStmt();
    305307
    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;
     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;
    313315};
    314316
     
    322324
    323325        ThrowStmt( Kind kind, Expression * expr, Expression * target = nullptr );
    324         ThrowStmt( const ThrowStmt & other );
     326        ThrowStmt( const ThrowStmt &other );
    325327        virtual ~ThrowStmt();
    326328
     
    331333        void set_target( Expression * newTarget ) { target = newTarget; }
    332334
    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;
     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;
    337339};
    338340
     
    343345        FinallyStmt * finallyBlock;
    344346
    345         TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt * finallyBlock = 0 );
    346         TryStmt( const TryStmt & other );
     347        TryStmt( CompoundStmt *tryBlock, std::list<CatchStmt *> &handlers, FinallyStmt *finallyBlock = 0 );
     348        TryStmt( const TryStmt &other );
    347349        virtual ~TryStmt();
    348350
    349         CompoundStmt * get_block() const { return block; }
    350         void set_block( CompoundStmt * newValue ) { block = newValue; }
     351        CompoundStmt *get_block() const { return block; }
     352        void set_block( CompoundStmt *newValue ) { block = newValue; }
    351353        std::list<CatchStmt *>& get_catchers() { return handlers; }
    352354
    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;
     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;
    360362};
    361363
     
    365367
    366368        const Kind kind;
    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 );
     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 );
    374376        virtual ~CatchStmt();
    375377
    376378        Kind get_kind() { return kind; }
    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;
     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;
    388390};
    389391
    390392class FinallyStmt : public Statement {
    391393  public:
    392         CompoundStmt * block;
    393 
    394         FinallyStmt( CompoundStmt * block );
    395         FinallyStmt( const FinallyStmt & other );
     394        CompoundStmt *block;
     395
     396        FinallyStmt( CompoundStmt *block );
     397        FinallyStmt( const FinallyStmt &other );
    396398        virtual ~FinallyStmt();
    397399
    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;
     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;
    405407};
    406408
     
    436438        } orelse;
    437439
    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;
     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;
    442444
    443445};
     
    462464class DeclStmt : public Statement {
    463465  public:
    464         Declaration * decl;
    465 
    466         DeclStmt( Declaration * decl );
    467         DeclStmt( const DeclStmt & other );
     466        Declaration *decl;
     467
     468        DeclStmt( Declaration *decl );
     469        DeclStmt( const DeclStmt &other );
    468470        virtual ~DeclStmt();
    469471
    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.
     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.
    482485class ImplicitCtorDtorStmt : public Statement {
    483486  public:
     
    489492        virtual ~ImplicitCtorDtorStmt();
    490493
    491         Statement * get_callStmt() const { return callStmt; }
     494        Statement *get_callStmt() const { return callStmt; }
    492495        void set_callStmt( Statement * newValue ) { callStmt = newValue; }
    493496
    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;
     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;
    498501};
    499502
  • src/main.cc

    rf343c6b r69c37cc  
    6565using namespace std;
    6666
     67
    6768void NewPass(const char * const name) {
    6869        Stats::Heap::newPass(name);
    6970        using namespace Stats::Counters;
    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         }
     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);
    8476}
    8577
  • tests/.expect/KRfunctions.x64.txt

    rf343c6b r69c37cc  
    8282    signed int _X1ai_2;
    8383    signed int _X1bi_2;
    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) /* ^?{} */);
     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) /* ^?{} */);
    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

    rf343c6b r69c37cc  
    8282    signed int _X1ai_2;
    8383    signed int _X1bi_2;
    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) /* ^?{} */);
     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) /* ^?{} */);
    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

    rf343c6b r69c37cc  
    1 completeTypeError.cfa:34:1 error: Cannot choose between 2 alternatives for expression
    2 Generated Cast of:
    3   Applying untyped:
    4     Name: *?
    5   ...to:
    6     Name: x
     1completeTypeError.cfa:33:1 error: No reasonable alternatives for expression Applying untyped:
     2  Name: *?
     3...to:
     4  Name: v
    75
    8 ... to: nothing Alternatives are:
    9 Cost ( 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 
    32 Cost ( 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 
     6completeTypeError.cfa:34:1 error: No reasonable alternatives for expression Applying untyped:
     7  Name: *?
     8...to:
     9  Name: y
    5510
    5611completeTypeError.cfa:35:1 error: No reasonable alternatives for expression Applying untyped:
     
    6924  Name: v
    7025
    71 completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped:
     26completeTypeError.cfa:58:1 error: No reasonable alternatives for expression Applying untyped:
    7227  Name: baz
    7328...to:
    7429  Name: y
    7530
    76 completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped:
     31completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped:
    7732  Name: quux
    7833...to:
    7934  Name: y
    8035
    81 completeTypeError.cfa:72:1 error: No alternatives with satisfiable assertions for Applying untyped:
     36completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped:
     37  Name: *?
     38...to:
     39  Name: y
     40
     41completeTypeError.cfa:72:1 error: No resolvable alternatives for expression Applying untyped:
    8242  Name: baz
    8343...to:
    8444  Name: z
    8545
    86    Unsatisfiable alternative:
     46Alternatives with failing assertions are:
    8747Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
    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
     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
    9959
    10060
    101              ?{}: pointer to function
    102              ... with parameters
    103                reference to instance of type T (not function type)
    104              ... returning nothing
     61         ?{}: pointer to function
     62         ... with parameters
     63           reference to instance of type T (not function type)
     64         ... returning nothing
    10565
    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
     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
    11171
    112              ^?{}: pointer to function
    113              ... with parameters
    114                reference to instance of type T (not function type)
    115              ... returning nothing
     72         ^?{}: pointer to function
     73         ... with parameters
     74           reference to instance of type T (not function type)
     75         ... returning nothing
    11676
    11777
    118            function
    119          ... with parameters
    120            pointer to instance of type T (not function type)
    121          ... returning nothing
     78       function
     79     ... with parameters
     80       pointer to instance of type T (not function type)
     81     ... returning nothing
    12282
    123        ... to arguments
    124          Variable Expression: z: pointer to instance of type T (not function type)
     83   ... to arguments
     84     Variable Expression: z: pointer to instance of type T (not function type)
    12585
    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
     86 (types:
     87   void
     88 )
     89 Environment:( _74_0_T ) -> instance of type T (not function type) (no widening)
    14090
    14191
     92
  • tests/.expect/declarationSpecifier.x64.txt

    rf343c6b r69c37cc  
    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_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) /* ^?{} */);
     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) /* ^?{} */);
    703703    return _X12_retval_maini_1;
    704704}
  • tests/.expect/declarationSpecifier.x86.txt

    rf343c6b r69c37cc  
    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_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) /* ^?{} */);
     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) /* ^?{} */);
    703703    return _X12_retval_maini_1;
    704704}
  • tests/.expect/extension.x64.txt

    rf343c6b r69c37cc  
    186186    __extension__ signed int _X1ci_2;
    187187    ((void)(__extension__ _X1ai_2=(__extension__ _X1bi_2+__extension__ _X1ci_2)));
    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) /* ^?{} */);
     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) /* ^?{} */);
    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

    rf343c6b r69c37cc  
    186186    __extension__ signed int _X1ci_2;
    187187    ((void)(__extension__ _X1ai_2=(__extension__ _X1bi_2+__extension__ _X1ci_2)));
    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) /* ^?{} */);
     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) /* ^?{} */);
    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

    rf343c6b r69c37cc  
    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_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) /* ^?{} */);
     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) /* ^?{} */);
    176176    return _X12_retval_maini_1;
    177177}
  • tests/.expect/gccExtensions.x86.txt

    rf343c6b r69c37cc  
    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_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) /* ^?{} */);
     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) /* ^?{} */);
    176176    return _X12_retval_maini_1;
    177177}
  • tests/.expect/loopctrl.txt

    rf343c6b r69c37cc  
    191910 8 6 4 2
    2020
    21 1 2 3 4 5 6 7 8 9 10
    22 10 9 8 7 6 5 4 3 2 1 0
    23212 4 6 8 10
    24222.1 3.8 5.5 7.2 8.9
     
    4442(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)
    4543(10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0)
    46 
    47 0 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4
    48 0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14
    49 0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13
    50 0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23
    51 
    52 0 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 4
    53 0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -14
    54 0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 13
    55 0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -23
    56 
    57 0 -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
    58 0 -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
    59 0 -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

    rf343c6b r69c37cc  
    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 \ 2 = 256
    13 912673 256 64 -64 0 0
    14 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
    15 0 0 18.3791736799526 0.264715-1.1922i
    16 16
    17 4 16
     12\ 16 256
     13\ 912673 256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i
  • tests/Makefile.am

    rf343c6b r69c37cc  
    2828timeouts=
    2929
    30 TEST_PY = python3 ${builddir}/test.py
     30TEST_PY = python ${builddir}/test.py
    3131
    3232# applies to both programs
     
    3636        -Wno-unused-function \
    3737        -quiet @CFA_FLAGS@ \
    38         -DIN_DIR="${abs_srcdir}/.in/"
     38        -DIN_DIR="${srcdir}/.in/"
    3939
    4040AM_CFLAGS += ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS}
    4141CC = @CFACC@
    4242
    43 PRETTY_PATH=mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
     43PRETTY_PATH=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/CPP rules so pretend like we have a C program
    51 _dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp
     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
    5252
    5353#----------------------------------------------------------------------------------------------------------------
     
    7474        @echo "int main() { return 0; }" > ${@}
    7575
    76 .dummy_hackxx.cpp:
    77         @echo "int bar() { return 0; }" > ${@}
    78 
    7976concurrency :
    8077        @+${TEST_PY} --debug=${debug}  --install=${installed} -Iconcurrent
     
    8279#----------------------------------------------------------------------------------------------------------------
    8380
    84 # Use for all tests, make sure the path are correct and all flags are added
    85 CFACOMPILETEST=$(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
    88 CFATEST_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
    91 CFATEST_STDERR=$(CFACOMPILETEST) 2> $(abspath ${@})
    92 
    93 #----------------------------------------------------------------------------------------------------------------
    94 
    9581# implicit rule so not all test require a rule
    9682% : %.cfa $(CFACC)
    97         $(CFATEST_STDOUT)
     83        $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    9884
    99 % : %.cpp
    100         $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     85declarationSpecifier: declarationSpecifier.cfa $(CFACC)
     86        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    10187
    102 #------------------------------------------------------------------------------
    103 # TARGET WITH STANDARD RULE BUT CUSTOM FLAGS
    104 #------------------------------------------------------------------------------
    105 # Expected failures
    106 declarationSpecifier_FLAGS= -CFA -XCFA -p
    107 gccExtensions_FLAGS= -CFA -XCFA -p
    108 extension_FLAGS= -CFA -XCFA -p
    109 attributes_FLAGS= -CFA -XCFA -p
    110 functions_FLAGS= -CFA -XCFA -p
    111 KRfunctions_FLAGS= -CFA -XCFA -p
    112 gmp_FLAGS= -lgmp
     88gccExtensions : gccExtensions.cfa $(CFACC)
     89        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    11390
    114 #------------------------------------------------------------------------------
    115 # Expected failures
    116 completeTypeError_FLAGS= -DERR1
     91extension : extension.cfa $(CFACC)
     92        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    11793
    118 #------------------------------------------------------------------------------
    119 # CUSTOM TARGET
    120 #------------------------------------------------------------------------------
    121 typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
    122         $(CFATEST_STDOUT) -DERR1
     94attributes : attributes.cfa $(CFACC)
     95        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    12396
    124 alloc-ERROR: alloc.cfa $(CFACC)
    125         $(CFATEST_STDOUT) -DERR1
     97functions: functions.cfa $(CFACC)
     98        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    12699
    127 nested-types-ERR1: nested-types.cfa $(CFACC)
    128         $(CFATEST_STDOUT) -DERR1
     100KRfunctions : KRfunctions.cfa $(CFACC)
     101        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    129102
    130 nested-types-ERR2: nested-types.cfa $(CFACC)
    131         $(CFATEST_STDOUT) -DERR2
     103sched-ext-parse : sched-ext-parse.c $(CFACC)
     104        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    132105
    133 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
    134         $(CFATEST_STDOUT) -DERR1
    135 
    136 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
    137         $(CFATEST_STDOUT) -DERR2
    138 
    139 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
    140         $(CFATEST_STDOUT) -DERR1
    141 
    142 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
    143         $(CFATEST_STDOUT) -DERR1
     106gmp : gmp.cfa $(CFACC)
     107        $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    144108
    145109#builtins
    146110builtins/sync: builtins/sync.cfa $(CFACC)
    147         $(CFATEST_STDERR) -fsyntax-only
     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
     116completeTypeError : completeTypeError.cfa $(CFACC)
     117        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     118
     119typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
     120        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     121
     122alloc-ERROR: alloc.cfa $(CFACC)
     123        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     124
     125fallthrough-ERROR: fallthrough.cfa $(CFACC)
     126        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     127
     128nested-types-ERR1: nested-types.cfa $(CFACC)
     129        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     130
     131nested-types-ERR2: nested-types.cfa $(CFACC)
     132        $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     133
     134# Constructor/destructor tests
     135raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
     136        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     137
     138raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
     139        $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     140
     141raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
     142        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     143
     144raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
     145        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    148146
    149147# Warnings
    150148warnings/self-assignment: warnings/self-assignment.cfa $(CFACC)
    151         $(CFATEST_STDERR) -fsyntax-only
     149        $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
  • tests/Makefile.in

    rf343c6b r69c37cc  
    107107CONFIG_CLEAN_FILES = config.py
    108108CONFIG_CLEAN_VPATH_FILES = test.py
    109 am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT) .dummy_hackxx.$(OBJEXT)
     109am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT)
    110110_dummy_hack_OBJECTS = $(am__dummy_hack_OBJECTS)
    111111_dummy_hack_LDADD = $(LDADD)
     
    155155am__v_CCLD_0 = @echo "  CCLD    " $@;
    156156am__v_CCLD_1 =
    157 CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
    158         $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
    159 LTCXXCOMPILE = $(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)
    163 AM_V_CXX = $(am__v_CXX_@AM_V@)
    164 am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
    165 am__v_CXX_0 = @echo "  CXX     " $@;
    166 am__v_CXX_1 =
    167 CXXLD = $(CXX)
    168 CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
    169         $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
    170         $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
    171 AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
    172 am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
    173 am__v_CXXLD_0 = @echo "  CXXLD   " $@;
    174 am__v_CXXLD_1 =
    175157SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES)
    176158DIST_SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES)
     
    378360concurrent =
    379361timeouts =
    380 TEST_PY = python3 ${builddir}/test.py
     362TEST_PY = python ${builddir}/test.py
    381363
    382364# applies to both programs
    383365AM_CFLAGS = $(if $(test), 2> $(test), ) -g -Wall -Wno-unused-function \
    384         -quiet @CFA_FLAGS@ -DIN_DIR="${abs_srcdir}/.in/" \
    385         ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS}
    386 PRETTY_PATH = mkdir -p $(dir $(abspath ${@})) && cd ${srcdir} &&
     366        -quiet @CFA_FLAGS@ -DIN_DIR="${srcdir}/.in/" ${DEBUG_FLAGS} \
     367        ${INSTALL_FLAGS} ${ARCH_FLAGS}
     368PRETTY_PATH = cd ${srcdir} &&
    387369avl_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
    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
    394 CFACOMPILETEST = $(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
    397 CFATEST_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
    400 CFATEST_STDERR = $(CFACOMPILETEST) 2> $(abspath ${@})
    401 
    402 #------------------------------------------------------------------------------
    403 # TARGET WITH STANDARD RULE BUT CUSTOM FLAGS
    404 #------------------------------------------------------------------------------
    405 # Expected failures
    406 declarationSpecifier_FLAGS = -CFA -XCFA -p
    407 gccExtensions_FLAGS = -CFA -XCFA -p
    408 extension_FLAGS = -CFA -XCFA -p
    409 attributes_FLAGS = -CFA -XCFA -p
    410 functions_FLAGS = -CFA -XCFA -p
    411 KRfunctions_FLAGS = -CFA -XCFA -p
    412 gmp_FLAGS = -lgmp
    413 
    414 #------------------------------------------------------------------------------
    415 # Expected failures
    416 completeTypeError_FLAGS = -DERR1
     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
    417372all: all-am
    418373
    419374.SUFFIXES:
    420 .SUFFIXES: .c .cfa .cpp .dummy_hack .dummy_hackxx .lo .o .obj .validate
     375.SUFFIXES: .c .cfa .dummy_hack .lo .o .obj .validate
    421376$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/src/cfa.make $(am__configure_deps)
    422377        @for dep in $?; do \
     
    454409.dummy_hack$(EXEEXT): $(_dummy_hack_OBJECTS) $(_dummy_hack_DEPENDENCIES) $(EXTRA__dummy_hack_DEPENDENCIES)
    455410        @rm -f .dummy_hack$(EXEEXT)
    456         $(AM_V_CXXLD)$(CXXLINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS)
     411        $(AM_V_CCLD)$(LINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS)
    457412avltree/$(am__dirstamp):
    458413        @$(MKDIR_P) avltree
     
    488443
    489444@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@
    491445
    492446.c.o:
     
    513467@AMDEP_TRUE@@am__fastdepCC_FALSE@       DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
    514468@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 $@ $<
    539469
    540470mostlyclean-libtool:
     
    787717        @echo "int main() { return 0; }" > ${@}
    788718
    789 .dummy_hackxx.cpp:
    790         @echo "int bar() { return 0; }" > ${@}
    791 
    792719concurrency :
    793720        @+${TEST_PY} --debug=${debug}  --install=${installed} -Iconcurrent
     
    797724# implicit rule so not all test require a rule
    798725% : %.cfa $(CFACC)
    799         $(CFATEST_STDOUT)
    800 
    801 % : %.cpp
    802         $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    803 
    804 #------------------------------------------------------------------------------
    805 # CUSTOM TARGET
    806 #------------------------------------------------------------------------------
    807 typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
    808         $(CFATEST_STDOUT) -DERR1
    809 
    810 alloc-ERROR: alloc.cfa $(CFACC)
    811         $(CFATEST_STDOUT) -DERR1
    812 
    813 nested-types-ERR1: nested-types.cfa $(CFACC)
    814         $(CFATEST_STDOUT) -DERR1
    815 
    816 nested-types-ERR2: nested-types.cfa $(CFACC)
    817         $(CFATEST_STDOUT) -DERR2
    818 
    819 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
    820         $(CFATEST_STDOUT) -DERR1
    821 
    822 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
    823         $(CFATEST_STDOUT) -DERR2
    824 
    825 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
    826         $(CFATEST_STDOUT) -DERR1
    827 
    828 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
    829         $(CFATEST_STDOUT) -DERR1
     726        $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     727
     728declarationSpecifier: declarationSpecifier.cfa $(CFACC)
     729        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     730
     731gccExtensions : gccExtensions.cfa $(CFACC)
     732        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     733
     734extension : extension.cfa $(CFACC)
     735        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     736
     737attributes : attributes.cfa $(CFACC)
     738        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     739
     740functions: functions.cfa $(CFACC)
     741        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     742
     743KRfunctions : KRfunctions.cfa $(CFACC)
     744        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     745
     746sched-ext-parse : sched-ext-parse.c $(CFACC)
     747        $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     748
     749gmp : gmp.cfa $(CFACC)
     750        $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    830751
    831752#builtins
    832753builtins/sync: builtins/sync.cfa $(CFACC)
    833         $(CFATEST_STDERR) -fsyntax-only
     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
     759completeTypeError : completeTypeError.cfa $(CFACC)
     760        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     761
     762typedefRedef-ERR1: typedefRedef.cfa $(CFACC)
     763        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     764
     765alloc-ERROR: alloc.cfa $(CFACC)
     766        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     767
     768fallthrough-ERROR: fallthrough.cfa $(CFACC)
     769        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     770
     771nested-types-ERR1: nested-types.cfa $(CFACC)
     772        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     773
     774nested-types-ERR2: nested-types.cfa $(CFACC)
     775        $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     776
     777# Constructor/destructor tests
     778raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC)
     779        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     780
     781raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC)
     782        $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     783
     784raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC)
     785        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
     786
     787raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC)
     788        $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})
    834789
    835790# Warnings
    836791warnings/self-assignment: warnings/self-assignment.cfa $(CFACC)
    837         $(CFATEST_STDERR) -fsyntax-only
     792        $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only
    838793
    839794# Tell versions [3.59,3.63) of GNU make to not export all variables.
  • tests/completeTypeError.cfa

    rf343c6b r69c37cc  
    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         *y;
     21        *x; // picks B
    2222        *z;
    2323        foo(i);
     
    3232        // bad
    3333        *v;
    34         *x;     // ambiguous
     34        *y;
    3535        foo(v);
    3636        baz(v);
     
    5252void qux(T * y) {
    5353        // okay
    54         *y;
    5554        bar(y);
    5655        qux(y);
     
    5958        baz(y);
    6059        quux(y);
     60        *y;
    6161}
    6262
  • tests/concurrent/examples/boundedBufferEXT.cfa

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

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

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

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

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

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

    rf343c6b r69c37cc  
    1616difi  ed B  y :   Pete  r A. 
    1717 Buh  r//   Last   Mod  ifie 
    18 d On   : F  ri M  ar 2  2 1
    19 :41:  03 2  019/  / Up  date 
    20  Cou  nt       :   33/  /#in 
     18d On   : T  ue D  ec 1  1 2
     19:31:  12 2  018/  / Up  date 
     20 Cou  nt       :   32/  /#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.cf  a" /  ///   End:   //
     78s.c"   ///  / En  d: /  /
  • tests/coroutine/.in/fmtLines.txt

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

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

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

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

    rf343c6b r69c37cc  
    1010// Created On       : Wed Sep 20 11:55:23 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 26 17:54:14 2019
    13 // Update Count     : 35
     12// Last Modified On : Tue Dec 11 21:58:06 2018
     13// Update Count     : 29
    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.[name, N] = [name, N];  &this.part = &part;
     26        (this.__cor){name};
     27        this.name = name;
     28        this.N = N;
     29        this.part = &part;
    2730}
    2831void ?{}( PingPong & this, const char * name, unsigned int N ) {
    29         this{ name, N, *0p };                                                           // call first constructor
     32        this{ name, N, *(PingPong *)0 };
    3033}
    3134void cycle( PingPong & pingpong ) {
     
    3336}
    3437void partner( PingPong & this, PingPong & part ) {
    35         &this.part = &part;
     38        this.part = &part;
    3639        resume( this );
    3740}
    38 void 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 );
     41void 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 );
    4245        } // for
    4346}
     
    5053// Local Variables: //
    5154// tab-width: 4 //
    52 // compile-command: "cfa pingpong.cfa" //
     55// compile-command: "cfa pingpong.c" //
    5356// End: //
  • tests/coroutine/prodcons.cfa

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

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

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

    rf343c6b r69c37cc  
    1010// Created On       : Fri Aug 25 15:21:11 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Apr 11 18:27:45 2019
    13 // Update Count     : 10
     12// Last Modified On : Tue Dec  4 21:37:09 2018
     13// Update Count     : 9
    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

    rf343c6b r69c37cc  
    1010// Created On       : Wed Mar  2 16:56:02 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Apr 18 08:03:30 2019
    13 // Update Count     : 113
     12// Last Modified On : Fri Dec 21 08:20:14 2018
     13// Update Count     : 112
    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

    rf343c6b r69c37cc  
    1010// Created On       : Wed Aug  8 18:32:59 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Apr 13 11:03:09 2019
    13 // Update Count     : 104
     12// Last Modified On : Thu Feb 21 08:54:47 2019
     13// Update Count     : 86
    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;
    6758        for ( i; 2 ~ @ ~ 2 ) {
    6859          if ( i > 10 ) break;
     
    10394        for ( s; (S){10,10} -~ (S){0} ~ (S){1} ) { sout | s; } sout | nl;
    10495        for ( s; (S){10,10} -~= (S){0} ) { 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;
     96        for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { sout | s; } sout | nl;
    12097}
    12198
  • tests/math1.cfa

    rf343c6b r69c37cc  
    1010// Created On       : Fri Apr 22 14:59:21 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 25 22:56:47 2019
    13 // Update Count     : 109
     12// Last Modified On : Wed Dec 12 16:28:49 2018
     13// Update Count     : 89
    1414//
    1515
     
    4949        unsigned int e = 2;
    5050    b \= e;
    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);
     51    sout | "\\" | b | b \ e;
     52    sout | "\\" | 'a' \ 3u | 2 \ 8u | 4 \ 3u | -4 \ 3u | nonl;
    5453        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;
    6654} // main
    6755
  • tests/pybin/settings.py

    rf343c6b r69c37cc  
     1from __future__ import print_function
     2
    13import os
    2 import subprocess
    34import sys
    4 from . import tools
     5import tools
    56
    67try :
     
    3839        def __init__(self, arch):
    3940                try:
    40                         canonical_host = Architecture.make_canonical( config.HOSTARCH )
     41                        canonical_host = Architecture.makeCanonical( config.HOSTARCH )
    4142                except KeyError:
    4243                        print("Unkown host architecture %s" % config.HOSTARCH, file=sys.stderr)
     
    4546                if arch:
    4647                        try:
    47                                 arch = Architecture.make_canonical( arch )
     48                                arch = Architecture.makeCanonical( arch )
    4849                        except KeyError:
    4950                                print("Unkown architecture %s" % arch, file=sys.stderr)
     
    7677
    7778        @classmethod
    78         def make_canonical(_, arch):
     79        def makeCanonical(_, arch):
    7980                return Architecture.KnownArchitectures[arch]
    8081
     
    8384        def __init__(self, value):
    8485                self.string = "debug" if value else "no debug"
    85                 self.flags  = """DEBUG_FLAGS=%s""" % ("-debug -O0" if value else "-nodebug -O2")
     86                self.flags  = """DEBUG_FLAGS="%s" """ % ("-debug -O0" if value else "-nodebug -O2")
    8687
    8788class Install:
    8889        def __init__(self, value):
    8990                self.string = "installed" if value else "in-tree"
    90                 self.flags  = """INSTALL_FLAGS=%s""" % ("" if value else "-in-tree")
     91                self.flags  = """INSTALL_FLAGS="%s" """ % ("" if value else "-in-tree")
    9192
    9293class Timeouts:
     
    111112        global install
    112113        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)
    122         output_width = 24
     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)
    123122
    124123
    125 def update_make_cmd(force, jobs):
     124def updateMakeCmd(force, jobs):
    126125        global make
    127126
    128         make = ['make'] if not force else ['make', "-j%i" % jobs]
     127        make = "make" if not force else ("make -j%i" % jobs)
    129128
    130129def validate():
    131130        errf = os.path.join(BUILDDIR, ".validate.err")
    132         make_ret, out = tools.make( ".validate", error_file = errf, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
     131        make_ret, _ = tools.make( ".validate", error_file = errf, redirects  = "2> /dev/null 1> /dev/null", )
    133132        if make_ret != 0:
    134133                with open (errf, "r") as myfile:
     
    140139
    141140        tools.rm(errf)
    142 
    143 def prep_output(tests):
    144         global output_width
    145         output_width = max(map(lambda t: len(t.target()), tests))
  • tests/pybin/test_run.py

    rf343c6b r69c37cc  
    44
    55import pybin.settings
     6import datetime
     7
     8from string import Template
     9
     10class DeltaTemplate(Template):
     11    delimiter = "%"
     12
     13def 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)
    618
    719# Test class that defines what a test is
  • tests/pybin/tools.py

    rf343c6b r69c37cc  
     1from __future__ import print_function
     2
    13import __main__
    24import argparse
    3 import contextlib
    45import fileinput
    56import multiprocessing
     
    910import signal
    1011import stat
    11 import subprocess
    1212import sys
    13 import tempfile
    1413import time
    15 import types
    1614
    1715from pybin import settings
     16from subprocess import Popen, PIPE, STDOUT
    1817
    1918################################################################################
     
    2221
    2322# helper functions to run terminal commands
    24 def sh(*cmd, timeout = False, output = None, input = None, error = subprocess.STDOUT):
    25         cmd = list(cmd)
     23def sh(cmd, print2stdout = True, input = None):
     24        # add input redirection if needed
     25        if input and os.path.isfile(input):
     26                cmd += " < %s" % input
    2627
    2728        # if this is a dry_run, only print the commands that would be ran
    2829        if settings.dry_run :
    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)
     30                print("cmd: %s" % cmd)
    4331                return 0, None
    4432
    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)
     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
    6738
    6839def is_ascii(fname):
     
    7445                return False
    7546
    76         code, out = sh("file %s" % fname, output=subprocess.PIPE)
     47        code, out = sh("file %s" % fname, print2stdout = False)
    7748        if code != 0:
    7849                return False
     
    8455
    8556        return match.group(1).startswith("ASCII text")
    86 
    87 def is_exe(fname):
    88         return os.path.isfile(fname) and os.access(fname, os.X_OK)
    89 
    90 def 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
    10357
    10458# Remove 1 or more files silently
    10559def rm( files ):
    106         if isinstance(files, str ): files = [ files ]
    107         for file in files:
    108                 sh( 'rm', '-f', file, output=subprocess.DEVNULL, error=subprocess.DEVNULL )
     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 )
    10965
    11066# Create 1 or more directory
    11167def mkdir( files ):
    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 )
     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) )
    11773
    11874
     
    12480# diff two files
    12581def 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
    126100        # fetch return code and error from the diff command
    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         )
     101        return sh(diff_cmd % (lhs, rhs), False)
    141102
    142103# call make
    143 def 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,
     104def 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 '',
    148109                test_param,
    149110                settings.arch.flags,
     
    151112                settings.install.flags,
    152113                flags,
    153                 target
    154         ]
    155         cmd = [s for s in cmd if s]
    156         return sh(*cmd, output=output, error=error)
     114                target,
     115                redirects
     116        ])
     117        return sh(cmd)
    157118
    158119def which(program):
     120    import os
     121    def is_exe(fpath):
     122        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
     123
    159124    fpath, fname = os.path.split(program)
    160125    if fpath:
     
    169134    return None
    170135
    171 @contextlib.contextmanager
    172 def 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)
     136def run(exe, output, input):
     137        ret, _ = sh("timeout %d %s > %s 2>&1" % (settings.timeout.single, exe, output), input = input)
     138        return ret
    180139
    181140################################################################################
     
    184143# move a file
    185144def mv(source, dest):
    186         ret, _ = sh("mv", source, dest)
     145        ret, _ = sh("mv %s %s" % (source, dest))
    187146        return ret
    188147
    189148# cat one file into the other
    190149def cat(source, dest):
    191         ret, _ = sh("cat", source, output=dest)
     150        ret, _ = sh("cat %s > %s" % (source, dest))
    192151        return ret
    193152
     
    204163
    205164# helper function to check if a files contains only a specific string
    206 def file_contains_only(file, text) :
     165def fileContainsOnly(file, text) :
    207166        with open(file) as f:
    208167                ff = f.read().strip()
    209168                result = ff == text.strip()
    210169
    211                 return result
     170                return result;
     171
     172# check whether or not a file is executable
     173def 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
    212182
    213183# transform path to canonical form
    214 def canonical_path(path):
     184def canonicalPath(path):
    215185        abspath = os.path.abspath(__main__.__file__)
    216186        dname = os.path.dirname(abspath)
     
    218188
    219189# compare path even if form is different
    220 def path_cmp(lhs, rhs):
    221         return canonical_path( lhs ) == canonical_path( rhs )
     190def pathCmp(lhs, rhs):
     191        return canonicalPath( lhs ) == canonicalPath( rhs )
    222192
    223193# walk all files in a path
    224 def path_walk( op ):
    225         dname = settings.SRCDIR
    226         for dirname, _, names in os.walk(dname):
     194def pathWalk( op ):
     195        def step(_, dirname, names):
    227196                for name in names:
    228197                        path = os.path.join(dirname, name)
    229198                        op( path )
    230199
     200        # Start the walk
     201        dname = settings.SRCDIR
     202        os.path.walk(dname, step, '')
     203
    231204################################################################################
    232205#               system
    233206################################################################################
    234207# count number of jobs to create
    235 def job_count( options, tests ):
     208def jobCount( options, tests ):
    236209        # check if the user already passed in a number of jobs for multi-threading
    237210        if not options.jobs:
     
    255228        return min( options.jobs, len(tests) ), force
    256229
     230# setup a proper processor pool with correct signal handling
     231def 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
     239class 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
    257249# enable core dumps for all the test children
    258250resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY))
     
    269261                return False
    270262        raise argparse.ArgumentTypeError(msg)
     263        return False
    271264
    272265def fancy_print(text):
    273266        column = which('column')
    274267        if column:
    275                 subprocess.run(column, input=bytes(text + "\n", "UTF-8"))
     268                cmd = "%s 2> /dev/null" % column
     269                proc = Popen(cmd, stdin=PIPE, stderr=None, shell=True)
     270                proc.communicate(input=text + "\n")
    276271        else:
    277272                print(text)
    278273
    279274
    280 def core_info(path):
    281         if not os.path.isfile(path):
    282                 return 1, "ERR Executable path is wrong"
    283 
     275def coreInfo(path):
    284276        cmd   = os.path.join(settings.SRCDIR, "pybin/print-core.gdb")
    285277        if not os.path.isfile(cmd):
    286278                return 1, "ERR Printing format for core dumps not found"
    287279
    288         core  = os.path.join(os.getcwd(), "core" )
     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"
    289284
    290285        if not os.path.isfile(core):
    291286                return 1, "ERR No core dump"
    292287
    293         return sh('gdb', '-n', path, core, '-batch', '-x', cmd, output=subprocess.PIPE)
     288        return sh("gdb -n %s %s -batch -x %s" % (path, core, cmd), print2stdout=False)
    294289
    295290class Timed:
  • tests/raii/init_once.cfa

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

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

    rf343c6b r69c37cc  
    1 #!/usr/bin/python3
     1#!/usr/bin/python
     2from __future__ import print_function
    23
    34from pybin.tools import *
     
    89import re
    910import sys
    10 import tempfile
    1111import time
    1212
     
    1515################################################################################
    1616
    17 def find_tests():
     17def findTests():
    1818        expected = []
    1919
    20         def match_test(path):
     20        def matchTest(path):
    2121                match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path)
    2222                if match :
     
    2828                                expected.append(test)
    2929
    30         path_walk( match_test )
     30        pathWalk( matchTest )
    3131
    3232        return expected
    3333
    3434# reads the directory ./.expect and indentifies the tests
    35 def list_tests( includes, excludes ):
     35def listTests( includes, excludes ):
    3636        # tests directly in the .expect folder will always be processed
    37         test_list = find_tests()
     37        test_list = findTests()
    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 valid_tests( options ):
     54def validTests( options ):
    5555        tests = []
    5656
     
    5959        if options.regenerate_expected :
    6060                for testname in options.tests :
    61                         testname = canonical_path( testname )
     61                        testname = canonicalPath( testname )
    6262                        if Test.valid_name(testname):
    63                                 found = [test for test in all_tests if canonical_path( test.target() ) == testname]
     63                                found = [test for test in allTests if canonicalPath( 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 all_tests if path_cmp( t.target(), testname )]
     71                        test = [t for t in allTests if pathCmp( t.target(), testname )]
    7272
    7373                        if test :
     
    7979
    8080# parses the option
    81 def parse_args():
     81def getOptions():
    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 no_rule(file, target):
    127         return not settings.dry_run and file_contains_only(file, "make: *** No rule to make target `%s'.  Stop." % target)
     126def isExe(file):
     127        return settings.dry_run or fileIsExecutable(file)
     128
     129def noRule(file, target):
     130        return not settings.dry_run and fileContainsOnly(file, "make: *** No rule to make target `%s'.  Stop." % target)
    128131
    129132# logic to run a single test and return the result (No handling of printing or other test framework logic)
     
    142145        # build, skipping to next test on error
    143146        with Timed() as comp_dur:
    144                 make_ret, _ = make( test.target(), output=subprocess.DEVNULL, error=out_file, error_file = err_file )
    145 
     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
    146150        run_dur = None
    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
     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)
    170156                        else :
    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
     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
    180181
    181182
     
    188189# run a single test and handle the errors, outputs, printing, exception handling, etc.
    189190def run_test_worker(t) :
    190         try :
     191
     192        with SignalHandling():
    191193                # print formated name
    192                 name_txt = '{0:{width}}  '.format(t.target(), width=settings.output_width)
     194                name_txt = "%24s  " % t.name
    193195
    194196                retcode, error, duration = run_single_test(t)
     
    198200
    199201                #print result with error if needed
    200                 text = '\t' + name_txt + result_txt
     202                text = name_txt + result_txt
    201203                out = sys.stdout
    202204                if error :
    203                         text = text + '\n' + error
     205                        text = text + "\n" + error
    204206                        out = sys.stderr
    205207
     
    208210                sys.stderr.flush()
    209211
    210                 return retcode != TestResult.SUCCESS
    211         except KeyboardInterrupt:
    212                 False
     212        return retcode != TestResult.SUCCESS
    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', output=subprocess.DEVNULL, error=subprocess.DEVNULL)
     217        make('clean', redirects = '> /dev/null 2>&1')
    218218
    219219        # create the executor for our jobs and handle the signal properly
    220         pool = multiprocessing.Pool(jobs)
     220        pool = setupPool(jobs)
    221221
    222222        # for each test to run
     
    233233
    234234        # clean the workspace
    235         make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL)
     235        make('clean', redirects = '> /dev/null 2>&1')
    236236
    237237        for failed in results:
     
    248248
    249249        # parse the command line arguments
    250         options = parse_args()
     250        options = getOptions()
    251251
    252252        # init global settings
     
    254254
    255255        # fetch the liest of all valid tests
    256         all_tests = list_tests( options.include, options.exclude )
     256        allTests = listTests( 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 = all_tests
     261                tests = allTests
    262262
    263263        #otherwise we need to validate that the test list that was entered is valid
    264264        else :
    265                 tests = valid_tests( options )
     265                tests = validTests( 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: t.toString(), tests)))
     283                fancy_print("\n".join(map(lambda t: "%s" % (t.toString()), tests)))
    284284
    285285        else :
    286286                # check the build configuration works
    287                 settings.prep_output(tests)
    288287                settings.validate()
    289288
    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,
     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',
    297294                        settings.arch.string,
    298                         settings.debug.string
     295                        settings.debug.string,
     296                        options.jobs
    299297                ))
    300298
Note: See TracChangeset for help on using the changeset viewer.