Changes in / [f845e80:98b4b12]


Ignore:
Files:
49 added
14 deleted
92 edited

Legend:

Unmodified
Added
Removed
  • benchmark/Makefile.am

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    rf845e80 r98b4b12  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar  8 14:53:02 2018
    13 // Update Count     : 78
     12// Last Modified On : Tue Mar 12 09:01:53 2019
     13// Update Count     : 83
    1414//
    1515
     
    1919#include <list>                    // for list
    2020#include <memory>                  // for allocator
    21 #include <vector>                        // for vector
     21#include <vector>                                  // for vector
    2222
    2323#include "BaseSyntaxNode.h"        // for BaseSyntaxNode
     
    4343        const std::list<Label> & get_labels() const { return labels; }
    4444
    45         virtual Statement *clone() const override = 0;
    46         virtual void accept( Visitor &v ) override = 0;
    47         virtual Statement *acceptMutator( Mutator &m ) override = 0;
    48         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     45        virtual Statement * clone() const override = 0;
     46        virtual void accept( Visitor & v ) override = 0;
     47        virtual Statement * acceptMutator( Mutator & m ) override = 0;
     48        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    4949};
    5050
     
    5555        CompoundStmt();
    5656        CompoundStmt( std::list<Statement *> stmts );
    57         CompoundStmt( const CompoundStmt &other );
     57        CompoundStmt( const CompoundStmt & other );
    5858        virtual ~CompoundStmt();
    5959
     
    6262        void push_front( Statement * stmt ) { kids.push_front( stmt ); }
    6363
    64         virtual CompoundStmt *clone() const override { return new CompoundStmt( *this ); }
    65         virtual void accept( Visitor &v ) override { v.visit( this ); }
    66         virtual CompoundStmt *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    67         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     64        virtual CompoundStmt * clone() const override { return new CompoundStmt( *this ); }
     65        virtual void accept( Visitor & v ) override { v.visit( this ); }
     66        virtual CompoundStmt * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     67        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    6868};
    6969
     
    7272        NullStmt( const std::list<Label> & labels = {} );
    7373
    74         virtual NullStmt *clone() const override { return new NullStmt( *this ); }
    75         virtual void accept( Visitor &v ) override { v.visit( this ); }
    76         virtual NullStmt *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    77         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     74        virtual NullStmt * clone() const override { return new NullStmt( *this ); }
     75        virtual void accept( Visitor & v ) override { v.visit( this ); }
     76        virtual NullStmt * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     77        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    7878};
    7979
    8080class ExprStmt : public Statement {
    8181  public:
    82         Expression *expr;
    83 
    84         ExprStmt( Expression *expr );
    85         ExprStmt( const ExprStmt &other );
     82        Expression * expr;
     83
     84        ExprStmt( Expression * expr );
     85        ExprStmt( const ExprStmt & other );
    8686        virtual ~ExprStmt();
    8787
    88         Expression *get_expr() { return expr; }
    89         void set_expr( Expression *newValue ) { expr = newValue; }
    90 
    91         virtual ExprStmt *clone() const override { return new ExprStmt( *this ); }
    92         virtual void accept( Visitor &v ) override { v.visit( this ); }
    93         virtual Statement *acceptMutator( Mutator &m )  override { return m.mutate( this ); }
    94         virtual void print( std::ostream &os, Indenter indent = {} ) const override;
     88        Expression * get_expr() { return expr; }
     89        void set_expr( Expression * newValue ) { expr = newValue; }
     90
     91        virtual ExprStmt * clone() const override { return new ExprStmt( *this ); }
     92        virtual void accept( Visitor & v ) override { v.visit( this ); }
     93        virtual Statement * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
     94        virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    9595};
    9696
     
    9898  public:
    9999        bool voltile;
    100         Expression *instruction;
     100        Expression * instruction;
    101101        std::list<Expression *> output, input;
    102102        std::list<ConstantExpr *> clobber;
    103103        std::list<Label> gotolabels;
    104104
    105         AsmStmt( bool voltile, Expression *instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels );
    106         AsmStmt( const AsmStmt &other );
     105        AsmStmt( bool voltile, Expression * instruction, std::list<Expression *> output, std::list<Expression *> input, std::list<ConstantExpr *> clobber, std::list<Label> gotolabels );
     106        AsmStmt( const AsmStmt & other );
    107107        virtual ~AsmStmt();
    108108
     
    114114        void set_output( const std::list<Expression *> & newValue ) { output = newValue; }
    115115        std::list<Expression *> & get_input() { return input; }
    116         void set_input( const std::list<Expression *> &newValue ) { input = newValue; }
     116        void set_input( const std::list<Expression *> & newValue ) { input = newValue; }
    117117        std::list<ConstantExpr *> & get_clobber() { return clobber; }
    118         void set_clobber( const std::list<ConstantExpr *> &newValue ) { clobber = newValue; }
     118        void set_clobber( const std::list<ConstantExpr *> & newValue ) { clobber = newValue; }
    119119        std::list<Label> & get_gotolabels() { return gotolabels; }
    120         void set_gotolabels( const std::list<Label> &newValue ) { gotolabels = newValue; }
     120        void set_gotolabels( const std::list<Label> & newValue ) { gotolabels = newValue; }
    121121
    122122        virtual AsmStmt * clone() const { return new AsmStmt( *this ); }
     
    141141class IfStmt : public Statement {
    142142  public:
    143         Expression *condition;
    144         Statement *thenPart;
    145         Statement *elsePart;
     143        Expression * condition;
     144        Statement * thenPart;
     145      &n