Changes in / [f343c6b:69c37cc]
- Files:
-
- 14 added
- 49 deleted
- 92 edited
-
Jenkinsfile (deleted)
-
benchmark/Makefile.am (modified) (3 diffs)
-
benchmark/Makefile.in (modified) (3 diffs)
-
benchmark/tls-fetch_add.c (deleted)
-
configure (modified) (2 diffs)
-
configure.ac (modified) (1 diff)
-
doc/bibliography/pl.bib (modified) (4 diffs)
-
doc/papers/concurrency/Paper.tex (modified) (16 diffs)
-
doc/papers/concurrency/examples/C++Cor-ts.cpp (deleted)
-
doc/papers/concurrency/examples/Fib.c (deleted)
-
doc/papers/concurrency/examples/Fib.cfa (deleted)
-
doc/papers/concurrency/examples/Fib.cpp (deleted)
-
doc/papers/concurrency/examples/Fib.py (deleted)
-
doc/papers/concurrency/examples/Fib.sim (deleted)
-
doc/papers/concurrency/examples/Fib2.cfa (deleted)
-
doc/papers/concurrency/examples/Fib2.cpp (deleted)
-
doc/papers/concurrency/examples/Fib2.py (deleted)
-
doc/papers/concurrency/examples/FibRefactor.py (deleted)
-
doc/papers/concurrency/examples/Fmt.sim (deleted)
-
doc/papers/concurrency/examples/Format.cc (deleted)
-
doc/papers/concurrency/examples/Format.cfa (deleted)
-
doc/papers/concurrency/examples/Format.cpp (deleted)
-
doc/papers/concurrency/examples/Format.py (deleted)
-
doc/papers/concurrency/examples/Pingpong.cc (deleted)
-
doc/papers/concurrency/examples/Pingpong.cfa (deleted)
-
doc/papers/concurrency/examples/Pingpong.py (deleted)
-
doc/papers/concurrency/examples/ProdCons.cfa (deleted)
-
doc/papers/concurrency/examples/ProdCons.cpp (deleted)
-
doc/papers/concurrency/examples/ProdCons.py (deleted)
-
doc/papers/concurrency/examples/ProdCons.sim (deleted)
-
doc/papers/concurrency/examples/Refactor.py (deleted)
-
doc/papers/concurrency/examples/counter.cpp (deleted)
-
doc/proposals/interned_string.cc (deleted)
-
doc/proposals/interned_string.h (deleted)
-
doc/proposals/specialized_casts.md (deleted)
-
doc/proposals/vtable.md (modified) (5 diffs)
-
doc/user/user.tex (modified) (5 diffs)
-
libcfa/configure (modified) (1 diff)
-
libcfa/configure.ac (modified) (1 diff)
-
libcfa/prelude/builtins.c (modified) (4 diffs)
-
libcfa/prelude/prelude-gen.cc (modified) (5 diffs)
-
libcfa/src/Makefile.am (modified) (1 diff)
-
libcfa/src/Makefile.in (modified) (1 diff)
-
libcfa/src/concurrency/CtxSwitch-x86_64.S (modified) (1 diff)
-
libcfa/src/concurrency/coroutine.cfa (modified) (6 diffs)
-
libcfa/src/concurrency/coroutine.hfa (modified) (6 diffs)
-
libcfa/src/concurrency/invoke.c (modified) (5 diffs)
-
libcfa/src/concurrency/invoke.h (modified) (4 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (8 diffs)
-
libcfa/src/concurrency/thread.cfa (modified) (4 diffs)
-
libcfa/src/fstream.cfa (modified) (14 diffs)
-
libcfa/src/fstream.hfa (modified) (2 diffs)
-
libcfa/src/gmp.hfa (modified) (2 diffs)
-
libcfa/src/heap.cfa (modified) (2 diffs)
-
libcfa/src/iostream.cfa (modified) (3 diffs)
-
libcfa/src/iostream.hfa (modified) (3 diffs)
-
libcfa/src/rational.cfa (modified) (9 diffs)
-
libcfa/src/rational.hfa (modified) (2 diffs)
-
libcfa/src/stdhdr/stdbool.h (modified) (1 diff)
-
libcfa/src/stdlib.hfa (modified) (4 diffs)
-
longrun_tests/Makefile.am (deleted)
-
longrun_tests/Makefile.in (deleted)
-
longrun_tests/block.cfa (deleted)
-
longrun_tests/coroutine.cfa (deleted)
-
longrun_tests/create.cfa (deleted)
-
longrun_tests/disjoint.cfa (deleted)
-
longrun_tests/enter.cfa (deleted)
-
longrun_tests/enter3.cfa (deleted)
-
longrun_tests/preempt.cfa (deleted)
-
longrun_tests/processor.cfa (deleted)
-
longrun_tests/stack.cfa (deleted)
-
longrun_tests/update-type (deleted)
-
longrun_tests/wait.cfa (deleted)
-
longrun_tests/yield.cfa (deleted)
-
src/Common/PassVisitor.cc (modified) (1 diff)
-
src/Common/PersistentMap.h (deleted)
-
src/Common/Stats/Counter.h (modified) (2 diffs)
-
src/ControlStruct/ForExprMutator.cc (modified) (4 diffs)
-
src/ControlStruct/LabelFixer.cc (modified) (7 diffs)
-
src/ControlStruct/LabelGenerator.cc (modified) (3 diffs)
-
src/Parser/ParseNode.h (modified) (2 diffs)
-
src/Parser/lex.ll (modified) (2 diffs)
-
src/Parser/parser.yy (modified) (10 diffs)
-
src/ResolvExpr/AlternativeFinder.cc (modified) (1 diff)
-
src/ResolvExpr/ResolveAssertions.cc (modified) (6 diffs)
-
src/ResolvExpr/ResolveAssertions.h (modified) (1 diff)
-
src/ResolvExpr/TypeEnvironment.cc (modified) (4 diffs)
-
src/ResolvExpr/TypeEnvironment.h (modified) (1 diff)
-
src/ResolvExpr/Unify.cc (modified) (1 diff)
-
src/SymTab/Indexer.cc (modified) (13 diffs)
-
src/SymTab/Indexer.h (modified) (5 diffs)
-
src/SynTree/Attribute.cc (modified) (1 diff)
-
src/SynTree/BaseSyntaxNode.h (modified) (2 diffs)
-
src/SynTree/Constant.cc (modified) (1 diff)
-
src/SynTree/Declaration.h (modified) (1 diff)
-
src/SynTree/Statement.h (modified) (23 diffs)
-
src/main.cc (modified) (1 diff)
-
tests/.expect/KRfunctions.x64.txt (modified) (1 diff)
-
tests/.expect/KRfunctions.x86.txt (modified) (1 diff)
-
tests/.expect/completeTypeError.txt (modified) (2 diffs)
-
tests/.expect/declarationSpecifier.x64.txt (modified) (1 diff)
-
tests/.expect/declarationSpecifier.x86.txt (modified) (1 diff)
-
tests/.expect/extension.x64.txt (modified) (1 diff)
-
tests/.expect/extension.x86.txt (modified) (1 diff)
-
tests/.expect/gccExtensions.x64.txt (modified) (1 diff)
-
tests/.expect/gccExtensions.x86.txt (modified) (1 diff)
-
tests/.expect/loopctrl.txt (modified) (2 diffs)
-
tests/.expect/math1.txt (modified) (1 diff)
-
tests/Makefile.am (modified) (5 diffs)
-
tests/Makefile.in (modified) (8 diffs)
-
tests/completeTypeError.cfa (modified) (5 diffs)
-
tests/concurrent/examples/boundedBufferEXT.cfa (modified) (2 diffs)
-
tests/concurrent/examples/boundedBufferINT.cfa (modified) (2 diffs)
-
tests/concurrent/examples/datingService.cfa (modified) (2 diffs)
-
tests/concurrent/examples/quickSort.cfa (modified) (2 diffs)
-
tests/concurrent/examples/quickSort.generic.cfa (deleted)
-
tests/concurrent/waitfor/parse2.cfa (modified) (2 diffs)
-
tests/config.py.in (modified) (1 diff)
-
tests/coroutine/.expect/devicedriver.txt (deleted)
-
tests/coroutine/.expect/fmtLines.txt (modified) (2 diffs)
-
tests/coroutine/.in/devicedriver.txt (deleted)
-
tests/coroutine/.in/fmtLines.txt (modified) (2 diffs)
-
tests/coroutine/cntparens.cfa (deleted)
-
tests/coroutine/devicedriver.cfa (deleted)
-
tests/coroutine/fibonacci.cfa (modified) (2 diffs)
-
tests/coroutine/fibonacci_1.cfa (modified) (4 diffs)
-
tests/coroutine/fmtLines.cfa (modified) (2 diffs)
-
tests/coroutine/pingpong.cfa (modified) (4 diffs)
-
tests/coroutine/prodcons.cfa (modified) (2 diffs)
-
tests/coroutine/runningTotal.cfa (modified) (2 diffs)
-
tests/forall.cfa (modified) (2 diffs)
-
tests/function-operator.cfa (modified) (2 diffs)
-
tests/io2.cfa (modified) (2 diffs)
-
tests/loopctrl.cfa (modified) (3 diffs)
-
tests/math1.cfa (modified) (2 diffs)
-
tests/preempt_longrun/Makefile.am (added)
-
tests/preempt_longrun/Makefile.in (added)
-
tests/preempt_longrun/block.c (added)
-
tests/preempt_longrun/coroutine.c (added)
-
tests/preempt_longrun/create.c (added)
-
tests/preempt_longrun/disjoint.c (added)
-
tests/preempt_longrun/enter.c (added)
-
tests/preempt_longrun/enter3.c (added)
-
tests/preempt_longrun/preempt.c (added)
-
tests/preempt_longrun/processor.c (added)
-
tests/preempt_longrun/stack.c (added)
-
tests/preempt_longrun/update-type (added)
-
tests/preempt_longrun/wait.c (added)
-
tests/preempt_longrun/yield.c (added)
-
tests/pybin/settings.py (modified) (7 diffs)
-
tests/pybin/test_run.py (modified) (1 diff)
-
tests/pybin/tools.py (modified) (13 diffs)
-
tests/raii/init_once.cfa (modified) (2 diffs)
-
tests/rational.cfa (modified) (3 diffs)
-
tests/test.py (modified) (19 diffs)
Legend:
- Unmodified
- Added
- Removed
-
benchmark/Makefile.am
rf343c6b r69c37cc 21 21 include $(top_srcdir)/src/cfa.make 22 22 23 AM_CFLAGS = -O2 -Wall - Wextra -Werror -I$(srcdir) -lrt -pthread24 AM_CFAFLAGS = -quiet - nodebug -in-tree25 AM_UPPFLAGS = -quiet -nodebug -multi -std=c++1423 AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread 24 AM_CFAFLAGS = -quiet -in-tree -nodebug 25 AM_UPPFLAGS = -quiet -nodebug -multi 26 26 27 27 BENCH_V_CC = $(__bench_v_CC_$(__quiet)) … … 139 139 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/fetch_add.c 140 140 141 tls-fetch_add$(EXEEXT):142 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/tls-fetch_add.c143 144 141 ## ========================================================================================================= 145 142 CTXSWITCH_DEPEND = \ … … 147 144 function.run \ 148 145 fetch_add.run \ 149 tls-fetch_add.run \150 146 ctxswitch-pthread.run \ 151 147 ctxswitch-cfa_coroutine.run \ -
benchmark/Makefile.in
rf343c6b r69c37cc 371 371 372 372 # applies to both programs 373 AM_CFLAGS = -O2 -Wall - Wextra -Werror -I$(srcdir) -lrt -pthread374 AM_CFAFLAGS = -quiet - nodebug -in-tree375 AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14373 AM_CFLAGS = -O2 -Wall -I$(srcdir) -lrt -pthread 374 AM_CFAFLAGS = -quiet -in-tree -nodebug 375 AM_UPPFLAGS = -quiet -nodebug -multi 376 376 BENCH_V_CC = $(__bench_v_CC_$(__quiet)) 377 377 BENCH_V_CFA = $(__bench_v_CFA_$(__quiet)) … … 402 402 dummy_SOURCES = dummyC.c dummyCXX.cpp 403 403 CTXSWITCH_DEPEND = loop.run function.run fetch_add.run \ 404 tls-fetch_add.run ctxswitch-pthread.run \405 ctxswitch-cfa_ coroutine.run ctxswitch-cfa_thread.run \406 ctxswitch- cfa_thread2.run ctxswitch-upp_coroutine.run \407 ctxswitch- upp_thread.run ctxswitch-goroutine.run \408 ctxswitch-java_thread.run$(am__append_1)404 ctxswitch-pthread.run ctxswitch-cfa_coroutine.run \ 405 ctxswitch-cfa_thread.run ctxswitch-cfa_thread2.run \ 406 ctxswitch-upp_coroutine.run ctxswitch-upp_thread.run \ 407 ctxswitch-goroutine.run ctxswitch-java_thread.run \ 408 $(am__append_1) 409 409 testdir = $(top_srcdir)/tests 410 410 all: all-am … … 799 799 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/fetch_add.c 800 800 801 tls-fetch_add$(EXEEXT):802 $(BENCH_V_CC)$(COMPILE) -DBENCH_N=500000000 $(srcdir)/tls-fetch_add.c803 804 801 @WITH_LIBFIBRE_TRUE@ctxswitch-kos_fibre$(EXEEXT): 805 802 @WITH_LIBFIBRE_TRUE@ $(BENCH_V_CXX)$(CXXCOMPILE) -DBENCH_N=50000000 $(srcdir)/ctxswitch/kos_fibre.cpp -I$(LIBFIBRE_DIR) -lfibre -
configure
rf343c6b r69c37cc 16738 16738 16739 16739 #============================================================================== 16740 ac_config_files="$ac_config_files Makefile driver/Makefile src/Makefile benchmark/Makefile tests/Makefile longrun_tests/Makefile tools/Makefile tools/prettyprinter/Makefile"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" 16741 16741 16742 16742 … … 17876 17876 "benchmark/Makefile") CONFIG_FILES="$CONFIG_FILES benchmark/Makefile" ;; 17877 17877 "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; 17878 " longrun_tests/Makefile") CONFIG_FILES="$CONFIG_FILES longrun_tests/Makefile" ;;17878 "tests/preempt_longrun/Makefile") CONFIG_FILES="$CONFIG_FILES tests/preempt_longrun/Makefile" ;; 17879 17879 "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;; 17880 17880 "tools/prettyprinter/Makefile") CONFIG_FILES="$CONFIG_FILES tools/prettyprinter/Makefile" ;; -
configure.ac
rf343c6b r69c37cc 211 211 benchmark/Makefile 212 212 tests/Makefile 213 longrun_tests/Makefile213 tests/preempt_longrun/Makefile 214 214 tools/Makefile 215 215 tools/prettyprinter/Makefile -
doc/bibliography/pl.bib
rf343c6b r69c37cc 1163 1163 title = {Checked C: Making C Safe by Extension}, 1164 1164 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/}, 1170 1170 } 1171 1171 1172 1172 @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/}} 1177 1177 } 1178 1178 … … 2347 2347 } 2348 2348 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 2365 2349 @article{design, 2366 2350 keywords = {Smalltalk, designing classes}, … … 2370 2354 journal = joop, 2371 2355 year = 1988, 2372 volume = 1, 2373 number = 2, 2374 pages = {22-35}, 2356 volume = 1, number = 2, pages = {22-35}, 2375 2357 comment = { 2376 2358 Abstract classes represent standard protocols. ``It is better to … … 3807 3789 optaddress = {Waterloo, Ontario, Canada, N2L 3G1}, 3808 3790 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},3821 3791 } 3822 3792 -
doc/papers/concurrency/Paper.tex
rf343c6b r69c37cc 215 215 {} 216 216 \lstnewenvironment{Go}[1][] 217 {\lstset{language=go,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}} 218 {} 219 \lstnewenvironment{python}[1][] 220 {\lstset{language=python,moredelim=**[is][\protect\color{red}]{`}{`},#1}\lstset{#1}} 217 {\lstset{#1}} 221 218 {} 222 219 … … 231 228 } 232 229 233 \title{\texorpdfstring{Advanced Control-flow and Concurrencyin \protect\CFA}{Advanced Control-flow in Cforall}}230 \title{\texorpdfstring{Advanced Control-flow in \protect\CFA}{Advanced Control-flow in Cforall}} 234 231 235 232 \author[1]{Thierry Delisle} … … 245 242 \abstract[Summary]{ 246 243 \CFA is a modern, polymorphic, non-object-oriented, backwards-compatible extension of the C programming language. 247 This paper discusses some advanced control-flow and concurrency/parallelism features in \CFA, along with the supporting runtime.248 These features are created from scratch because they do not exist in ISO C, or are low-level and/or unimplemented, so C programmers continue to rely on library features, like C pthreads.249 \CFA introduces language-level control-flow mechanisms, like coroutines, user-level threading, and monitors for mutual exclusion and synchronization.250 A unique contribution of this work is allowing multiple monitors to be safely acquired \emph{simultaneously} (deadlock free), while integrating this capability with monitor synchronization mechanisms.251 These features also integrate with the \CFA polymorphic type-system and exception handling, while respecting the expectations and style of C programmers.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. 252 249 Experimental results show comparable performance of the new features with similar mechanisms in other concurrent programming-languages. 253 250 }% … … 264 261 \section{Introduction} 265 262 266 This paper discusses the design of language-level control-flow and concurrency/parallelism extensionsin \CFA and its runtime.263 This paper discusses the design of advanced, high-level control-flow extensions (especially concurrency and parallelism) in \CFA and its runtime. 267 264 \CFA is a modern, polymorphic, non-object-oriented\footnote{ 268 265 \CFA has features often associated with object-oriented programming languages, such as constructors, destructors, virtuals and simple inheritance. 269 266 However, 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.}, 270 267 backwards-compatible extension of the C programming language~\cite{Moss18}. 271 Within the \CFA framework, new control-flow features are created from scratch. 272 ISO \Celeven defines only a subset of the \CFA extensions, where the overlapping features are concurrency~\cite[\S~7.26]{C11}. 273 However, \Celeven concurrency is largely wrappers for a subset of the pthreads library~\cite{Butenhof97,Pthreads}. 274 Furthermore, \Celeven and pthreads concurrency is simple, based on thread fork/join in a function and a few locks, which is low-level and error prone; 275 no high-level language concurrency features are defined. 276 Interestingly, almost a decade after publication of the \Celeven standard, neither gcc-8, clang-8 nor msvc-19 (most recent versions) support the \Celeven include @threads.h@, indicating little interest in the C11 concurrency approach. 277 Finally, while the \Celeven standard does not state a concurrent threading-model, the historical association with pthreads suggests implementations would adopt kernel-level threading (1:1)~\cite{ThreadModel}. 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}. 278 274 279 275 In contrast, there has been a renewed interest during the past decade in user-level (M:N, green) threading in old and new programming languages. … … 288 284 289 285 A further effort over the past decade is the development of language memory-models to deal with the conflict between certain language features and compiler/hardware optimizations. 290 This issue can be rephrased as : some language features are pervasive (language and runtime) and cannot be safely added via a library to prevent invalidation by sequential optimizations~\cite{Buhr95a,Boehm05}.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}. 291 287 The consequence is that a language must be cognizant of these features and provide sufficient tools to program around any safety issues. 292 288 For example, C created the @volatile@ qualifier to provide correct execution for @setjmp@/@logjmp@ (concurrency came later). 293 The commonsolution 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}.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}. 294 290 295 291 While 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. 296 292 Essentially, using low-level explicit locks is the concurrent equivalent of assembler programming. 297 Just as most assembler programming is replaced with high-level programming, explicit locks can be replaced with high-level concurrencyin a programming language.298 The n the goal is forthe compiler to check for correct usage and follow any complex coding conventions implicitly.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. 299 295 The drawback is that language constructs may preclude certain specialized techniques, therefore introducing inefficiency or inhibiting concurrency. 300 296 For 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. … … 303 299 As stated, this observation applies to non-concurrent forms of complex control-flow, like exception handling and coroutines. 304 300 305 Adapting the programming language to these features also allows matching the control-flow model with the programming-language style, versus adoptingone general (sound) library/paradigm.301 Adapting the programming language allows matching the control-flow model with the programming-language style, versus adapting to one general (sound) library/paradigm. 306 302 For 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++}. 307 303 It 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. … … 311 307 however, 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.} 312 308 Finally, with extended language features and user-level threading it is possible to discretely fold locking and non-blocking I/O multiplexing into the language's I/O libraries, so threading implicitly dovetails with the I/O subsystem. 313 \CFA embraces language extensions and user-level threading to provide advanced control-flow (exception handling\footnote{ 314 \CFA exception handling will be presented in a separate paper. 315 The key feature that dovetails with this paper is non-local exceptions allowing exceptions to be raised across stacks, with synchronous exceptions raised among coroutines and asynchronous exceptions raised among threads, similar to that in \uC~\cite[\S~5]{uC++} 316 } and coroutines) and concurrency. 317 318 Most augmented traditional (Fortran 18~\cite{Fortran18}, Cobol 14~\cite{Cobol14}, Ada 12~\cite{Ada12}, Java 11~\cite{Java11}) and new languages (Go~\cite{Go}, Rust~\cite{Rust}, and D~\cite{D}), except \CC, diverge from C with different syntax and semantics, only interoperate indirectly with C, and are not systems languages, for those with managed memory. 319 As a result, there is a significant learning curve to move to these languages, and C legacy-code must be rewritten. 320 While \CC, like \CFA, takes an evolutionary approach to extend C, \CC's constantly growing complex and interdependent features-set (e.g., objects, inheritance, templates, etc.) mean idiomatic \CC code is difficult to use from C, and C programmers must expend significant effort learning \CC. 321 Hence, rewriting and retraining costs for these languages, even \CC, are prohibitive for companies with a large C software-base. 322 \CFA with its orthogonal feature-set, its high-performance runtime, and direct access to all existing C libraries circumvents these problems. 323 324 We present comparative examples so the reader can judge if the \CFA control-flow extensions are equivalent or better than those in or proposed for \Celeven, \CC and other concurrent, imperative programming languages, and perform experiments to show the \CFA runtime is competitive with other similar mechanisms. 325 The detailed contributions of this work are: 309 310 \CFA embraces language extensions and user-level threading to provide advanced control-flow and concurrency. 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: 326 313 \begin{itemize} 327 314 \item … … 628 615 629 616 630 \section{Coroutines: Stepping Stone}631 \label{coroutine} 632 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). 633 620 Coroutines are generalized routines allowing execution to be temporarily suspended and later resumed. 634 621 Hence, 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. … … 654 641 \centering 655 642 \newbox\myboxA 656 % \begin{lrbox}{\myboxA}657 % \begin{cfa}[aboveskip=0pt,belowskip=0pt]658 % `int fn1, fn2, state = 1;` // single global variables659 % int fib() {660 % int fn;661 % `switch ( state )` { // explicit execution state662 % 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}676 643 \begin{lrbox}{\myboxA} 677 644 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 678 #define FIB_INIT { 0, 1 } 679 typedef struct { int fn1, fn; } Fib; 645 `int f1, f2, state = 1;` // single global variables 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 } 655 int main() { 656 657 for ( int i = 0; i < 10; i += 1 ) { 658 printf( "%d\n", fib() ); 659 } 660 } 661 \end{cfa} 662 \end{lrbox} 663 664 \newbox\myboxB 665 \begin{lrbox}{\myboxB} 666 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 667 #define FIB_INIT `{ 0, 1 }` 668 typedef struct { int f2, f1; } Fib; 680 669 int fib( Fib * f ) { 681 670 682 int ret = f->fn1; 683 f->fn1 = f->fn; 684 f->fn = ret + f->fn; 671 int ret = f->f2; 672 int fn = f->f1 + f->f2; 673 f->f2 = f->f1; f->f1 = fn; 674 685 675 return ret; 686 676 } 687 688 689 690 677 int main() { 691 678 Fib f1 = FIB_INIT, f2 = FIB_INIT; 692 679 for ( int i = 0; i < 10; i += 1 ) { 693 printf( "%d %d\n", 694 fib( &f1 ), fib( &f2 ) ); 680 printf( "%d %d\n", fib( &f1 ), fib( &f2 ) ); 695 681 } 696 682 } … … 698 684 \end{lrbox} 699 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; 709 } 710 int main() { 711 Fib f1, f2; 712 for ( int i = 1; i <= 10; i += 1 ) { 713 sout | next( f1 ) | next( f2 ); 714 } 715 } 716 \end{cfa} 717 \end{lrbox} 700 718 \newbox\myboxB 701 719 \begin{lrbox}{\myboxB} 702 720 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 703 `coroutine` Fib { int fn1; };704 void main( Fib & f ib) with( fib ) {705 int fn ;706 [fn1, fn] = [0, 1];707 for () {708 `suspend();` 709 [fn1, fn] = [fn, fn1 + fn];721 `coroutine` Fib { int ret; }; 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();` 710 728 } 711 729 } 712 int ?()( Fib & fib ) with( fib ) {713 `resume( fib );` return fn1;714 } 715 int main() { 716 Fib f1, f2; 717 for ( 10 ) { 718 sout | f1() | f2(); 719 } 730 int next( Fib & fib ) with( fib ) { 731 `resume( fib );` 732 return ret; 733 } 734 735 736 737 720 738 721 739 722 740 \end{cfa} 723 741 \end{lrbox} 724 725 \newbox\myboxC 726 \begin{lrbox}{\myboxC} 727 \begin{python}[aboveskip=0pt,belowskip=0pt] 728 729 def Fib(): 730 731 fn1, fn = 0, 1 732 while True: 733 `yield fn1` 734 fn1, fn = fn, fn1 + fn 735 736 737 // next prewritten 738 739 740 f1 = Fib() 741 f2 = Fib() 742 for i in range( 10 ): 743 print( next( f1 ), next( f2 ) ) 744 745 746 747 \end{python} 748 \end{lrbox} 749 750 \subfloat[C]{\label{f:GlobalVariables}\usebox\myboxA} 751 \hspace{3pt} 752 \vrule 753 \hspace{3pt} 754 \subfloat[\CFA]{\label{f:ExternalState}\usebox\myboxB} 755 \hspace{3pt} 756 \vrule 757 \hspace{3pt} 758 \subfloat[Python]{\label{f:ExternalState}\usebox\myboxC} 759 \caption{Fibonacci Generator} 760 \label{f:C-fibonacci} 761 762 % \bigskip 763 % 764 % \newbox\myboxA 765 % \begin{lrbox}{\myboxA} 766 % \begin{cfa}[aboveskip=0pt,belowskip=0pt] 767 % `coroutine` Fib { int fn; }; 768 % void main( Fib & fib ) with( fib ) { 769 % fn = 0; int fn1 = fn; `suspend()`; 770 % fn = 1; int fn2 = fn1; fn1 = fn; `suspend()`; 771 % for () { 772 % fn = fn1 + fn2; fn2 = fn1; fn1 = fn; `suspend()`; } 773 % } 774 % int next( Fib & fib ) with( fib ) { `resume( fib );` return fn; } 775 % int main() { 776 % Fib f1, f2; 777 % for ( 10 ) 778 % sout | next( f1 ) | next( f2 ); 779 % } 780 % \end{cfa} 781 % \end{lrbox} 782 % \newbox\myboxB 783 % \begin{lrbox}{\myboxB} 784 % \begin{python}[aboveskip=0pt,belowskip=0pt] 785 % 786 % def Fibonacci(): 787 % fn = 0; fn1 = fn; `yield fn` # suspend 788 % fn = 1; fn2 = fn1; fn1 = fn; `yield fn` 789 % while True: 790 % fn = fn1 + fn2; fn2 = fn1; fn1 = fn; `yield fn` 791 % 792 % 793 % f1 = Fibonacci() 794 % f2 = Fibonacci() 795 % for i in range( 10 ): 796 % print( `next( f1 )`, `next( f2 )` ) # resume 797 % 798 % \end{python} 799 % \end{lrbox} 800 % \subfloat[\CFA]{\label{f:Coroutine3States}\usebox\myboxA} 801 % \qquad 802 % \subfloat[Python]{\label{f:Coroutine1State}\usebox\myboxB} 803 % \caption{Fibonacci input coroutine, 3 states, internal variables} 804 % \label{f:cfa-fibonacci} 742 \subfloat[3 States, internal variables]{\label{f:Coroutine3States}\usebox\myboxA} 743 \qquad\qquad 744 \subfloat[1 State, internal variables]{\label{f:Coroutine1State}\usebox\myboxB} 745 \caption{\CFA Coroutine Fibonacci Implementations} 746 \label{f:cfa-fibonacci} 805 747 \end{figure} 806 748 … … 842 784 \begin{lrbox}{\myboxA} 843 785 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 844 `coroutine` F mt {845 char ch; // communication variables846 int g, b; // needed in destructor786 `coroutine` Format { 787 char ch; // used for communication 788 int g, b; // global because used in destructor 847 789 }; 848 void main( F mt & fmt ) with( fmt ) {849 for ( ) {850 for ( g = 0; g < 5; g += 1 ) { // groups851 for ( b = 0; b < 4; b += 1 ) { // block s790 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 852 794 `suspend();` 853 sout | ch; } // print character 854 sout | " "; } // block separator 855 sout | nl; } // group separator 856 } 857 void ?{}( Fmt & fmt ) { `resume( fmt );` } // prime 858 void ^?{}( Fmt & fmt ) with( fmt ) { // destructor 859 if ( g != 0 || b != 0 ) // special case 860 sout | nl; } 861 void send( Fmt & fmt, char c ) { fmt.ch = c; `resume( fmt )`; } 795 sout | ch; // separator 796 } 797 sout | " "; // separator 798 } 799 sout | nl; 800 } 801 } 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 } 862 809 int main() { 863 Fmt fmt; 864 sout | nlOff; // turn off auto newline 865 for ( 41 ) 866 send( fmt, 'a' ); 810 Format fmt; 811 eof: for ( ;; ) { 812 sin | fmt.ch; 813 if ( eof( sin ) ) break eof; 814 format( fmt ); 815 } 867 816 } 868 817 \end{cfa} … … 871 820 \newbox\myboxB 872 821 \begin{lrbox}{\myboxB} 873 \begin{python}[aboveskip=0pt,belowskip=0pt] 874 875 876 877 def Fmt(): 878 try: 879 while True: 880 for g in range( 5 ): 881 for b in range( 4 ): 882 883 print( `(yield)`, end='' ) 884 print( ' ', end='' ) 885 print() 886 887 888 except GeneratorExit: 889 if g != 0 | b != 0: 890 print() 891 892 893 fmt = Fmt() 894 `next( fmt )` # prime 895 for i in range( 41 ): 896 `fmt.send( 'a' );` # send to yield 897 898 \end{python} 822 \begin{cfa}[aboveskip=0pt,belowskip=0pt] 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} 899 855 \end{lrbox} 900 \subfloat[\CFA ]{\label{f:CFAFmt}\usebox\myboxA}856 \subfloat[\CFA Coroutine]{\label{f:CFAFmt}\usebox\myboxA} 901 857 \qquad 902 \subfloat[ Python]{\label{f:CFmt}\usebox\myboxB}903 \caption{ Output formatting text}858 \subfloat[C Linearized]{\label{f:CFmt}\usebox\myboxB} 859 \caption{Formatting text into lines of 5 blocks of 4 characters.} 904 860 \label{f:fmt-line} 905 861 \end{figure} … … 922 878 void main( Prod & prod ) with( prod ) { 923 879 // 1st resume starts here 924 for ( i ; N) {880 for ( int i = 0; i < N; i += 1 ) { 925 881 int p1 = random( 100 ), p2 = random( 100 ); 926 882 sout | p1 | " " | p2; … … 938 894 } 939 895 void start( Prod & prod, int N, Cons &c ) { 940 &prod.c = &c; // reassignable reference896 &prod.c = &c; 941 897 prod.[N, receipt] = [N, 0]; 942 898 `resume( prod );` … … 953 909 Prod & p; 954 910 int p1, p2, status; 955 bool done;911 _Bool done; 956 912 }; 957 913 void ?{}( Cons & cons, Prod & p ) { 958 &cons.p = &p; // reassignable reference914 &cons.p = &p; 959 915 cons.[status, done ] = [0, false]; 960 916 } … … 1013 969 The program main restarts after the resume in @start@. 1014 970 @start@ returns and the program main terminates. 1015 1016 One \emph{killer} application for a coroutine is device drivers, which at one time caused 70\%-85\% of failures in Windows/Linux~\cite{Swift05}.1017 Many device drivers are a finite state-machine parsing a protocol, e.g.:1018 \begin{tabbing}1019 \ldots STX \= \ldots message \ldots \= ESC \= ETX \= \ldots message \ldots \= ETX \= 2-byte crc \= \ldots \kill1020 \ldots STX \> \ldots message \ldots \> ESC \> ETX \> \ldots message \ldots \> ETX \> 2-byte crc \> \ldots1021 \end{tabbing}1022 where a network message begins with the control character STX and ends with an ETX, followed by a 2-byte cyclic-redundancy check.1023 Control characters may appear in a message if preceded by an ESC.1024 Because FSMs can be complex and occur frequently in important domains, direct support of the coroutine is crucial in a systems programminglanguage.1025 1026 \begin{figure}1027 \begin{cfa}1028 enum Status { CONT, MSG, ESTX, ELNTH, ECRC };1029 `coroutine` Driver {1030 Status status;1031 char * msg, byte;1032 };1033 void ?{}( Driver & d, char * m ) { d.msg = m; } $\C[3.0in]{// constructor}$1034 Status next( Driver & d, char b ) with( d ) { $\C{// 'with' opens scope}$1035 byte = b; `resume( d );` return status;1036 }1037 void main( Driver & d ) with( d ) {1038 enum { STX = '\002', ESC = '\033', ETX = '\003', MaxMsg = 64 };1039 unsigned short int crc; $\C{// error checking}$1040 msg: for () { $\C{// parse message}$1041 status = CONT;1042 unsigned int lnth = 0, sum = 0;1043 while ( byte != STX ) `suspend();`1044 emsg: for () {1045 `suspend();` $\C{// process byte}$1046 choose ( byte ) { $\C{// switch with default break}$1047 case STX:1048 status = ESTX; `suspend();` continue msg;1049 case ETX:1050 break emsg;1051 case ESC:1052 suspend();1053 } // choose1054 if ( lnth >= MaxMsg ) { $\C{// buffer full ?}$1055 status = ELNTH; `suspend();` continue msg; }1056 msg[lnth++] = byte;1057 sum += byte;1058 } // for1059 msg[lnth] = '\0'; $\C{// terminate string}\CRT$1060 `suspend();`1061 crc = (unsigned char)byte << 8; // prevent sign extension for signed char1062 `suspend();`1063 status = (crc | (unsigned char)byte) == sum ? MSG : ECRC;1064 `suspend();`1065 } // for1066 }1067 \end{cfa}1068 \caption{Device driver for simple communication protocol}1069 \end{figure}1070 971 1071 972 -
doc/proposals/vtable.md
rf343c6b r69c37cc 10 10 other languages. They will mostly contain function pointers although they 11 11 should be able to store anything that goes into a trait. 12 13 I also include notes on a sample implementation, which primarly exists to show14 there is a resonable implementation. The code samples for that are in a slight15 psudo-code to help avoid name mangling and keeps some CFA features while they16 would actually be writen in C.17 12 18 13 Trait Instances … … 47 42 before. 48 43 49 For traits to be used this way they should meet two requirements. First they 50 should only have a single polymorphic type and each assertion should use that 51 type once as a parameter. Extentions may later loosen these requirements. 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. 52 48 53 If a trait object is used it should generate a series of implicate functions 54 each of which implements one of the functions required by the trait. So for 55 combiner there is an implicate: 56 57 void combine(trait combiner & this, int); 58 59 This function is the one actually called at the end 60 61 The main use case for trait objects is that they can be stored. They can be 62 passed into functions, but using the trait directly is prefred in this case. 63 64 trait drawable(otype T) { 65 void draw(Surface & to, T & draw); 66 Rect(int) drawArea(T & draw); 67 }; 68 69 struct UpdatingSurface { 70 Surface * surface; 71 vector(trait drawable) drawables; 72 }; 73 74 void updateSurface(UpdatingSurface & us) { 75 for (size_t i = 0 ; i < us.drawables.size ; ++i) { 76 draw(us.surface, us.drawables[i]); 77 } 78 } 79 80 Currently these traits are limited to 1 trait parameter and functions should 81 have exactly 1 parameter. We cannot abstract away pairs of types and still 82 pass them into normal functions, which take them seperately. 83 84 The second is required the because we need to get the vtable from somewhere. 85 If there are 0 trait objects than no vtable is avalible, if we have more than 86 1 than the vtables give conflicting answers on what underlying function to 87 call. And even then the underlying type assumes a concrete type. 88 89 This loop can sort of be broken by using the trait object directly in the 90 signature. This has well defined meaning, but might not be useful. 91 92 trait example(otype T) { 93 bool test(T & this, trait example & that); 94 } 95 96 #### Sample Implementation 97 A simple way to implement trait objects is by a pair of pointers. One to the 98 underlying object and one to the vtable. 99 100 struct vtable_drawable { 101 void (*draw)(Surface &, void *); 102 Rect(int) (*drawArea)(void *); 103 }; 104 105 struct drawable { 106 void * object; 107 vtable_drawable * vtable; 108 }; 109 110 The functions that run on the trait object would generally be generated using 111 the following pattern: 112 113 void draw(Surface & surface, drawable & traitObj) { 114 return traitObj.vtable->draw(surface, traitObj.object); 115 } 116 117 There may have to be special cases for things like copy construction, that 118 might require a more sigificant wrapper. On the other hand moving could be 119 implemented by moving the pointers without any need to refer to the base 120 object. 121 122 ### Extention: Multiple Trait Parameters 123 Currently, this gives traits two independent uses. They use the same syntax, 124 except for limits boxable traits have, and yet don't really mix. The most 125 natural way to do this is to allow trait instances to pick one parameter 126 that they are generic over, the others they choose types to implement. 127 128 The two ways to do the selection, the first is do it at the trait definition. 129 Each trait picks out a single parameter which it can box (here the `virtual` 130 qualifier). When you create an instance of a trait object you provide 131 arguments like for a generic structure, but skip over the marked parameter. 132 133 trait combiner(virtual otype T, otype Combined) { 134 void combine(T &, Combined &); 135 } 136 137 trait combiner(int) int_combiner; 138 139 The second is to do it at the instaniation point. A placeholder (here the 140 keyword `virtual`) is used to explicately skip over the parameter that will be 141 abstracted away, with the same rules as above if it was the marked parameter. 142 143 trait combiner(otype T, otype Combined) { 144 void combine(T &, Combined &); 145 }; 146 147 trait combiner(virtual, int) int_combiner; 148 149 Using both (first to set the default, second as a local override) would also 150 work, although might be exessively complicated. 151 152 This is useful in cases where you want to use a generic type, but leave part 153 of it open and store partially generic result. As a simple example 154 155 trait folder(otype T, otype In, otype Out) { 156 void fold(T & this, In); 157 Out fold_result(T & this); 158 } 159 160 Which allows you to fold values without putting them in a container. If they 161 are already in a container this is exessive, but if they are generated over 162 time this gives you a simple interface. This could for instance be used in 163 a profile, where T changes for each profiling statistic and you can plug in 164 multiple profilers for any run by adding them to an array. 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. 165 52 166 53 Hierarchy … … 203 90 the pointer to it. 204 91 205 Exception Example:206 (Also I'm not sure where I got these casing rules.)207 208 trait exception(otype T) virtual() {209 char const * what(T & this);210 }211 212 trait io_error(otype T) virtual(exception) {213 FILE * which_file(T & this);214 }215 216 struct eof_error(otype T) virtual(io_error) {217 FILE * file;218 }219 220 char const * what(eof_error &) {221 return "Tried to read from an empty file.";222 }223 224 FILE * which_file(eof_error & this) {225 return eof_error.file;226 }227 228 Ast Example:229 230 trait ast_node(otype T) virtual() {231 void print(T & this, ostream & out);232 void visit(T & this, Visitor & visitor);233 CodeLocation const & get_code_location(T & this);234 }235 236 trait expression_node(otype T) virtual(ast_node) {237 Type eval_type(T const & this);238 }239 240 struct operator_expression virtual(expression_node) {241 enum operator_kind kind;242 trait expression_node rands[2];243 }244 245 trait statement_node(otype T) virtual(ast_node) {246 vector(Label) & get_labels(T & this);247 }248 249 struct goto_statement virtual(statement_node) {250 vector(Label) labels;251 Label target;252 }253 254 trait declaration_node(otype T) virtual(ast_node) {255 string name_of(T const & this);256 Type type_of(T const & this);257 }258 259 struct using_declaration virtual(declaration_node) {260 string new_type;261 Type old_type;262 }263 264 struct variable_declaration virtual(declaration_node) {265 string name;266 Type type;267 }268 269 #### Sample Implementation270 The type id may be as little as:271 272 struct typeid {273 struct typeid const * const parent;274 };275 276 Some linker magic would have to be used to ensure exactly one copy of each277 structure for each type exists in memory. There seem to be spectial once278 sections that support this and it should be easier than generating unique279 ids across compilation units.280 281 The structure could be extended to contain any additional type information.282 283 There are two general designs for vtables with type ids. The first is to put284 the type id at the top of the vtable, this is the most compact and efficient285 solution but only works if we have exactly 1 vtable for each type. The second286 is to put a pointer to the type id in each vtable. This has more overhead but287 allows multiple vtables.288 289 struct <trait>_vtable {290 struct typeid const id;291 292 // Trait dependent list of vtable members.293 };294 295 struct <trait>_vtable {296 struct typeid const * const id;297 298 // Trait dependent list of vtable members.299 };300 301 ### Virtual Casts302 To convert from a pointer to a type higher on the hierarchy to one lower on303 the hierarchy a check is used to make sure that the underlying type is also304 of that lower type.305 306 The proposed syntax for this is:307 308 trait SubType * new_value = (virtual trait SubType *)super_type;309 310 It will return the same pointer if it does point to the subtype and null if311 it does not, doing the check and conversion in one operation.312 313 92 ### Inline vtables 314 93 Since the structures here are usually made to be turned into trait objects 315 94 it might be worth it to have fields on them to store the virtual table 316 pointer. This would have to be declared on the trait as an assertion (example: 317 `vtable;` or `T.vtable;`), but if it is the trait object could be a single 318 pointer. 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. 319 97 320 There are also three options for where the pointer to the vtable. It could be 321 anywhere, a fixed location for each trait or always at the front. For the per- 322 trait solution an extention to specify what it is (example `vtable[0];`) which 323 could also be used to combine it with others. So these options can be combined 324 to allow access to all three options. 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. 325 101 326 102 ### Virtual Tables as Types 327 Here we consider encoding plus the implementation of functions on it to be a328 type. Which is to say in the type hierarchy structures aren't concrete types 329 anymore, instead they are parent types to vtables, which combine the encoding 330 andimplementation.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. 331 107 332 108 Resolution Scope … … 347 123 other. 348 124 349 Some syntax would have to be added to specify the resolution point. To ensure 350 a single instance there may have to be two variants, one forward declaration 351 and one to create the instance. With some compiler magic the forward 352 declaration maybe enough. 353 354 extern trait combiner(struct summation) vtable; 355 trait combiner(struct summation) vtable; 356 357 Or (with the same variants): 358 359 vtable combiner(struct summation); 360 361 The extern variant promises that the vtable will exist while the normal one 362 is where the resolution actually happens. 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. 363 127 364 128 ### Explicit Resolution Points: … … 376 140 However this also means that stack-allocated functions can end up in the 377 141 vtable. 378 379 extern trait combiner(struct summation) vtable sum;380 trait combiner(struct summation) vtable sum;381 382 extern trait combiner(struct summation) vtable sum default;383 trait combiner(struct summation) vtable sum default;384 385 The extern difference is the same before. The name (sum in the samples) is386 used at the binding site to say which one is picked. The default keyword can387 be used in only some of the declarations.388 389 trait combiner fee = (summation_instance, sum);390 trait combiner foe = summation_instance;391 392 (I am not really happy about this syntax, but it kind of works.)393 The object being bound is required. The name of the vtable is optional if394 there is exactly one vtable name marked with default.395 396 These could also be placed inside functions. In which case both the name and397 the default keyword might be optional. If the name is ommited in an assignment398 the closest vtable is choosen (returning to the global default rule if no399 approprate local vtable is in scope).400 142 401 143 ### Site Based Resolution: -
doc/user/user.tex
rf343c6b r69c37cc 11 11 %% Created On : Wed Apr 6 14:53:29 2016 12 12 %% Last Modified By : Peter A. Buhr 13 %% Last Modified On : Sun Apr 14 11:02:34 201914 %% Update Count : 34 4313 %% Last Modified On : Tue Dec 11 23:19:26 2018 14 %% Update Count : 3400 15 15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 16 … … 508 508 509 509 As for \Index{division}, there are exponentiation operators for integral and floating types, including the builtin \Index{complex} types. 510 Integral exponentiation\index{exponentiation!unsigned integral} is performed with repeated multiplication\footnote{The multiplication computation is $O(\log y)$.} (or shifting if the exponent is 2). 511 Overflow from large exponents or negative exponents return zero. 512 Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative. 513 \begin{cfa} 514 sout | 1 ®\® 0 | 1 ®\® 1 | 2 ®\® 8 | -4 ®\® 3 | 5 ®\® 3 | 5 ®\® 32 | 5L ®\® 32 | 5L ®\® 64 | -4 ®\® -3 | -4.0 ®\® -3 | 4.0 ®\® 2.1 515 | (1.0f+2.0fi) ®\® (3.0f+2.0fi); 516 1 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i 517 \end{cfa} 518 Note, ©5 ®\® 32© and ©5L ®\® 64© overflow, and ©-4 ®\® -3© is a fraction but stored in an integer so all three computations generate an integral zero. 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} 519 518 Parenthesis are necessary for complex constants or the expression is parsed as ©1.0f+®(®2.0fi \ 3.0f®)®+2.0fi©. 520 The exponentiation operator is available for all the basic types, but for user-defined types, only the integral-computation version is available. 521 \begin{cfa} 522 forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) 523 OT ?®\®?( OT ep, unsigned int y ); 524 forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) 525 OT ?®\®?( OT ep, unsigned long int y ); 526 \end{cfa} 527 The user type ©T© must define multiplication, one, ©1©, and, ©*©. 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. 528 522 529 523 … … 555 549 \subsection{Loop Control} 556 550 557 The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges (see Figure~\ref{f:LoopControlExamples}). 558 \begin{itemize} 559 \item 551 The ©for©/©while©/©do-while© loop-control allows empty or simplified ranges. 560 552 An empty conditional implies ©1©. 561 \item 562 The up-to range ©~©\index{~@©~©} means exclusive range [M,N). 563 \item 564 The up-to range ©~=©\index{~=@©~=©} means inclusive range [M,N]. 565 \item 566 The down-to range ©-~©\index{-~@©-~©} means exclusive range [N,M). 567 \item 568 The down-to range ©-~=©\index{-~=@©-~=©} means inclusive range [N,M]. 569 \item 570 ©@© means put nothing in this field. 571 \item 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]. 572 557 ©0© is the implicit start value; 573 \item574 558 ©1© is the implicit increment value. 575 \item576 559 The up-to range uses ©+=© for increment; 577 \item 578 The down-to range uses ©-=© for decrement. 579 \item 560 the down-to range uses ©-=© for decrement. 580 561 The 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}584 562 \begin{cquote} 585 \begin{tabular}{@{}l |l@{}}586 \multicolumn{ 1}{c|}{loop control} & \multicolumn{1}{c}{output} \\563 \begin{tabular}{@{}ll|l@{}} 564 \multicolumn{2}{c|}{loop control} & \multicolumn{1}{c}{output} \\ 587 565 \hline 588 566 \begin{cfa} 589 sout | nlOff; 590 while ®()® { sout | "empty"; break; } sout | nl; 591 do { sout | "empty"; break; } while ®()®; sout | nl; 592 for ®()® { sout | "empty"; break; } sout | nl; 593 for ( ®0® ) { sout | "A"; } sout | "zero" | nl; 594 for ( ®1® ) { sout | "A"; } sout | nl; 595 for ( ®10® ) { sout | "A"; } sout | nl; 596 for ( ®1 ~= 10 ~ 2® ) { sout | "B"; } sout | nl; 597 for ( ®10 -~= 1 ~ 2® ) { sout | "C"; } sout | nl; 598 for ( ®0.5 ~ 5.5® ) { sout | "D"; } sout | nl; 599 for ( ®5.5 -~ 0.5® ) { sout | "E"; } sout | nl; 600 for ( ®i; 10® ) { sout | i; } sout | nl; 601 for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; } sout | nl; 602 for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; } sout | nl; 603 for ( ®i; 0.5 ~ 5.5® ) { sout | i; } sout | nl; 604 for ( ®i; 5.5 -~ 0.5® ) { sout | i; } sout | nl; 605 for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; } sout | nl; 606 for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; } sout | nl; 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; } 607 584 enum { N = 10 }; 608 for ( ®N® ) { sout | "N"; } sout | nl;609 for ( ®i; N® ) { sout | i; } sout | nl;610 for ( ®i; N -~ 0® ) { sout | i; } sout | nl;585 for ( ®N® ) { sout | "N"; } 586 for ( ®i; N® ) { sout | i; } 587 for ( ®i; N -~ 0® ) { sout | i; } 611 588 const int start = 3, comp = 10, inc = 2; 612 for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; } sout | nl; 613 for ( ®i; 1 ~ @® ) { if ( i > 10 ) break; 614 sout | i; } sout | nl; 615 for ( ®i; 10 -~ @® ) { if ( i < 0 ) break; 616 sout | i; } sout | nl; 617 for ( ®i; 2 ~ @ ~ 2® ) { if ( i > 10 ) break; 618 sout | i; } sout | nl; 619 for ( ®i; 2.1 ~ @ ~ @® ) { if ( i > 10.5 ) break; 620 sout | i; i += 1.7; } sout | nl; 621 for ( ®i; 10 -~ @ ~ 2® ) { if ( i < 0 ) break; 622 sout | i; } sout | nl; 623 for ( ®i; 12.1 ~ @ ~ @® ) { if ( i < 2.5 ) break; 624 sout | i; i -= 1.7; } sout | nl; 625 for ( ®i; 5 : j; -5 ~ @® ) { sout | i | j; } sout | nl; 626 for ( ®i; 5 : j; -5 -~ @® ) { sout | i | j; } sout | nl; 627 for ( ®i; 5 : j; -5 ~ @ ~ 2® ) { sout | i | j; } sout | nl; 628 for ( ®i; 5 : j; -5 -~ @ ~ 2® ) { sout | i | j; } sout | nl; 629 for ( ®j; -5 ~ @ : i; 5® ) { sout | i | j; } sout | nl; 630 for ( ®j; -5 -~ @ : i; 5® ) { sout | i | j; } sout | nl; 631 for ( ®j; -5 ~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl; 632 for ( ®j; -5 -~ @ ~ 2 : i; 5® ) { sout | i | j; } sout | nl; 633 for ( ®j; -5 -~ @ ~ 2 : i; 5 : k; 1.5 ~ @® ) { 634 sout | i | j | k; } sout | nl; 635 for ( ®j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 5® ) { 636 sout | i | j | k; } sout | nl; 637 for ( ®k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 5® ) { 638 sout | i | j | k; } sout | nl; 589 for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; } 639 590 \end{cfa} 640 591 & 641 592 \begin{cfa} 642 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} 643 619 empty 644 620 empty … … 664 640 665 641 3 6 9 666 667 1 2 3 4 5 6 7 8 9 10668 669 10 9 8 7 6 5 4 3 2 1 0670 671 2 4 6 8 10672 673 2.1 3.8 5.5 7.2 8.9674 675 10 8 6 4 2 0676 677 12.1 10.4 8.7 7 5.3 3.6678 0 -5 1 -4 2 -3 3 -2 4 -1679 0 -5 1 -6 2 -7 3 -8 4 -9680 0 -5 1 -3 2 -1 3 1 4 3681 0 -5 1 -7 2 -9 3 -11 4 -13682 0 -5 1 -4 2 -3 3 -2 4 -1683 0 -5 1 -6 2 -7 3 -8 4 -9684 0 -5 1 -3 2 -1 3 1 4 3685 0 -5 1 -7 2 -9 3 -11 4 -13686 687 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5688 689 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5690 691 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5692 642 \end{cfa} 693 643 \end{tabular} 694 644 \end{cquote} 695 \caption{Loop Control Examples}696 \label{f:LoopControlExamples}697 \end{figure}698 645 699 646 … … 1373 1320 \end{cfa} 1374 1321 Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}). 1375 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice, even though Dennis Richie believed otherwise: 1376 \begin{quote} 1377 In spite of its difficulties, I believe that the C's approach to declarations remains plausible, and am comfortable with it; it is a useful unifying principle.~\cite[p.~12]{Ritchie93} 1378 \end{quote} 1322 While attempting to make the two contexts consistent is a laudable goal, it has not worked out in practice. 1379 1323 1380 1324 \CFA provides its own type, variable and routine declarations, using a different syntax. -
libcfa/configure
rf343c6b r69c37cc 2977 2977 ;; 2978 2978 esac 2979 2980 CONFIG_CFAFLAGS="${CONFIG_CFAFLAGS} ${CFAFLAGS}"2981 2979 2982 2980 -
libcfa/configure.ac
rf343c6b r69c37cc 64 64 esac 65 65 66 CONFIG_CFAFLAGS="${CONFIG_CFAFLAGS} ${CFAFLAGS}"67 68 66 AC_SUBST(CONFIG_CFLAGS) 69 67 AC_SUBST(CONFIG_CFAFLAGS) -
libcfa/prelude/builtins.c
rf343c6b r69c37cc 10 10 // Created On : Fri Jul 21 16:21:03 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Mar 26 23:10:36201913 // Update Count : 9512 // Last Modified On : Sun Mar 10 10:52:50 2019 13 // Update Count : 31 14 14 // 15 15 … … 18 18 typedef unsigned long long __cfaabi_abi_exception_type_t; 19 19 20 #include <limits.h> // CHAR_BIT21 20 #include "../src/virtual.h" 22 21 #include "../src/exception.h" … … 27 26 // increment/decrement unification 28 27 29 static inline { 30 forall( dtype DT | { DT & ?+=?( DT &, one_t ); } ) 31 DT & ++?( DT & x ) { return x += 1; } 28 static inline forall( dtype T | { T & ?+=?( T &, one_t ); } ) 29 T & ++? ( T & x ) { return x += 1; } 32 30 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; }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; } 35 33 36 forall( dtype DT | { DT & ?-=?( DT &, one_t ); } )37 DT & --?( DT & x ) { return x -= 1; }34 static inline forall( dtype T | { T & ?-=?( T &, one_t ); } ) 35 T & --? ( T & x ) { return x -= 1; } 38 36 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 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; } 42 39 43 40 // universal typed pointer constant 44 // Compiler issue: there is a problem with anonymous types that do not have a size. 45 static inline forall( dtype DT | sized(DT) ) DT * intptr( uintptr_t addr ) { return (DT *)addr; }41 42 static inline forall( dtype T ) T * intptr( uintptr_t addr ) { return (T *)addr; } 46 43 47 44 // exponentiation operator implementation … … 56 53 } // extern "C" 57 54 58 static inline { 59 float ?\?( float x, float y ) { return powf( x, y ); } 60 double ?\?( double x, double y ) { return pow( x, y ); } 61 long double ?\?( long double x, long double y ) { return powl( x, y ); } 62 float _Complex ?\?( float _Complex x, _Complex float y ) { return cpowf(x, y ); } 63 double _Complex ?\?( double _Complex x, _Complex double y ) { return cpow( x, y ); } 64 long double _Complex ?\?( long double _Complex x, _Complex long double y ) { return cpowl( x, y ); } 65 } // distribution 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 ); } 66 61 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 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 } // ?\? 70 72 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 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 } // ?\? 82 83 83 static inline { 84 long int ?\?( int ep, unsigned int y ) { __CFA_EXP__(); } 85 long int ?\?( long int ep, unsigned long int y ) { __CFA_EXP__(); } 86 // unsigned computation may be faster and larger 87 unsigned long int ?\?( unsigned int ep, unsigned int y ) { __CFA_EXP__(); } 88 unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { __CFA_EXP__(); } 89 } // distribution 84 // unsigned computation may be faster and larger 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 } // ?\? 90 95 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__() 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 } // ?\? 97 100 98 static inline forall( otype OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) { 99 OT ?\?( OT ep, unsigned int y ) { __CFA_EXP__(); } 100 OT ?\?( OT ep, unsigned long int y ) { __CFA_EXP__(); } 101 } // distribution 101 // FIXME (x \ (unsigned long int)y) relies on X ?\?(T, unsigned long) a function that is neither 102 // defined, nor passed as an assertion parameter. Without user-defined conversions, cannot specify 103 // X as a type that casts to double, yet it doesn't make sense to write functions with that type 104 // signature where X is double. 102 105 103 #undef __CFA_BASE_COMP_1__ 104 #undef __CFA_BASE_COMP_2__ 105 #undef __CFA_EXP_OVERFLOW__ 106 // static inline forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); double ?/?( double, T ); } ) 107 // double ?\?( T x, signed long int y ) { 108 // if ( y >= 0 ) return (double)(x \ (unsigned long int)y); 109 // else return 1.0 / x \ (unsigned long int)(-y); 110 // } // ?\? 106 111 107 static inline { 108 long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; } 109 unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; } 110 int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; } 111 unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; } 112 } // distribution 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; } 113 116 114 117 // Local Variables: // -
libcfa/prelude/prelude-gen.cc
rf343c6b r69c37cc 10 10 // Created On : Sat Feb 16 08:44:58 2019 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Apr 2 17:18:24201913 // Update Count : 3712 // Last Modified On : Fri Mar 8 16:00:22 2019 13 // Update Count : 26 14 14 // 15 15 … … 118 118 { "?!=?", false, "signed int", Normal, "" }, 119 119 { "?=?", true, "", Normal, "" }, // void * LHS, zero_t RHS ??? 120 // { "*?", false, "&", Normal, " | sized(DT)" }, // & ??? 121 { "*?", false, "&", Normal, "" }, // & ??? 120 { "*?", false, "&", Normal, " | sized(DT)" }, // & ??? 122 121 123 122 { "?-?", false, "ptrdiff_t", Normal, " | sized(DT)" }, … … 209 208 cout << "void ?{} (" << type << " &);" << endl; 210 209 cout << "void ?{} (" << type << " &, " << type << ");" << endl; 211 cout << type << " ?=? (" << type << " &, " << type << ")";210 cout << type << " ?=? (" << type << " &, " << type << ")"; 212 211 if ( do_volatile ) { 213 cout << ", ?=?(volatile " << type << " &, " << type << ")";212 cout << ", ?=?(volatile " << type << " &, " << type << ")"; 214 213 } 215 214 cout << ";" << endl; … … 218 217 219 218 otype("zero_t"); 220 cout << endl;221 219 otype("one_t"); 222 cout << endl;223 220 otype("_Bool", true); 224 221 cout << endl; … … 228 225 cout << "void ?{}(" << type.name << " &, " << type.name << ");" << endl; 229 226 cout << "void ?{}(" << type.name << " &, zero_t);" << endl; 230 cout << "void ?{}(" << type.name << " &, one_t);" << endl;231 227 cout << "void ^?{}(" << type.name << " &);" << endl; 232 228 cout << endl; -
libcfa/src/Makefile.am
rf343c6b r69c37cc 74 74 75 75 prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@ 76 ${AM_V_GEN} $(CFACOMPILE) -quiet -in-tree-XCFA -l ${<} -c -o ${@}76 ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@} 77 77 78 78 prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@ 79 79 ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \ 80 $(CFACOMPILE) -quiet -in-tree-XCFA -l ${<} -c -o ${@}80 @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@} 81 81 82 82 -
libcfa/src/Makefile.in
rf343c6b r69c37cc 926 926 927 927 prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@ 928 ${AM_V_GEN} $(CFACOMPILE) -quiet -in-tree-XCFA -l ${<} -c -o ${@}928 ${AM_V_GEN}@CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@} 929 929 930 930 prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @CFACC@ @CFACPP@ 931 931 ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \ 932 $(CFACOMPILE) -quiet -in-tree-XCFA -l ${<} -c -o ${@}932 @CFACC@ ${AM_CFLAGS} ${CFLAGS} -quiet -in-tree @CONFIG_CFAFLAGS@ -XCFA -l ${<} -c -o ${@} 933 933 934 934 #---------------------------------------------------------------------------------------------------------------- -
libcfa/src/concurrency/CtxSwitch-x86_64.S
rf343c6b r69c37cc 88 88 ret 89 89 90 //.text91 // .align 292 //.globl CtxStore93 //CtxStore:94 // // Save floating & SSE control words on the stack.95 //96 // subq $8,%rsp97 // stmxcsr 0(%rsp) // 4 bytes98 // fnstcw 4(%rsp) // 2 bytes99 //100 // // Save volatile registers on the stack.101 //102 // pushq %r15103 // pushq %r14104 // pushq %r13105 // pushq %r12106 // pushq %rbx107 //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 thread114 //115 // ret116 //117 //.text118 // .align 2119 //.globl CtxRet120 //CtxRet:121 // // Load new context from the "to" area.122 //123 // movq SP_OFFSET(%rdi),%rsp124 // movq FP_OFFSET(%rdi),%rbp125 //126 // // Load volatile registers from the stack.127 //128 // popq %rbx129 // popq %r12130 // popq %r13131 // popq %r14132 // popq %r15133 //134 // // Load floating & SSE control words from the stack.135 //136 // fldcw 4(%rsp)137 // ldmxcsr 0(%rsp)138 // addq $8,%rsp139 //140 // // Return to thread.141 //142 // ret143 144 145 90 .text 146 91 .align 2 -
libcfa/src/concurrency/coroutine.cfa
rf343c6b r69c37cc 35 35 36 36 extern "C" { 37 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage , struct coroutine_desc *) __attribute__ ((__noreturn__));37 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage) __attribute__ ((__noreturn__)); 38 38 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) __attribute__ ((__noreturn__)); 39 39 static void _CtxCoroutine_UnwindCleanup(_Unwind_Reason_Code, struct _Unwind_Exception *) { … … 84 84 void ^?{}(coroutine_desc& this) { 85 85 if(this.state != Halted && this.state != Start) { 86 coroutine_desc * src = TL_GET( this_ thread )->curr_cor;86 coroutine_desc * src = TL_GET( this_coroutine ); 87 87 coroutine_desc * dst = &this; 88 88 … … 115 115 // Wrapper for co 116 116 void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) { 117 // Safety note : Preemption must be disabled since there is a race condition 118 // kernelTLS.this_thread->curr_cor and $rsp/$rbp must agree at all times 117 // Safety note : This could cause some false positives due to preemption 119 118 verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate ); 120 119 disable_interrupts(); … … 124 123 125 124 // set new coroutine that task is executing 126 TL_GET( this_thread )->curr_cor= dst;125 kernelTLS.this_coroutine = dst; 127 126 128 127 // context switch to specified coroutine … … 135 134 136 135 enable_interrupts( __cfaabi_dbg_ctx ); 136 // Safety note : This could cause some false positives due to preemption 137 137 verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate ); 138 138 139 140 139 if( unlikely(src->cancellation != NULL) ) { 141 _CtxCoroutine_Unwind(src->cancellation , src);140 _CtxCoroutine_Unwind(src->cancellation); 142 141 } 143 142 } //ctxSwitchDirect … … 198 197 } 199 198 200 void __leave_coroutine( coroutine_desc * src ) { 199 void __leave_coroutine() { 200 coroutine_desc * src = TL_GET( this_coroutine ); // optimization 201 201 coroutine_desc * starter = src->cancellation != 0 ? src->last : src->starter; 202 202 -
libcfa/src/concurrency/coroutine.hfa
rf343c6b r69c37cc 46 46 //----------------------------------------------------------------------------- 47 47 // Public coroutine API 48 static inline void suspend( void);48 static inline void suspend(); 49 49 50 50 forall(dtype T | is_coroutine(T)) … … 71 71 72 72 // Suspend implementation inlined for performance 73 static inline void suspend( void) {73 static inline void suspend() { 74 74 // optimization : read TLS once and reuse it 75 75 // Safety note: this is preemption safe since if … … 77 77 // will also migrate which means this value will 78 78 // stay in syn with the TLS 79 coroutine_desc * src = TL_GET( this_ thread )->curr_cor;79 coroutine_desc * src = TL_GET( this_coroutine ); 80 80 81 81 assertf( src->last != 0, … … 99 99 // will also migrate which means this value will 100 100 // stay in syn with the TLS 101 coroutine_desc * src = TL_GET( this_ thread )->curr_cor;101 coroutine_desc * src = TL_GET( this_coroutine ); 102 102 coroutine_desc * dst = get_coroutine(cor); 103 103 … … 129 129 // will also migrate which means this value will 130 130 // stay in syn with the TLS 131 coroutine_desc * src = TL_GET( this_ thread )->curr_cor;131 coroutine_desc * src = TL_GET( this_coroutine ); 132 132 133 133 // not resuming self ? … … 146 146 } 147 147 148 149 150 // static inline bool suspend_checkpoint(void) {151 // // optimization : read TLS once and reuse it152 // // Safety note: this is preemption safe since if153 // // preemption occurs after this line, the pointer154 // // will also migrate which means this value will155 // // stay in syn with the TLS156 // // set state of current coroutine to inactive157 // this->state = Checkpoint;158 159 // // context switch to specified coroutine160 // 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 active167 // src->state = Active;168 169 // enable_interrupts( __cfaabi_dbg_ctx );170 // // Safety note : This could cause some false positives due to preemption171 // 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 it182 // // Safety note: this is preemption safe since if183 // // preemption occurs after this line, the pointer184 // // will also migrate which means this value will185 // // stay in syn with the TLS186 // 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 date198 // verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );199 // disable_interrupts();200 201 // // set state of current coroutine to inactive202 // src->state = src->state == Halted ? Halted : Inactive;203 204 // // set new coroutine that task is executing205 // kernelTLS.this_coroutine = dst;206 207 // // context switch to specified coroutine208 // assert( src->stack.context );209 // CtxRet( src->stack.context );210 211 // abort();212 // }213 214 148 // Local Variables: // 215 149 // mode: c // -
libcfa/src/concurrency/invoke.c
rf343c6b r69c37cc 28 28 29 29 extern void __suspend_internal(void); 30 extern void __leave_coroutine( struct coroutine_desc *);31 extern void __finish_creation( struct coroutine_desc *);30 extern void __leave_coroutine(void); 31 extern void __finish_creation(void); 32 32 extern void __leave_thread_monitor( struct thread_desc * this ); 33 33 extern void disable_interrupts(); … … 52 52 53 53 //Final suspend, should never return 54 __leave_coroutine( cor);54 __leave_coroutine(); 55 55 __cabi_abort( "Resumed dead coroutine" ); 56 56 } … … 62 62 __attribute((__unused__)) struct _Unwind_Exception * unwind_exception, 63 63 __attribute((__unused__)) struct _Unwind_Context * context, 64 void * param64 __attribute((__unused__)) void * param 65 65 ) { 66 66 if( actions & _UA_END_OF_STACK ) { 67 67 // We finished unwinding the coroutine, 68 68 // leave it 69 __leave_coroutine( param);69 __leave_coroutine(); 70 70 __cabi_abort( "Resumed dead coroutine" ); 71 71 } … … 75 75 } 76 76 77 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage , struct coroutine_desc * cor) __attribute__ ((__noreturn__));78 void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage , struct coroutine_desc * cor) {79 _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, _CtxCoroutine_UnwindStop, cor);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 ); 80 80 printf("UNWIND ERROR %d after force unwind\n", ret); 81 81 abort(); … … 88 88 void *this 89 89 ) { 90 // First suspend, once the thread arrives here, 91 // the function pointer to main can be invalidated without risk 92 __finish_creation(); 93 90 94 // Fetch the thread handle from the user defined thread structure 91 95 struct thread_desc* thrd = get_thread( this ); 92 93 // First suspend, once the thread arrives here,94 // the function pointer to main can be invalidated without risk95 __finish_creation(&thrd->self_cor);96 97 // Restore the last to NULL, we clobbered because of the thunk problem98 96 thrd->self_cor.last = NULL; 99 97 -
libcfa/src/concurrency/invoke.h
rf343c6b r69c37cc 50 50 51 51 extern thread_local struct KernelThreadData { 52 struct coroutine_desc * volatile this_coroutine; 52 53 struct thread_desc * volatile this_thread; 53 54 struct processor * volatile this_processor; … … 60 61 } kernelTLS __attribute__ ((tls_model ( "initial-exec" ))); 61 62 } 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 62 67 #endif 63 68 … … 165 170 struct thread_desc * prev; 166 171 } node; 167 }; 168 169 #ifdef __cforall 170 extern "Cforall" { 171 static inline struct coroutine_desc * volatile active_coroutine() { return TL_GET( this_thread )->curr_cor; } 172 static inline struct thread_desc * volatile active_thread () { return TL_GET( this_thread ); } 173 static inline struct processor * volatile active_processor() { return TL_GET( this_processor ); } // UNSAFE 174 172 }; 173 174 #ifdef __cforall 175 extern "Cforall" { 175 176 static inline thread_desc * & get_next( thread_desc & this ) { 176 177 return this.next; … … 231 232 extern void CtxInvokeStub( void ); 232 233 void CtxSwitch( void * from, void * to ) asm ("CtxSwitch"); 233 // void CtxStore ( void * this ) asm ("CtxStore");234 // void CtxRet ( void * dst ) asm ("CtxRet");235 234 236 235 #if defined( __i386 ) -
libcfa/src/concurrency/kernel.cfa
rf343c6b r69c37cc 60 60 NULL, 61 61 NULL, 62 NULL, 62 63 { 1, false, false } 63 64 }; … … 262 263 static void returnToKernel() { 263 264 coroutine_desc * proc_cor = get_coroutine(kernelTLS.this_processor->runner); 264 coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor ;265 coroutine_desc * thrd_cor = kernelTLS.this_thread->curr_cor = kernelTLS.this_coroutine; 265 266 ThreadCtxSwitch(thrd_cor, proc_cor); 266 267 } … … 306 307 processor * proc = (processor *) arg; 307 308 kernelTLS.this_processor = proc; 309 kernelTLS.this_coroutine = NULL; 308 310 kernelTLS.this_thread = NULL; 309 311 kernelTLS.preemption_state.[enabled, disable_count] = [false, 1]; … … 319 321 320 322 //Set global state 323 kernelTLS.this_coroutine = get_coroutine(proc->runner); 321 324 kernelTLS.this_thread = NULL; 322 325 … … 348 351 // KERNEL_ONLY 349 352 void kernel_first_resume(processor * this) { 350 coroutine_desc * src = mainThread->curr_cor;353 coroutine_desc * src = kernelTLS.this_coroutine; 351 354 coroutine_desc * dst = get_coroutine(this->runner); 352 355 … … 363 366 // set state of current coroutine to inactive 364 367 src->state = src->state == Halted ? Halted : Inactive; 368 369 // set new coroutine that task is executing 370 kernelTLS.this_coroutine = dst; 365 371 366 372 // SKULLDUGGERY normally interrupts are enable before leaving a coroutine ctxswitch. … … 593 599 kernelTLS.this_processor = mainProcessor; 594 600 kernelTLS.this_thread = mainThread; 601 kernelTLS.this_coroutine = &mainThread->self_cor; 595 602 596 603 // Enable preemption … … 713 720 __cfaabi_dbg_bits_write( abort_text, len ); 714 721 715 if ( &thrd->self_cor != thrd->curr_cor) {716 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", thrd->curr_cor->name, thrd->curr_cor);722 if ( get_coroutine(thrd) != kernelTLS.this_coroutine ) { 723 len = snprintf( abort_text, abort_text_size, " in coroutine %.256s (%p).\n", kernelTLS.this_coroutine->name, kernelTLS.this_coroutine ); 717 724 __cfaabi_dbg_bits_write( abort_text, len ); 718 725 } -
libcfa/src/concurrency/thread.cfa
rf343c6b r69c37cc 75 75 coroutine_desc* thrd_c = get_coroutine(this); 76 76 thread_desc * thrd_h = get_thread (this); 77 thrd_c->last = TL_GET( this_ thread )->curr_cor;77 thrd_c->last = TL_GET( this_coroutine ); 78 78 79 79 // __cfaabi_dbg_print_safe("Thread start : %p (t %p, c %p)\n", this, thrd_c, thrd_h); … … 81 81 disable_interrupts(); 82 82 create_stack(&thrd_c->stack, thrd_c->stack.size); 83 kernelTLS.this_coroutine = thrd_c; 83 84 CtxStart(&this, CtxInvokeThread); 84 85 assert( thrd_c->last->stack.context ); … … 91 92 extern "C" { 92 93 // KERNEL ONLY 93 void __finish_creation(coroutine_desc * thrd_c) { 94 void __finish_creation(void) { 95 coroutine_desc* thrd_c = kernelTLS.this_coroutine; 94 96 ThreadCtxSwitch( thrd_c, thrd_c->last ); 95 97 } … … 118 120 // set new coroutine that the processor is executing 119 121 // and context switch to it 122 kernelTLS.this_coroutine = dst; 120 123 assert( src->stack.context ); 121 124 CtxSwitch( src->stack.context, dst->stack.context ); 125 kernelTLS.this_coroutine = src; 122 126 123 127 // set state of new coroutine to active -
libcfa/src/fstream.cfa
rf343c6b r69c37cc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Apr 20 12:03:43 201913 // Update Count : 3 1112 // Last Modified On : Mon Dec 24 18:33:38 2018 13 // Update Count : 304 14 14 // 15 15 … … 23 23 #include <complex.h> // creal, cimag 24 24 #include <assert.h> 25 #include <errno.h> // errno26 25 27 26 #define IO_MSG "I/O error: " … … 33 32 os.nlOnOff = nlOnOff; 34 33 os.prt = prt; 35 os.sawNL = false;36 34 sepSet( os, separator ); 37 35 sepSetCur( os, sepGet( os ) ); … … 107 105 #ifdef __CFA_DEBUG__ 108 106 if ( file == 0 ) { 109 abort( IO_MSG "open output file \"%s\", %s", name, strerror( errno ) ); 107 fprintf( stderr, IO_MSG "open output file \"%s\", ", name ); 108 perror( 0 ); 109 exit( EXIT_FAILURE ); 110 110 } // if 111 111 #endif // __CFA_DEBUG__ … … 121 121 122 122 if ( fclose( (FILE *)(os.file) ) == EOF ) { 123 abort( IO_MSG "close output %s", strerror( errno ));123 perror( IO_MSG "close output" ); 124 124 } // if 125 125 } // close … … 127 127 ofstream & write( ofstream & os, const char * data, size_t size ) { 128 128 if ( fail( os ) ) { 129 abort( "attempt write I/O on failed stream\n" ); 129 fprintf( stderr, "attempt write I/O on failed stream\n" ); 130 exit( EXIT_FAILURE ); 130 131 } // if 131 132 132 133 if ( fwrite( data, 1, size, (FILE *)(os.file) ) != size ) { 133 abort( IO_MSG "write %s", strerror( errno ) ); 134 perror( IO_MSG "write" ); 135 exit( EXIT_FAILURE ); 134 136 } // if 135 137 return os; … … 142 144 if ( len == EOF ) { 143 145 if ( ferror( (FILE *)(os.file) ) ) { 144 abort( "invalid write\n" ); 146 fprintf( stderr, "invalid write\n" ); 147 exit( EXIT_FAILURE ); 145 148 } // if 146 149 } // if … … 163 166 void ?{}( ifstream & is, void * file ) { 164 167 is.file = file; 165 is.nlOnOff = false;166 168 } 167 169 … … 175 177 open( is, name, "r" ); 176 178 } 177 178 void nlOn( ifstream & os ) { os.nlOnOff = true; }179 void nlOff( ifstream & os ) { os.nlOnOff = false; }180 bool getANL( ifstream & os ) { return os.nlOnOff; }181 179 182 180 int fail( ifstream & is ) { … … 189 187 190 188 void open( ifstream & is, const char * name, const char * mode ) { 191 FILE * file = fopen( name, mode );189 FILE *file = fopen( name, mode ); 192 190 #ifdef __CFA_DEBUG__ 193 191 if ( file == 0 ) { 194 abort( IO_MSG "open input file \"%s\", %s\n", name, strerror( errno ) ); 192 fprintf( stderr, IO_MSG "open input file \"%s\", ", name ); 193 perror( 0 ); 194 exit( EXIT_FAILURE ); 195 195 } // if 196 196 #endif // __CFA_DEBUG__ … … 206 206 207 207 if ( fclose( (FILE *)(is.file) ) == EOF ) { 208 abort( IO_MSG "close input %s", strerror( errno ));208 perror( IO_MSG "close input" ); 209 209 } // if 210 210 } // close … … 212 212 ifstream & read( ifstream & is, char * data, size_t size ) { 213 213 if ( fail( is ) ) { 214 abort( "attempt read I/O on failed stream\n" ); 214 fprintf( stderr, "attempt read I/O on failed stream\n" ); 215 exit( EXIT_FAILURE ); 215 216 } // if 216 217 217 218 if ( fread( data, size, 1, (FILE *)(is.file) ) == 0 ) { 218 abort( IO_MSG "read %s", strerror( errno ) ); 219 perror( IO_MSG "read" ); 220 exit( EXIT_FAILURE ); 219 221 } // if 220 222 return is; … … 223 225 ifstream &ungetc( ifstream & is, char c ) { 224 226 if ( fail( is ) ) { 225 abort( "attempt ungetc I/O on failed stream\n" ); 227 fprintf( stderr, "attempt ungetc I/O on failed stream\n" ); 228 exit( EXIT_FAILURE ); 226 229 } // if 227 230 228 231 if ( ungetc( c, (FILE *)(is.file) ) == EOF ) { 229 abort( IO_MSG "ungetc %s", strerror( errno ) ); 232 perror( IO_MSG "ungetc" ); 233 exit( EXIT_FAILURE ); 230 234 } // if 231 235 return is; … … 239 243 if ( len == EOF ) { 240 244 if ( ferror( (FILE *)(is.file) ) ) { 241 abort( "invalid read\n" ); 245 fprintf( stderr, "invalid read\n" ); 246 exit( EXIT_FAILURE ); 242 247 } // if 243 248 } // if -
libcfa/src/fstream.hfa
rf343c6b r69c37cc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Apr 20 12:03:58 201913 // Update Count : 1 5112 // Last Modified On : Mon Dec 24 18:33:41 2018 13 // Update Count : 149 14 14 // 15 15 … … 73 73 struct ifstream { 74 74 void * file; 75 bool nlOnOff;76 75 }; // ifstream 77 76 78 77 // public 79 void nlOn( ifstream & );80 void nlOff( ifstream & );81 bool getANL( ifstream & );82 78 int fail( ifstream & is ); 83 79 int eof( ifstream & is ); -
libcfa/src/gmp.hfa
rf343c6b r69c37cc 10 10 // Created On : Tue Apr 19 08:43:43 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Apr 20 09:01:52 201913 // Update Count : 2 412 // Last Modified On : Tue Dec 4 23:25:51 2018 13 // Update Count : 22 14 14 // 15 15 … … 271 271 272 272 void ?|?( ostype & os, Int mp ) { 273 (ostype)(os | mp); nl( os );273 (ostype)(os | mp); if ( getANL( os ) ) nl( os ); 274 274 } // ?|? 275 275 } // distribution -
libcfa/src/heap.cfa
rf343c6b r69c37cc 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:43:10 201913 // Update Count : 51 412 // Last Modified On : Thu Sep 6 09:01:30 2018 13 // Update Count : 513 14 14 // 15 15 … … 1034 1034 // Local Variables: // 1035 1035 // tab-width: 4 // 1036 // compile-command: "cfa -nodebug -O2 heap.c fa" //1036 // compile-command: "cfa -nodebug -O2 heap.c" // 1037 1037 // End: // -
libcfa/src/iostream.cfa
rf343c6b r69c37cc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Apr 20 14:02:43201913 // Update Count : 61712 // Last Modified On : Mon Mar 4 20:57:24 2019 13 // Update Count : 593 14 14 // 15 15 … … 396 396 397 397 istype & ?|?( istype & is, char & c ) { 398 char temp; 399 for () { 400 fmt( is, "%c", &temp ); // must pass pointer through varg to fmt 401 // do not overwrite parameter with newline unless appropriate 402 if ( temp != '\n' || getANL( is ) ) { c = temp; break; } 403 if ( eof( is ) ) break; 404 } // for 398 fmt( is, "%c", &c ); // must pass pointer through varg to fmt 405 399 return is; 406 400 } // ?|? … … 504 498 return is; 505 499 } // nl 506 507 istype & nlOn( istype & is ) {508 nlOn( is ); // call void returning509 return is;510 } // nlOn511 512 istype & nlOff( istype & is ) {513 nlOff( is ); // call void returning514 return is;515 } // nlOff516 500 } // distribution 517 501 -
libcfa/src/iostream.hfa
rf343c6b r69c37cc 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Apr 20 12:04:07201913 // Update Count : 22 612 // Last Modified On : Tue Feb 26 16:57:22 2019 13 // Update Count : 221 14 14 // 15 15 … … 149 149 150 150 trait istream( dtype istype ) { 151 void nlOn( istype & ); // read newline152 void nlOff( istype & ); // scan newline153 bool getANL( istype & ); // get scan newline (on/off)154 151 int fail( istype & ); 155 152 int eof( istype & ); … … 190 187 191 188 // manipulators 192 istype & nlOn( istype & );193 istype & nlOff( istype & );194 189 istype & ?|?( istype &, istype & (*)( istype & ) ); 195 190 istype & nl( istype & is ); -
libcfa/src/rational.cfa
rf343c6b r69c37cc 10 10 // Created On : Wed Apr 6 17:54:28 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Mar 28 17:33:03 201913 // Update Count : 1 8112 // Last Modified On : Sun Dec 23 22:56:49 2018 13 // Update Count : 170 14 14 // 15 15 … … 35 35 static RationalImpl simplify( RationalImpl & n, RationalImpl & d ) { 36 36 if ( d == (RationalImpl){0} ) { 37 abort( "Invalid rational number construction: denominator cannot be equal to 0.\n" ); 37 serr | "Invalid rational number construction: denominator cannot be equal to 0."; 38 exit( EXIT_FAILURE ); 38 39 } // exit 39 40 if ( d < (RationalImpl){0} ) { d = -d; n = -n; } // move sign to numerator … … 53 54 void ?{}( Rational(RationalImpl) & r, RationalImpl n, RationalImpl d ) { 54 55 RationalImpl t = simplify( n, d ); // simplify 55 r.[numerator, denominator] = [n / t, d / t]; 56 r.numerator = n / t; 57 r.denominator = d / t; 56 58 } // rational 57 59 … … 76 78 RationalImpl prev = r.numerator; 77 79 RationalImpl t = gcd( abs( n ), r.denominator ); // simplify 78 r.[numerator, denominator] = [n / t, r.denominator / t]; 80 r.numerator = n / t; 81 r.denominator = r.denominator / t; 79 82 return prev; 80 83 } // numerator … … 83 86 RationalImpl prev = r.denominator; 84 87 RationalImpl t = simplify( r.numerator, d ); // simplify 85 r.[numerator, denominator] = [r.numerator / t, d / t]; 88 r.numerator = r.numerator / t; 89 r.denominator = d / t; 86 90 return prev; 87 91 } // denominator … … 116 120 117 121 Rational(RationalImpl) +?( Rational(RationalImpl) r ) { 118 return (Rational(RationalImpl)){ r.numerator, r.denominator }; 122 Rational(RationalImpl) t = { r.numerator, r.denominator }; 123 return t; 119 124 } // +? 120 125 121 126 Rational(RationalImpl) -?( Rational(RationalImpl) r ) { 122 return (Rational(RationalImpl)){ -r.numerator, r.denominator }; 127 Rational(RationalImpl) t = { -r.numerator, r.denominator }; 128 return t; 123 129 } // -? 124 130 125 131 Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 126 132 if ( l.denominator == r.denominator ) { // special case 127 return (Rational(RationalImpl)){ l.numerator + r.numerator, l.denominator }; 133 Rational(RationalImpl) t = { l.numerator + r.numerator, l.denominator }; 134 return t; 128 135 } else { 129 return (Rational(RationalImpl)){ l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator }; 136 Rational(RationalImpl) t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator }; 137 return t; 130 138 } // if 131 139 } // ?+? … … 133 141 Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 134 142 if ( l.denominator == r.denominator ) { // special case 135 return (Rational(RationalImpl)){ l.numerator - r.numerator, l.denominator }; 143 Rational(RationalImpl) t = { l.numerator - r.numerator, l.denominator }; 144 return t; 136 145 } else { 137 return (Rational(RationalImpl)){ l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator }; 146 Rational(RationalImpl) t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator }; 147 return t; 138 148 } // if 139 149 } // ?-? 140 150 141 151 Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 142 return (Rational(RationalImpl)){ l.numerator * r.numerator, l.denominator * r.denominator }; 152 Rational(RationalImpl) t = { l.numerator * r.numerator, l.denominator * r.denominator }; 153 return t; 143 154 } // ?*? 144 155 145 156 Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { 146 157 if ( r.numerator < (RationalImpl){0} ) { 147 r.[numerator, denominator] = [-r.numerator, -r.denominator]; 158 r.numerator = -r.numerator; 159 r.denominator = -r.denominator; 148 160 } // if 149 return (Rational(RationalImpl)){ l.numerator * r.denominator, l.denominator * r.numerator }; 161 Rational(RationalImpl) t = { l.numerator * r.denominator, l.denominator * r.numerator }; 162 return t; 150 163 } // ?/? 151 164 … … 154 167 forall( dtype istype | istream( istype ) | { istype & ?|?( istype &, RationalImpl & ); } ) 155 168 istype & ?|?( istype & is, Rational(RationalImpl) & r ) { 169 RationalImpl t; 156 170 is | r.numerator | r.denominator; 157 RationalImplt = simplify( r.numerator, r.denominator );171 t = simplify( r.numerator, r.denominator ); 158 172 r.numerator /= t; 159 173 r.denominator /= t; … … 171 185 } // distribution 172 186 } // distribution 173 174 forall( otype RationalImpl | arithmetic( RationalImpl ) | { RationalImpl ?\?( RationalImpl, unsigned long ); } )175 Rational(RationalImpl) ?\?( Rational(RationalImpl) x, long int y ) {176 if ( y < 0 ) {177 return (Rational(RationalImpl)){ x.denominator \ -y, x.numerator \ -y };178 } else {179 return (Rational(RationalImpl)){ x.numerator \ y, x.denominator \ y };180 } // if181 }182 187 183 188 // conversion -
libcfa/src/rational.hfa
rf343c6b r69c37cc 12 12 // Created On : Wed Apr 6 17:56:25 2016 13 13 // Last Modified By : Peter A. Buhr 14 // Last Modified On : Tue Mar 26 23:16:10 201915 // Update Count : 10 914 // Last Modified On : Tue Dec 4 23:07:46 2018 15 // Update Count : 106 16 16 // 17 17 … … 98 98 } // distribution 99 99 100 forall( otype RationalImpl | arithmetic( RationalImpl ) |{RationalImpl ?\?( RationalImpl, unsigned long );} )101 Rational(RationalImpl) ?\?( Rational(RationalImpl) x, long int y );102 103 100 // conversion 104 101 forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); } ) -
libcfa/src/stdhdr/stdbool.h
rf343c6b r69c37cc 10 10 // Created On : Mon Jul 4 23:25:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 25 08:00:08 201913 // Update Count : 1 512 // Last Modified On : Tue Jul 5 20:39:51 2016 13 // Update Count : 12 14 14 // 15 15 16 16 extern "C" { 17 17 #include_next <stdbool.h> // has internal check for multiple expansion 18 19 // allows printing as true/false20 #if defined( true )21 #undef true22 #define true ((_Bool)1)23 #endif // true24 25 #if defined( false )26 #undef false27 #define false ((_Bool)0)28 #endif // false29 18 } // extern "C" 30 19 -
libcfa/src/stdlib.hfa
rf343c6b r69c37cc 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Apr 24 17:35:43 201913 // Update Count : 3 5212 // Last Modified On : Mon Dec 17 15:37:45 2018 13 // Update Count : 346 14 14 // 15 15 … … 40 40 } // malloc 41 41 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 42 49 T * calloc( size_t dim ) { 43 50 return (T *)(void *)calloc( dim, sizeof(T) ); // C calloc … … 69 76 T * alloc( char fill ) { 70 77 T * ptr = (T *)(void *)malloc( (size_t)sizeof(T) ); // C malloc 71 return (T *)memset( ptr, (int)fill, sizeof(T) ); // initializewith fill value78 return (T *)memset( ptr, (int)fill, sizeof(T) ); // initial with fill value 72 79 } // alloc 73 80 … … 77 84 78 85 T * alloc( size_t dim, char fill ) { 79 T * ptr = (T *)(void *)malloc( dim * (size_t)sizeof(T) ); // C calloc80 return (T *)memset( ptr, (int)fill, dim * sizeof(T) ); // initializewith fill value86 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 81 88 } // alloc 82 89 -
src/Common/PassVisitor.cc
rf343c6b r69c37cc 17 17 18 18 PassVisitorStats pass_visitor_stats; 19 Stats::Counters::SimpleCounter* BaseSyntaxNode::new_nodes = nullptr; -
src/Common/Stats/Counter.h
rf343c6b r69c37cc 37 37 class SimpleCounter { 38 38 public: 39 inline void operator++() {}40 39 inline void operator++(int) {} 41 40 inline void operator+=(size_t) {} … … 85 84 virtual void print(std::ostream & os) override { os << count; } 86 85 87 inline void operator++() { if(!enabled) return; count++; }88 86 inline void operator++(int) { if(!enabled) return; count++; } 89 87 inline void operator+=(size_t value) { if(!enabled) return; count += value; } -
src/ControlStruct/ForExprMutator.cc
rf343c6b r69c37cc 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Mar 11 22:26:52 201913 // Update Count : 1 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Aug 18 10:22:00 2017 13 // Update Count : 12 14 14 // 15 15 … … 21 21 22 22 namespace ControlStruct { 23 Statement * hoist( Statement * originalStmt, std::list<Statement *> &init ) {23 Statement *hoist( Statement *originalStmt, std::list<Statement *> &init ) { 24 24 // If no hoisting is needed, skip: 25 25 if ( 0 == init.size() ) { … … 29 29 // Create compound statement, move initializers outside, 30 30 // 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(); 33 33 stmts.splice( stmts.end(), init ); 34 34 … … 38 38 } 39 39 40 Statement * ForExprMutator::postmutate( IfStmt *ifStmt ) {40 Statement *ForExprMutator::postmutate( IfStmt *ifStmt ) { 41 41 return hoist( ifStmt, ifStmt->initialization ); 42 42 } 43 Statement * ForExprMutator::postmutate( ForStmt *forStmt ) {43 Statement *ForExprMutator::postmutate( ForStmt *forStmt ) { 44 44 // hoist any initializer declarations to make them C89 (rather than C99) 45 45 return hoist( forStmt, forStmt->initialization ); 46 46 } 47 Statement * ForExprMutator::postmutate( WhileStmt *whileStmt ) {47 Statement *ForExprMutator::postmutate( WhileStmt *whileStmt ) { 48 48 return hoist( whileStmt, whileStmt->initialization ); 49 49 } -
src/ControlStruct/LabelFixer.cc
rf343c6b r69c37cc 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Mar 11 22:26:02 201913 // Update Count : 15 911 // Last Modified By : Rob Schluntz 12 // Last Modified On : Tue Jul 28 13:32:43 2015 13 // Update Count : 156 14 14 // 15 15 … … 32 32 } 33 33 34 LabelFixer::LabelFixer( LabelGenerator * gen ) : generator ( gen ) {34 LabelFixer::LabelFixer( LabelGenerator *gen ) : generator ( gen ) { 35 35 if ( generator == 0 ) 36 36 generator = LabelGenerator::getGenerator(); … … 49 49 50 50 // prune to at most one label definition for each statement 51 void LabelFixer::previsit( Statement * stmt ) {51 void LabelFixer::previsit( Statement *stmt ) { 52 52 std::list< Label > &labels = stmt->get_labels(); 53 53 … … 58 58 } 59 59 60 void LabelFixer::previsit( BranchStmt * branchStmt ) {60 void LabelFixer::previsit( BranchStmt *branchStmt ) { 61 61 previsit( ( Statement *)branchStmt ); 62 62 … … 75 75 76 76 77 // sets the definition of the labelTable entry to be the provided statement for every label in the list78 // parameter. Happens for every kind of statement79 Label LabelFixer::setLabelsDef( std::list< Label > & llabel, Statement *definition ) {77 // sets the definition of the labelTable entry to be the provided 78 // statement for every label in the list parameter. Happens for every kind of statement 79 Label LabelFixer::setLabelsDef( std::list< Label > &llabel, Statement *definition ) { 80 80 assert( definition != 0 ); 81 81 assert( llabel.size() > 0 ); … … 100 100 } // for 101 101 102 // produce one of the labels attached to this statement to be temporarily used as the canonical label 102 // produce one of the labels attached to this statement to be 103 // temporarily used as the canonical label 103 104 return labelTable[ llabel.front() ]->get_label(); 104 105 } … … 116 117 117 118 // Builds a table that maps a label to its defining statement. 118 std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) {119 std::map<Label, Statement * > *LabelFixer::resolveJumps() throw ( SemanticErrorException ) { 119 120 std::map< Label, Statement * > *ret = new std::map< Label, Statement * >(); 120 121 for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) { -
src/ControlStruct/LabelGenerator.cc
rf343c6b r69c37cc 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Mon Mar 11 22:23:20 201913 // Update Count : 1 511 // Last Modified By : Andrew Beach 12 // Last Modified On : Thr Aug 14 14:14:00 2015 13 // Update Count : 14 14 14 // 15 15 … … 24 24 25 25 namespace ControlStruct { 26 LabelGenerator * LabelGenerator::labelGenerator = 0;26 LabelGenerator *LabelGenerator::labelGenerator = 0; 27 27 28 LabelGenerator * LabelGenerator::getGenerator() {28 LabelGenerator *LabelGenerator::getGenerator() { 29 29 if ( LabelGenerator::labelGenerator == 0 ) 30 30 LabelGenerator::labelGenerator = new LabelGenerator(); 31 31 32 return labelGenerator; 32 33 } … … 37 38 if ( stmt && ! stmt->get_labels().empty() ) { 38 39 os << "_" << stmt->get_labels().front() << "__"; 39 } // if40 } 40 41 std::string ret = os.str(); 41 42 Label l( ret ); -
src/Parser/ParseNode.h
rf343c6b r69c37cc 10 10 // Created On : Sat May 16 13:28:16 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 15 14:22:39 201913 // Update Count : 8 7412 // Last Modified On : Wed Feb 13 17:36:49 2019 13 // Update Count : 867 14 14 // 15 15 … … 132 132 void printOneLine( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {} 133 133 134 Expression *get_expr() const { return expr.get(); } 134 135 template<typename T> 135 136 bool isExpressionType() const { return nullptr != dynamic_cast<T>(expr.get()); } 136 137 137 138 Expression * build() const { return const_cast<ExpressionNode *>(this)->expr.release(); } 138 139 std::unique_ptr<Expression> expr; // public because of lifetime implications140 139 private: 141 140 bool extension = false; 141 std::unique_ptr<Expression> expr; 142 142 }; // ExpressionNode 143 143 -
src/Parser/lex.ll
rf343c6b r69c37cc 10 10 * Created On : Sat Sep 22 08:58:10 2001 11 11 * Last Modified By : Peter A. Buhr 12 * Last Modified On : Wed Mar 13 14:54:30201913 * Update Count : 70 712 * Last Modified On : Sun Mar 10 09:13:09 2019 13 * Update Count : 706 14 14 */ 15 15 … … 226 226 char { KEYWORD_RETURN(CHAR); } 227 227 choose { KEYWORD_RETURN(CHOOSE); } // CFA 228 coerce { KEYWORD_RETURN(COERCE); } // CFA229 228 _Complex { KEYWORD_RETURN(COMPLEX); } // C99 230 229 __complex { KEYWORD_RETURN(COMPLEX); } // GCC -
src/Parser/parser.yy
rf343c6b r69c37cc 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 15 15:02:56201913 // Update Count : 42 9012 // Last Modified On : Thu Feb 21 08:45:07 2019 13 // Update Count : 4232 14 14 // 15 15 … … 185 185 186 186 ForCtrl * forCtrl( ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) { 187 ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type-> expr.get());187 ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->get_expr()); 188 188 if ( constant && (constant->get_constant()->get_value() == "0" || constant->get_constant()->get_value() == "1") ) { 189 189 type = new ExpressionNode( new CastExpr( maybeMoveBuild< Expression >(type), new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ) ); … … 198 198 199 199 ForCtrl * forCtrl( ExpressionNode * type, ExpressionNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) { 200 if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index-> expr.get()) ) {200 if ( NameExpr * identifier = dynamic_cast<NameExpr *>(index->get_expr()) ) { 201 201 return forCtrl( type, new string( identifier->name ), start, compop, comp, inc ); 202 } else if ( CommaExpr * commaExpr = dynamic_cast<CommaExpr *>(index-> expr.get()) ) {202 } else if ( CommaExpr * commaExpr = dynamic_cast<CommaExpr *>(index->get_expr()) ) { 203 203 if ( NameExpr * identifier = dynamic_cast<NameExpr *>(commaExpr->arg1 ) ) { 204 204 return forCtrl( type, new string( identifier->name ), start, compop, comp, inc ); … … 265 265 %token RESTRICT // C99 266 266 %token ATOMIC // C11 267 %token FORALL MUTEX VIRTUAL COERCE// CFA267 %token FORALL MUTEX VIRTUAL // CFA 268 268 %token VOID CHAR SHORT INT LONG FLOAT DOUBLE SIGNED UNSIGNED 269 269 %token BOOL COMPLEX IMAGINARY // C99 … … 334 334 %type<en> subrange 335 335 %type<decl> asm_name_opt 336 %type<en> asm_operands_opt asm_operands_listasm_operand336 %type<en> asm_operands_opt asm_operands_list asm_operand 337 337 %type<label> label_list 338 338 %type<en> asm_clobbers_list_opt 339 339 %type<flag> asm_volatile_opt 340 340 %type<en> handler_predicate_opt 341 %type<genexpr> generic_association generic_assoc_list341 %type<genexpr> generic_association generic_assoc_list 342 342 343 343 // statements … … 795 795 | '(' type_no_function ')' cast_expression 796 796 { $$ = new ExpressionNode( build_cast( $2, $4 ) ); } 797 // keyword cast cannot be grouped because of reduction in aggregate_key798 797 | '(' COROUTINE '&' ')' cast_expression // CFA 799 798 { $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); } … … 807 806 | '(' VIRTUAL type_no_function ')' cast_expression // CFA 808 807 { $$ = new ExpressionNode( new VirtualCastExpr( maybeMoveBuild< Expression >( $5 ), maybeMoveBuildType( $3 ) ) ); } 809 | '(' RETURN type_no_function ')' cast_expression // CFA810 { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; }811 | '(' COERCE type_no_function ')' cast_expression // CFA812 { SemanticError( yylloc, "Coerce cast is currently unimplemented." ); $$ = nullptr; }813 | '(' qualifier_cast_list ')' cast_expression // CFA814 { SemanticError( yylloc, "Qualifier cast is currently unimplemented." ); $$ = nullptr; }815 808 // | '(' type_no_function ')' tuple 816 809 // { $$ = new ExpressionNode( build_cast( $2, $4 ) ); } 817 ;818 819 qualifier_cast_list:820 cast_modifier type_qualifier_name821 | cast_modifier MUTEX822 | qualifier_cast_list cast_modifier type_qualifier_name823 | qualifier_cast_list cast_modifier MUTEX824 ;825 826 cast_modifier:827 '-'828 | '+'829 810 ; 830 811 … … 1164 1145 for_control_expression 1165 1146 | for_control_expression_list ':' for_control_expression 1166 // ForCtrl + ForCtrl: 1167 // init + init => multiple declaration statements that are hoisted 1168 // condition + condition => (expression) && (expression) 1169 // change + change => (expression), (expression) 1170 { 1171 $1->init->set_last( $3->init ); 1172 if ( $1->condition ) { 1173 if ( $3->condition ) { 1174 $1->condition->expr.reset( new LogicalExpr( $1->condition->expr.release(), $3->condition->expr.release(), true ) ); 1175 } // if 1176 } else $1->condition = $3->condition; 1177 if ( $1->change ) { 1178 if ( $3->change ) { 1179 $1->change->expr.reset( new CommaExpr( $1->change->expr.release(), $3->change->expr.release() ) ); 1180 } // if 1181 } else $1->change = $3->change; 1182 $$ = $1; 1183 } 1147 { $$ = $3; } 1184 1148 ; 1185 1149 … … 1191 1155 | declaration comma_expression_opt ';' comma_expression_opt // C99, declaration has ';' 1192 1156 { $$ = new ForCtrl( $1, $2, $4 ); } 1193 1194 1157 | comma_expression // CFA 1195 1158 { $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ), … … 1206 1169 | comma_expression ';' comma_expression inclexcl comma_expression '~' comma_expression // CFA 1207 1170 { $$ = 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 '~' '@' // CFA1211 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }1212 | comma_expression ';' comma_expression ErangeDown '@' // CFA1213 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::GThan, nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }1214 1171 | comma_expression ';' comma_expression '~' '@' '~' comma_expression // CFA 1215 1172 { $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, $7 ); } -
src/ResolvExpr/AlternativeFinder.cc
rf343c6b r69c37cc 258 258 // - necessary pre-requisite to pruning 259 259 AltList candidates; 260 std::list<std::string> errors;261 260 for ( unsigned i = 0; i < alternatives.size(); ++i ) { 262 resolveAssertions( alternatives[i], indexer, candidates , errors);261 resolveAssertions( alternatives[i], indexer, candidates ); 263 262 } 264 263 // fail early if none such 265 264 if ( mode.failFast && candidates.empty() ) { 266 265 std::ostringstream stream; 267 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 268 // << "Alternatives with failing assertions are:\n"; 269 // printAlts( alternatives, stream, 1 ); 270 for ( const auto& err : errors ) { 271 stream << err; 272 } 266 stream << "No resolvable alternatives for expression " << expr << "\n" 267 << "Alternatives with failing assertions are:\n"; 268 printAlts( alternatives, stream, 1 ); 273 269 SemanticError( expr->location, stream.str() ); 274 270 } -
src/ResolvExpr/ResolveAssertions.cc
rf343c6b r69c37cc 20 20 #include <list> // for list 21 21 #include <memory> // for unique_ptr 22 #include <sstream> // for ostringstream 23 #include <string> // for string 22 #include <string> 24 23 #include <unordered_map> // for unordered_map, unordered_multimap 25 24 #include <utility> // for move … … 28 27 #include "Alternative.h" // for Alternative, AssertionItem, AssertionList 29 28 #include "Common/FilterCombos.h" // for filterCombos 30 #include "Common/Indenter.h" // for Indenter31 29 #include "Common/utility.h" // for sort_mins 32 30 #include "ResolvExpr/RenameVars.h" // for renameTyVars … … 99 97 return { item, item.matches[i] }; 100 98 } 101 102 const DeclarationWithType* get_decl() const { return cache->at(key).deferIds[0].decl; }103 99 104 100 // sortable by key … … 368 364 static const int recursionLimit = /* 10 */ 4; 369 365 370 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out , std::list<std::string>& errors) {366 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out ) { 371 367 // finish early if no assertions to resolve 372 368 if ( alt.need.empty() ) { … … 389 385 for ( auto& assn : resn.need ) { 390 386 // fail early if any assertion is not resolvable 391 if ( ! resolveAssertion( assn, resn, assnCache ) ) { 392 Indenter tabs{ Indenter::tabsize, 3 }; 393 std::ostringstream ss; 394 ss << tabs << "Unsatisfiable alternative:\n"; 395 resn.alt.print( ss, ++tabs ); 396 ss << --tabs << "Could not satisfy assertion:\n"; 397 assn.decl->print( ss, ++tabs ); 398 399 errors.emplace_back( ss.str() ); 400 goto nextResn; 401 } 387 if ( ! resolveAssertion( assn, resn, assnCache ) ) goto nextResn; 402 388 } 403 389 … … 418 404 resn.deferred, 419 405 CandidateEnvMerger{ resn.alt.env, resn.alt.openVars, resn.indexer } ); 420 // fail early if no mutually-compatible assertion satisfaction421 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 }435 406 // sort by cost 436 407 CandidateCost coster{ resn.indexer }; -
src/ResolvExpr/ResolveAssertions.h
rf343c6b r69c37cc 24 24 namespace ResolvExpr { 25 25 /// Recursively resolves all assertions provided in an alternative; returns true iff succeeds 26 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out , std::list<std::string>& errors);26 void resolveAssertions( Alternative& alt, const SymTab::Indexer& indexer, AltList& out ); 27 27 } // namespace ResolvExpr 28 28 -
src/ResolvExpr/TypeEnvironment.cc
rf343c6b r69c37cc 386 386 } 387 387 388 bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, 389 TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, 390 const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) { 388 bool TypeEnvironment::bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) { 391 389 392 390 auto class1 = internal_lookup( var1->get_name() ); … … 430 428 class1->set_type( common ); 431 429 } 432 class1->data.isComplete |= data.isComplete;433 430 env.erase( class2 ); 434 431 } else return false; … … 438 435 class1->vars.insert( class2->vars.begin(), class2->vars.end() ); 439 436 class1->allowWidening = widen1; 440 class1->data.isComplete |= data.isComplete;441 437 env.erase( class2 ); 442 438 } else { 443 439 class2->vars.insert( class1->vars.begin(), class1->vars.end() ); 444 440 class2->allowWidening = widen2; 445 class2->data.isComplete |= data.isComplete;446 441 env.erase( class1 ); 447 442 } // if … … 450 445 class1->vars.insert( var2->get_name() ); 451 446 class1->allowWidening = widen1; 452 class1->data.isComplete |= data.isComplete;453 447 } else if ( class2 != env.end() ) { 454 448 // var1 unbound, add to class2 455 449 class2->vars.insert( var1->get_name() ); 456 450 class2->allowWidening = widen2; 457 class2->data.isComplete |= data.isComplete;458 451 } else { 459 452 // neither var bound, create new class -
src/ResolvExpr/TypeEnvironment.h
rf343c6b r69c37cc 139 139 /// Binds the type classes represented by `var1` and `var2` together; will add 140 140 /// one or both classes if needed. Returns false on failure. 141 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );141 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ); 142 142 143 143 /// Disallows widening for all bindings in the environment -
src/ResolvExpr/Unify.cc
rf343c6b r69c37cc 172 172 bool isopen2 = var2 && ( entry2 != openVars.end() ); 173 173 174 if ( isopen1 && isopen2 ) { 175 if ( entry1->second.kind != entry2->second.kind ) { 176 result = false; 177 } else { 178 result = env.bindVarToVar( 179 var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions, 180 haveAssertions, openVars, widenMode, indexer ); 181 } 174 if ( isopen1 && isopen2 && entry1->second == entry2->second ) { 175 result = env.bindVarToVar( var1, var2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer ); 182 176 } else if ( isopen1 ) { 183 177 result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widenMode, indexer ); -
src/SymTab/Indexer.cc
rf343c6b r69c37cc 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 21:37:33 2015 11 // Last Modified By : Aaron B. Moss12 // Last Modified On : Fri Mar 8 13:55:00 201913 // Update Count : 2 111 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Aug 17 16:08:40 2017 13 // Update Count : 20 14 14 // 15 15 … … 17 17 18 18 #include <cassert> // for assert, strict_dynamic_cast 19 #include <iostream> // for operator<<, basic_ostream, ostream 19 20 #include <string> // for string, operator<<, operator!= 20 #include <memory> // for shared_ptr, make_shared21 21 #include <unordered_map> // for operator!=, unordered_map<>::const... 22 22 #include <unordered_set> // for unordered_set 23 23 #include <utility> // for pair, make_pair, move 24 #include <vector> // for vector25 24 26 25 #include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign 27 26 #include "Common/SemanticError.h" // for SemanticError 28 27 #include "Common/utility.h" // for cloneAll 29 #include "Common/Stats/Counter.h" // for counters30 #include "GenPoly/GenPoly.h" // for getFunctionType28 #include "Common/Stats/Counter.h" // for counters 29 #include "GenPoly/GenPoly.h" 31 30 #include "InitTweak/InitTweak.h" // for isConstructor, isCopyFunction, isC... 32 31 #include "Mangler.h" // for Mangler … … 40 39 #include "SynTree/Type.h" // for Type, StructInstType, UnionInstType 41 40 41 #define debugPrint(x) if ( doDebug ) { std::cerr << x; } 42 42 43 namespace SymTab { 43 44 44 45 // Statistics block 45 46 namespace { 46 static inline auto stats() { 47 48 static inline auto stats_idtable() { 49 using namespace Stats::Counters; 50 static auto group = build<CounterGroup>("IdTable"); 51 static struct { 52 SimpleCounter * find; 53 AverageCounter<double> * size; 54 AverageCounter<double> * key; 55 } ret = { 56 .find = build<SimpleCounter>("Find calls", group), 57 .size = build<AverageCounter<double>>("Average Size", group), 58 .key = build<AverageCounter<double>>("Average Key Size", group), 59 }; 60 return ret; 61 } 62 63 static inline auto stats_indexers() { 47 64 using namespace Stats::Counters; 48 65 static auto group = build<CounterGroup>("Indexers"); … … 50 67 SimpleCounter * count; 51 68 AverageCounter<double> * size; 52 SimpleCounter * new_scopes; 53 SimpleCounter * lazy_scopes; 54 AverageCounter<double> * avg_scope_depth; 55 MaxCounter<size_t> * max_scope_depth; 56 SimpleCounter * add_calls; 57 SimpleCounter * lookup_calls; 58 SimpleCounter * map_lookups; 59 SimpleCounter * map_mutations; 69 AverageCounter<double> * depth_a; 70 MaxCounter<size_t> * depth_m; 60 71 } ret = { 61 72 .count = build<SimpleCounter>("Count", group), 62 73 .size = build<AverageCounter<double>>("Average Size", group), 63 .new_scopes = build<SimpleCounter>("Scopes", group), 64 .lazy_scopes = build<SimpleCounter>("Lazy Scopes", group), 65 .avg_scope_depth = build<AverageCounter<double>>("Average Scope", group), 66 .max_scope_depth = build<MaxCounter<size_t>>("Max Scope", group), 67 .add_calls = build<SimpleCounter>("Add Calls", group), 68 .lookup_calls = build<SimpleCounter>("Lookup Calls", group), 69 .map_lookups = build<SimpleCounter>("Map Lookups", group), 70 .map_mutations = build<SimpleCounter>("Map Mutations", group) 74 .depth_a = build<AverageCounter<double>>("Average Depth", group), 75 .depth_m = build<MaxCounter<size_t>>("Max Depth", group), 71 76 }; 72 77 return ret; … … 74 79 } 75 80 76 Indexer::Indexer() 77 : idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable(), 78 prevScope(), scope( 0 ), repScope( 0 ) { ++*stats().count; } 81 std::ostream & operator<<( std::ostream & out, const Indexer::IdData & data ) { 82 return out << "(" << data.id << "," << data.baseExpr << ")"; 83 } 84 85 typedef std::unordered_map< std::string, Indexer::IdData > MangleTable; 86 typedef std::unordered_map< std::string, MangleTable > IdTable; 87 typedef std::unordered_map< std::string, NamedTypeDecl* > TypeTable; 88 typedef std::unordered_map< std::string, StructDecl* > StructTable; 89 typedef std::unordered_map< std::string, EnumDecl* > EnumTable; 90 typedef std::unordered_map< std::string, UnionDecl* > UnionTable; 91 typedef std::unordered_map< std::string, TraitDecl* > TraitTable; 92 93 void dump( const IdTable &table, std::ostream &os ) { 94 for ( IdTable::const_iterator id = table.begin(); id != table.end(); ++id ) { 95 for ( MangleTable::const_iterator mangle = id->second.begin(); mangle != id->second.end(); ++mangle ) { 96 os << mangle->second << std::endl; 97 } 98 } 99 } 100 101 template< typename Decl > 102 void dump( const std::unordered_map< std::string, Decl* > &table, std::ostream &os ) { 103 for ( typename std::unordered_map< std::string, Decl* >::const_iterator it = table.begin(); it != table.end(); ++it ) { 104 os << it->second << std::endl; 105 } // for 106 } 107 108 struct Indexer::Impl { 109 Impl( unsigned long _scope ) : refCount(1), scope( _scope ), size( 0 ), base(), 110 idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {} 111 Impl( unsigned long _scope, Indexer &&_base ) : refCount(1), scope( _scope ), size( 0 ), base( _base ), 112 idTable(), typeTable(), structTable(), enumTable(), unionTable(), traitTable() {} 113 unsigned long refCount; ///< Number of references to these tables 114 unsigned long scope; ///< Scope these tables are associated with 115 unsigned long size; ///< Number of elements stored in this table 116 const Indexer base; ///< Base indexer this extends 117 118 IdTable idTable; ///< Identifier namespace 119 TypeTable typeTable; ///< Type namespace 120 StructTable structTable; ///< Struct namespace 121 EnumTable enumTable; ///< Enum namespace 122 UnionTable unionTable; ///< Union namespace 123 TraitTable traitTable; ///< Trait namespace 124 }; 125 126 Indexer::Impl *Indexer::newRef( Indexer::Impl *toClone ) { 127 if ( ! toClone ) return 0; 128 129 // shorten the search chain by skipping empty links 130 Indexer::Impl *ret = toClone->size == 0 ? toClone->base.tables : toClone; 131 if ( ret ) { ++ret->refCount; } 132 133 return ret; 134 } 135 136 void Indexer::deleteRef( Indexer::Impl *toFree ) { 137 if ( ! toFree ) return; 138 139 if ( --toFree->refCount == 0 ) delete toFree; 140 } 141 142 void Indexer::removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const { 143 // only need to perform this step for constructors, destructors, and assignment functions 144 if ( ! CodeGen::isCtorDtorAssign( id ) ) return; 145 146 // helpful data structure to organize properties for a type 147 struct ValueType { 148 struct DeclBall { // properties for this particular decl 149 IdData decl; 150 bool isUserDefinedFunc; 151 bool isCopyFunc; 152 }; 153 // properties for this type 154 bool existsUserDefinedCopyFunc = false; // user-defined copy ctor found 155 BaseSyntaxNode * deleteStmt = nullptr; // non-null if a user-defined function is found 156 std::list< DeclBall > decls; 157 158 // another FunctionDecl for the current type was found - determine 159 // if it has special properties and update data structure accordingly 160 ValueType & operator+=( IdData data ) { 161 DeclarationWithType * function = data.id; 162 bool isUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage ); 163 bool isCopyFunc = InitTweak::isCopyFunction( function, function->name ); 164 decls.push_back( DeclBall{ data, isUserDefinedFunc, isCopyFunc } ); 165 existsUserDefinedCopyFunc = existsUserDefinedCopyFunc || (isUserDefinedFunc && isCopyFunc); 166 if ( isUserDefinedFunc && ! deleteStmt ) { 167 // any user-defined function can act as an implicit delete statement for generated constructors. 168 // a delete stmt should not act as an implicit delete statement. 169 deleteStmt = data.id; 170 } 171 return *this; 172 } 173 }; // ValueType 174 175 std::list< IdData > copy; 176 copy.splice( copy.end(), out ); 177 178 // organize discovered declarations by type 179 std::unordered_map< std::string, ValueType > funcMap; 180 for ( auto decl : copy ) { 181 if ( FunctionDecl * function = dynamic_cast< FunctionDecl * >( decl.id ) ) { 182 std::list< DeclarationWithType * > & params = function->type->parameters; 183 assert( ! params.empty() ); 184 // use base type of pointer, so that qualifiers on the pointer type aren't considered. 185 Type * base = InitTweak::getPointerBase( params.front()->get_type() ); 186 assert( base ); 187 funcMap[ Mangler::mangle( base ) ] += decl; 188 } else { 189 out.push_back( decl ); 190 } 191 } 192 193 // if a type contains user defined ctor/dtor/assign, then special rules trigger, which determine 194 // the set of ctor/dtor/assign that can be used by the requester. In particular, if the user defines 195 // a default ctor, then the generated default ctor is unavailable, likewise for copy ctor 196 // and dtor. If the user defines any ctor/dtor, then no generated field ctors are available. 197 // If the user defines any ctor then the generated default ctor is unavailable (intrinsic default 198 // ctor must be overridden exactly). If the user defines anything that looks like a copy constructor, 199 // then the generated copy constructor is unavailable, and likewise for the assignment operator. 200 for ( std::pair< const std::string, ValueType > & pair : funcMap ) { 201 ValueType & val = pair.second; 202 for ( ValueType::DeclBall ball : val.decls ) { 203 bool isNotUserDefinedFunc = ! ball.isUserDefinedFunc && ball.decl.id->linkage != LinkageSpec::Intrinsic; 204 bool isCopyFunc = ball.isCopyFunc; 205 bool existsUserDefinedCopyFunc = val.existsUserDefinedCopyFunc; 206 207 // only implicitly delete non-user defined functions that are not intrinsic, and are 208 // not copy functions (assignment or copy constructor). If a user-defined copy function exists, 209 // do not pass along the non-user-defined copy functions since signatures do not have to match, 210 // and the generated functions will often be cheaper. 211 if ( isNotUserDefinedFunc ) { 212 if ( isCopyFunc ) { 213 // Skip over non-user-defined copy functions when there is a user-defined copy function. 214 // Since their signatures do not have to be exact, deleting them is the wrong choice. 215 if ( existsUserDefinedCopyFunc ) continue; 216 } else { 217 // delete non-user-defined non-copy functions if applicable. 218 // deleteStmt will be non-null only if a user-defined function is found. 219 ball.decl.deleteStmt = val.deleteStmt; 220 } 221 } 222 out.push_back( ball.decl ); 223 } 224 } 225 } 226 227 void Indexer::makeWritable() { 228 if ( ! tables ) { 229 // create indexer if not yet set 230 tables = new Indexer::Impl( scope ); 231 } else if ( tables->refCount > 1 || tables->scope != scope ) { 232 // make this indexer the base of a fresh indexer at the current scope 233 tables = new Indexer::Impl( scope, std::move( *this ) ); 234 } 235 } 236 237 Indexer::Indexer() : tables( 0 ), scope( 0 ) { 238 (*stats_indexers().count)++; 239 } 240 241 Indexer::Indexer( const Indexer &that ) : doDebug( that.doDebug ), tables( newRef( that.tables ) ), scope( that.scope ) { 242 (*stats_indexers().count)++; 243 } 244 245 Indexer::Indexer( Indexer &&that ) : doDebug( that.doDebug ), tables( that.tables ), scope( that.scope ) { 246 that.tables = 0; 247 } 79 248 80 249 Indexer::~Indexer() { 81 stats().size->push( idTable ? idTable->size() : 0 ); 82 } 83 84 void Indexer::lazyInitScope() { 85 if ( repScope < scope ) { 86 ++*stats().lazy_scopes; 87 // create rollback 88 prevScope = std::make_shared<Indexer>( *this ); 89 // update repScope 90 repScope = scope; 91 } 92 } 93 94 void Indexer::enterScope() { 95 ++scope; 96 97 ++*stats().new_scopes; 98 stats().avg_scope_depth->push( scope ); 99 stats().max_scope_depth->push( scope ); 100 } 101 102 void Indexer::leaveScope() { 103 if ( repScope == scope ) { 104 Ptr prev = prevScope; // make sure prevScope stays live 105 *this = std::move(*prevScope); // replace with previous scope 106 } 107 108 --scope; 250 if(tables) { 251 stats_indexers().size->push( tables->idTable.size() ); 252 size_t depth = 1; 253 for( auto crnt = tables->base.tables; crnt; crnt = crnt->base.tables ) { 254 ++depth; 255 } 256 stats_indexers().depth_a->push( depth ); 257 stats_indexers().depth_m->push( depth ); 258 } 259 deleteRef( tables ); 260 } 261 262 Indexer& Indexer::operator= ( const Indexer &that ) { 263 deleteRef( tables ); 264 265 tables = newRef( that.tables ); 266 scope = that.scope; 267 doDebug = that.doDebug; 268 269 return *this; 270 } 271 272 Indexer& Indexer::operator= ( Indexer &&that ) { 273 deleteRef( tables ); 274 275 tables = that.tables; 276 scope = that.scope; 277 doDebug = that.doDebug; 278 279 that.tables = 0; 280 281 return *this; 109 282 } 110 283 111 284 void Indexer::lookupId( const std::string &id, std::list< IdData > &out ) const { 112 ++*stats().lookup_calls; 113 if ( ! idTable ) return; 114 115 ++*stats().map_lookups; 116 auto decls = idTable->find( id ); 117 if ( decls == idTable->end() ) return; 118 119 for ( auto decl : *(decls->second) ) { 120 out.push_back( decl.second ); 121 } 285 std::unordered_set< std::string > foundMangleNames; 286 287 Indexer::Impl *searchTables = tables; 288 while ( searchTables ) { 289 290 (*stats_idtable().find)++; 291 stats_idtable().key->push( id.size() ); 292 stats_idtable().size->push( searchTables->idTable.size() ); 293 IdTable::const_iterator decls = searchTables->idTable.find( id ); 294 if ( decls != searchTables->idTable.end() ) { 295 const MangleTable &mangleTable = decls->second; 296 for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) { 297 // mark the mangled name as found, skipping this insertion if a declaration for that name has already been found 298 if ( foundMangleNames.insert( decl->first ).second == false ) continue; 299 300 out.push_back( decl->second ); 301 } 302 } 303 304 // get declarations from base indexers 305 searchTables = searchTables->base.tables; 306 } 307 308 // some special functions, e.g. constructors and destructors 309 // remove autogenerated functions when they are defined so that 310 // they can never be matched 311 removeSpecialOverrides( id, out ); 122 312 } 123 313 124 314 NamedTypeDecl *Indexer::lookupType( const std::string &id ) const { 125 ++*stats().lookup_calls; 126 if ( ! typeTable ) return nullptr; 127 ++*stats().map_lookups; 128 auto it = typeTable->find( id ); 129 return it == typeTable->end() ? nullptr : it->second.decl; 315 if ( ! tables ) return 0; 316 317 TypeTable::const_iterator ret = tables->typeTable.find( id ); 318 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupType( id ); 130 319 } 131 320 132 321 StructDecl *Indexer::lookupStruct( const std::string &id ) const { 133 ++*stats().lookup_calls; 134 if ( ! structTable ) return nullptr; 135 ++*stats().map_lookups; 136 auto it = structTable->find( id ); 137 return it == structTable->end() ? nullptr : it->second.decl; 322 if ( ! tables ) return 0; 323 324 StructTable::const_iterator ret = tables->structTable.find( id ); 325 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStruct( id ); 326 } 327 328 NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const { 329 return lookupTypeAtScope( id, 0 ); 330 } 331 332 StructDecl *Indexer::globalLookupStruct( const std::string &id ) const { 333 return lookupStructAtScope( id, 0 ); 334 } 335 336 UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const { 337 return lookupUnionAtScope( id, 0 ); 338 } 339 340 EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const { 341 return lookupEnumAtScope( id, 0 ); 138 342 } 139 343 140 344 EnumDecl *Indexer::lookupEnum( const std::string &id ) const { 141 ++*stats().lookup_calls; 142 if ( ! enumTable ) return nullptr; 143 ++*stats().map_lookups; 144 auto it = enumTable->find( id ); 145 return it == enumTable->end() ? nullptr : it->second.decl; 345 if ( ! tables ) return 0; 346 347 EnumTable::const_iterator ret = tables->enumTable.find( id ); 348 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnum( id ); 146 349 } 147 350 148 351 UnionDecl *Indexer::lookupUnion( const std::string &id ) const { 149 ++*stats().lookup_calls; 150 if ( ! unionTable ) return nullptr; 151 ++*stats().map_lookups; 152 auto it = unionTable->find( id ); 153 return it == unionTable->end() ? nullptr : it->second.decl; 352 if ( ! tables ) return 0; 353 354 UnionTable::const_iterator ret = tables->unionTable.find( id ); 355 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnion( id ); 154 356 } 155 357 156 358 TraitDecl *Indexer::lookupTrait( const std::string &id ) const { 157 ++*stats().lookup_calls; 158 if ( ! traitTable ) return nullptr; 159 ++*stats().map_lookups; 160 auto it = traitTable->find( id ); 161 return it == traitTable->end() ? nullptr : it->second.decl; 162 } 163 164 const Indexer* Indexer::atScope( unsigned long target ) const { 165 // by lazy construction, final indexer in list has repScope 0, cannot be > target 166 // otherwise, will find first scope representing the target 167 const Indexer* indexer = this; 168 while ( indexer->repScope > target ) { 169 indexer = indexer->prevScope.get(); 170 } 171 return indexer; 172 } 173 174 NamedTypeDecl *Indexer::globalLookupType( const std::string &id ) const { 175 return atScope( 0 )->lookupType( id ); 176 } 177 178 StructDecl *Indexer::globalLookupStruct( const std::string &id ) const { 179 return atScope( 0 )->lookupStruct( id ); 180 } 181 182 UnionDecl *Indexer::globalLookupUnion( const std::string &id ) const { 183 return atScope( 0 )->lookupUnion( id ); 184 } 185 186 EnumDecl *Indexer::globalLookupEnum( const std::string &id ) const { 187 return atScope( 0 )->lookupEnum( id ); 359 if ( ! tables ) return 0; 360 361 TraitTable::const_iterator ret = tables->traitTable.find( id ); 362 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTrait( id ); 363 } 364 365 const Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) const { 366 if ( ! tables ) return nullptr; 367 if ( tables->scope < scope ) return nullptr; 368 369 (*stats_idtable().find)++; 370 stats_idtable().key->push( id.size() ); 371 stats_idtable().size->push( tables->idTable.size() ); 372 IdTable::const_iterator decls = tables->idTable.find( id ); 373 if ( decls != tables->idTable.end() ) { 374 const MangleTable &mangleTable = decls->second; 375 MangleTable::const_iterator decl = mangleTable.find( mangleName ); 376 if ( decl != mangleTable.end() ) return &decl->second; 377 } 378 379 return tables->base.lookupIdAtScope( id, mangleName, scope ); 380 } 381 382 Indexer::IdData * Indexer::lookupIdAtScope( const std::string &id, const std::string &mangleName, unsigned long scope ) { 383 return const_cast<IdData *>(const_cast<const Indexer *>(this)->lookupIdAtScope( id, mangleName, scope )); 384 } 385 386 bool Indexer::hasIncompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const { 387 if ( ! tables ) return false; 388 if ( tables->scope < scope ) return false; 389 390 (*stats_idtable().find)++; 391 stats_idtable().key->push( id.size() ); 392 stats_idtable().size->push( tables->idTable.size() ); 393 IdTable::const_iterator decls = tables->idTable.find( id ); 394 if ( decls != tables->idTable.end() ) { 395 const MangleTable &mangleTable = decls->second; 396 for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) { 397 // check for C decls with the same name, skipping those with a compatible type (by mangleName) 398 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first != mangleName ) return true; 399 } 400 } 401 402 return tables->base.hasIncompatibleCDecl( id, mangleName, scope ); 403 } 404 405 bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName, unsigned long scope ) const { 406 if ( ! tables ) return false; 407 if ( tables->scope < scope ) return false; 408 409 (*stats_idtable().find)++; 410 stats_idtable().key->push( id.size() ); 411 stats_idtable().size->push( tables->idTable.size() ); 412 IdTable::const_iterator decls = tables->idTable.find( id ); 413 if ( decls != tables->idTable.end() ) { 414 const MangleTable &mangleTable = decls->second; 415 for ( MangleTable::const_iterator decl = mangleTable.begin(); decl != mangleTable.end(); ++decl ) { 416 // check for C decls with the same name, skipping 417 // those with an incompatible type (by mangleName) 418 if ( ! LinkageSpec::isMangled( decl->second.id->get_linkage() ) && decl->first == mangleName ) return true; 419 } 420 } 421 422 return tables->base.hasCompatibleCDecl( id, mangleName, scope ); 423 } 424 425 NamedTypeDecl *Indexer::lookupTypeAtScope( const std::string &id, unsigned long scope ) const { 426 if ( ! tables ) return 0; 427 if ( tables->scope < scope ) return 0; 428 if ( tables->scope > scope ) return tables->base.lookupTypeAtScope( id, scope ); 429 430 TypeTable::const_iterator ret = tables->typeTable.find( id ); 431 return ret != tables->typeTable.end() ? ret->second : tables->base.lookupTypeAtScope( id, scope ); 432 } 433 434 StructDecl *Indexer::lookupStructAtScope( const std::string &id, unsigned long scope ) const { 435 if ( ! tables ) return 0; 436 if ( tables->scope < scope ) return 0; 437 if ( tables->scope > scope ) return tables->base.lookupStructAtScope( id, scope ); 438 439 StructTable::const_iterator ret = tables->structTable.find( id ); 440 return ret != tables->structTable.end() ? ret->second : tables->base.lookupStructAtScope( id, scope ); 441 } 442 443 EnumDecl *Indexer::lookupEnumAtScope( const std::string &id, unsigned long scope ) const { 444 if ( ! tables ) return 0; 445 if ( tables->scope < scope ) return 0; 446 if ( tables->scope > scope ) return tables->base.lookupEnumAtScope( id, scope ); 447 448 EnumTable::const_iterator ret = tables->enumTable.find( id ); 449 return ret != tables->enumTable.end() ? ret->second : tables->base.lookupEnumAtScope( id, scope ); 450 } 451 452 UnionDecl *Indexer::lookupUnionAtScope( const std::string &id, unsigned long scope ) const { 453 if ( ! tables ) return 0; 454 if ( tables->scope < scope ) return 0; 455 if ( tables->scope > scope ) return tables->base.lookupUnionAtScope( id, scope ); 456 457 UnionTable::const_iterator ret = tables->unionTable.find( id ); 458 return ret != tables->unionTable.end() ? ret->second : tables->base.lookupUnionAtScope( id, scope ); 459 } 460 461 TraitDecl *Indexer::lookupTraitAtScope( const std::string &id, unsigned long scope ) const { 462 if ( ! tables ) return 0; 463 if ( tables->scope < scope ) return 0; 464 if ( tables->scope > scope ) return tables->base.lookupTraitAtScope( id, scope ); 465 466 TraitTable::const_iterator ret = tables->traitTable.find( id ); 467 return ret != tables->traitTable.end() ? ret->second : tables->base.lookupTraitAtScope( id, scope ); 188 468 } 189 469 … … 207 487 } 208 488 209 210 bool Indexer::addedIdConflicts( 211 const Indexer::IdData & existing, DeclarationWithType *added, 212 Indexer::OnConflict handleConflicts, BaseSyntaxNode * deleteStmt ) { 213 // if we're giving the same name mangling to things of different types then there is 214 // something wrong 489 bool addedIdConflicts( Indexer::IdData & existing, DeclarationWithType *added, BaseSyntaxNode * deleteStmt, Indexer::ConflictFunction handleConflicts ) { 490 // if we're giving the same name mangling to things of different types then there is something wrong 215 491 assert( (isObject( added ) && isObject( existing.id ) ) 216 492 || ( isFunction( added ) && isFunction( existing.id ) ) ); 217 493 218 if ( LinkageSpec::isOverridable( existing.id-> linkage) ) {494 if ( LinkageSpec::isOverridable( existing.id->get_linkage() ) ) { 219 495 // new definition shadows the autogenerated one, even at the same scope 220 496 return false; 221 } else if ( LinkageSpec::isMangled( added->linkage ) 222 || ResolvExpr::typesCompatible( 223 added->get_type(), existing.id->get_type(), Indexer() ) ) { 497 } else if ( LinkageSpec::isMangled( added->get_linkage() ) || ResolvExpr::typesCompatible( added->get_type(), existing.id->get_type(), Indexer() ) ) { 224 498 225 499 // it is a conflict if one declaration is deleted and the other is not 226 500 if ( deleteStmt && ! existing.deleteStmt ) { 227 if ( handleConflicts.mode == OnConflict::Error ) { 228 SemanticError( added, "deletion of defined identifier " ); 229 } 230 return true; 501 return handleConflicts( existing, "deletion of defined identifier " ); 231 502 } else if ( ! deleteStmt && existing.deleteStmt ) { 232 if ( handleConflicts.mode == OnConflict::Error ) { 233 SemanticError( added, "definition of deleted identifier " ); 234 } 235 return true; 503 return handleConflicts( existing, "definition of deleted identifier " ); 236 504 } 237 505 238 506 if ( isDefinition( added ) && isDefinition( existing.id ) ) { 239 if ( handleConflicts.mode == OnConflict::Error ) { 240 SemanticError( added, 241 isFunction( added ) ? 242 "duplicate function definition for " : 243 "duplicate object definition for " ); 244 } 245 return true; 507 if ( isFunction( added ) ) { 508 return handleConflicts( existing, "duplicate function definition for " ); 509 } else { 510 return handleConflicts( existing, "duplicate object definition for " ); 511 } // if 246 512 } // if 247 513 } else { 248 if ( handleConflicts.mode == OnConflict::Error ) { 249 SemanticError( added, "duplicate definition for " ); 250 } 251 return true; 514 return handleConflicts( existing, "duplicate definition for " ); 252 515 } // if 253 516 … … 255 518 } 256 519 257 bool Indexer::hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const { 258 if ( ! idTable ) return false; 259 260 ++*stats().map_lookups; 261 auto decls = idTable->find( id ); 262 if ( decls == idTable->end() ) return false; 263 264 for ( auto decl : *(decls->second) ) { 265 // skip other scopes (hidden by this decl) 266 if ( decl.second.scope != scope ) continue; 267 // check for C decl with compatible type (by mangleName) 268 if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first == mangleName ) { 269 return true; 270 } 271 } 272 273 return false; 274 } 275 276 bool Indexer::hasIncompatibleCDecl( 277 const std::string &id, const std::string &mangleName ) const { 278 if ( ! idTable ) return false; 279 280 ++*stats().map_lookups; 281 auto decls = idTable->find( id ); 282 if ( decls == idTable->end() ) return false; 283 284 for ( auto decl : *(decls->second) ) { 285 // skip other scopes (hidden by this decl) 286 if ( decl.second.scope != scope ) continue; 287 // check for C decl with incompatible type (by manglename) 288 if ( ! LinkageSpec::isMangled( decl.second.id->linkage ) && decl.first != mangleName ) { 289 return true; 290 } 291 } 292 293 return false; 294 } 295 296 /// gets the base type of the first parameter; decl must be a ctor/dtor/assignment function 297 std::string getOtypeKey( FunctionDecl* function ) { 298 auto& params = function->type->parameters; 299 assert( ! params.empty() ); 300 // use base type of pointer, so that qualifiers on the pointer type aren't considered. 301 Type* base = InitTweak::getPointerBase( params.front()->get_type() ); 302 assert( base ); 303 return Mangler::mangle( base ); 304 } 305 306 /// gets the declaration for the function acting on a type specified by otype key, 307 /// nullptr if none such 308 FunctionDecl * getFunctionForOtype( DeclarationWithType * decl, const std::string& otypeKey ) { 309 FunctionDecl * func = dynamic_cast< FunctionDecl * >( decl ); 310 if ( ! func || otypeKey != getOtypeKey( func ) ) return nullptr; 311 return func; 312 } 313 314 bool Indexer::removeSpecialOverrides( 315 Indexer::IdData& data, Indexer::MangleTable::Ptr& mangleTable ) { 316 // if a type contains user defined ctor/dtor/assign, then special rules trigger, which 317 // determinethe set of ctor/dtor/assign that can be used by the requester. In particular, 318 // if the user defines a default ctor, then the generated default ctor is unavailable, 319 // likewise for copy ctor and dtor. If the user defines any ctor/dtor, then no generated 320 // field ctors are available. If the user defines any ctor then the generated default ctor 321 // is unavailable (intrinsic default ctor must be overridden exactly). If the user defines 322 // anything that looks like a copy constructor, then the generated copy constructor is 323 // unavailable, and likewise for the assignment operator. 324 325 // only relevant on function declarations 326 FunctionDecl * function = dynamic_cast< FunctionDecl * >( data.id ); 327 if ( ! function ) return true; 328 // only need to perform this check for constructors, destructors, and assignment functions 329 if ( ! CodeGen::isCtorDtorAssign( data.id->name ) ) return true; 330 331 // set up information for this type 332 bool dataIsUserDefinedFunc = ! LinkageSpec::isOverridable( function->linkage ); 333 bool dataIsCopyFunc = InitTweak::isCopyFunction( function, function->name ); 334 std::string dataOtypeKey = getOtypeKey( function ); 335 336 if ( dataIsUserDefinedFunc && dataIsCopyFunc ) { 337 // this is a user-defined copy function 338 // if this is the first such, delete/remove non-user-defined overloads as needed 339 std::vector< std::string > removed; 340 std::vector< MangleTable::value_type > deleted; 341 bool alreadyUserDefinedFunc = false; 342 343 for ( const auto& entry : *mangleTable ) { 344 // skip decls that aren't functions or are for the wrong type 345 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey ); 346 if ( ! decl ) continue; 347 348 bool isCopyFunc = InitTweak::isCopyFunction( decl, decl->name ); 349 if ( ! LinkageSpec::isOverridable( decl->linkage ) ) { 350 // matching user-defined function 351 if ( isCopyFunc ) { 352 // mutation already performed, return early 353 return true; 354 } else { 355 // note that non-copy deletions already performed 356 alreadyUserDefinedFunc = true; 357 } 358 } else { 359 // non-user-defined function; mark for deletion/removal as appropriate 360 if ( isCopyFunc ) { 361 removed.push_back( entry.first ); 362 } else if ( ! alreadyUserDefinedFunc ) { 363 deleted.push_back( entry ); 364 } 365 } 366 } 367 368 // perform removals from mangle table, and deletions if necessary 369 for ( const auto& key : removed ) { 370 ++*stats().map_mutations; 371 mangleTable = mangleTable->erase( key ); 372 } 373 if ( ! alreadyUserDefinedFunc ) for ( const auto& entry : deleted ) { 374 ++*stats().map_mutations; 375 mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } ); 376 } 377 } else if ( dataIsUserDefinedFunc ) { 378 // this is a user-defined non-copy function 379 // if this is the first user-defined function, delete non-user-defined overloads 380 std::vector< MangleTable::value_type > deleted; 381 382 for ( const auto& entry : *mangleTable ) { 383 // skip decls that aren't functions or are for the wrong type 384 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey ); 385 if ( ! decl ) continue; 386 387 // exit early if already a matching user-defined function; 388 // earlier function will have mutated table 389 if ( ! LinkageSpec::isOverridable( decl->linkage ) ) return true; 390 391 // skip mutating intrinsic functions 392 if ( decl->linkage == LinkageSpec::Intrinsic ) continue; 393 394 // user-defined non-copy functions do not override copy functions 395 if ( InitTweak::isCopyFunction( decl, decl->name ) ) continue; 396 397 // this function to be deleted after mangleTable iteration is complete 398 deleted.push_back( entry ); 399 } 400 401 // mark deletions to update mangle table 402 // this needs to be a separate loop because of iterator invalidation 403 for ( const auto& entry : deleted ) { 404 ++*stats().map_mutations; 405 mangleTable = mangleTable->set( entry.first, IdData{ entry.second, function } ); 406 } 407 } else if ( function->linkage != LinkageSpec::Intrinsic ) { 408 // this is an overridable generated function 409 // if there already exists a matching user-defined function, delete this appropriately 410 for ( const auto& entry : *mangleTable ) { 411 // skip decls that aren't functions or are for the wrong type 412 FunctionDecl * decl = getFunctionForOtype( entry.second.id, dataOtypeKey ); 413 if ( ! decl ) continue; 414 415 // skip non-user-defined functions 416 if ( LinkageSpec::isOverridable( decl->linkage ) ) continue; 417 418 if ( dataIsCopyFunc ) { 419 // remove current function if exists a user-defined copy function 420 // since the signatures for copy functions don't need to match exactly, using 421 // a delete statement is the wrong approach 422 if ( InitTweak::isCopyFunction( decl, decl->name ) ) return false; 423 } else { 424 // mark current function deleted by first user-defined function found 425 data.deleteStmt = decl; 426 return true; 427 } 428 } 429 } 430 431 // nothing (more) to fix, return true 432 return true; 433 } 434 435 void Indexer::addId( 436 DeclarationWithType *decl, OnConflict handleConflicts, Expression * baseExpr, 437 BaseSyntaxNode * deleteStmt ) { 438 ++*stats().add_calls; 520 void Indexer::addId( DeclarationWithType *decl, ConflictFunction handleConflicts, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) { 521 if ( decl->name == "" ) return; 522 debugPrint( "Adding Id " << decl->name << std::endl ); 523 makeWritable(); 524 439 525 const std::string &name = decl->name; 440 if ( name == "" ) return;441 442 526 std::string mangleName; 443 527 if ( LinkageSpec::isOverridable( decl->linkage ) ) { 444 // mangle the name without including the appropriate suffix, so overridable routines 445 // are placed into thesame "bucket" as their user defined versions.528 // mangle the name without including the appropriate suffix, so overridable routines are placed into the 529 // same "bucket" as their user defined versions. 446 530 mangleName = Mangler::mangle( decl, false ); 447 531 } else { … … 449 533 } // if 450 534 451 // this ensures that no two declarations with the same unmangled name at the same scope 452 // both have C linkage 453 if ( LinkageSpec::isMangled( decl->linkage ) ) { 535 // this ensures that no two declarations with the same unmangled name at the same scope both have C linkage 536 if ( ! LinkageSpec::isMangled( decl->linkage ) ) { 537 // NOTE this is broken in Richard's original code in such a way that it never triggers (it 538 // doesn't check decls that have the same manglename, and all C-linkage decls are defined to 539 // have their name as their manglename, hence the error can never trigger). 540 // The code here is closer to correct, but name mangling would have to be completely 541 // isomorphic to C type-compatibility, which it may not be. 542 if ( hasIncompatibleCDecl( name, mangleName, scope ) ) { 543 SemanticError( decl, "conflicting overload of C function " ); 544 } 545 } else { 454 546 // Check that a Cforall declaration doesn't override any C declaration 455 if ( hasCompatibleCDecl( name, mangleName ) ) {547 if ( hasCompatibleCDecl( name, mangleName, scope ) ) { 456 548 SemanticError( decl, "Cforall declaration hides C function " ); 457 549 } 458 } else { 459 // NOTE: only correct if name mangling is completely isomorphic to C 460 // type-compatibility, which it may not be. 461 if ( hasIncompatibleCDecl( name, mangleName ) ) { 462 SemanticError( decl, "conflicting overload of C function " ); 463 } 464 } 465 466 // ensure tables exist and add identifier 467 MangleTable::Ptr mangleTable; 468 if ( ! idTable ) { 469 idTable = IdTable::new_ptr(); 470 mangleTable = MangleTable::new_ptr(); 471 } else { 472 ++*stats().map_lookups; 473 auto decls = idTable->find( name ); 474 if ( decls == idTable->end() ) { 475 mangleTable = MangleTable::new_ptr(); 476 } else { 477 mangleTable = decls->second; 478 // skip in-scope repeat declarations of same identifier 479 ++*stats().map_lookups; 480 auto existing = mangleTable->find( mangleName ); 481 if ( existing != mangleTable->end() 482 && existing->second.scope == scope 483 && existing->second.id ) { 484 if ( addedIdConflicts( existing->second, decl, handleConflicts, deleteStmt ) ) { 485 if ( handleConflicts.mode == OnConflict::Delete ) { 486 // set delete expression for conflicting identifier 487 lazyInitScope(); 488 *stats().map_mutations += 2; 489 idTable = idTable->set( 490 name, 491 mangleTable->set( 492 mangleName, 493 IdData{ existing->second, handleConflicts.deleteStmt } ) ); 494 } 495 return; 496 } 497 } 498 } 499 } 500 501 // add/overwrite with new identifier 502 lazyInitScope(); 503 IdData data{ decl, baseExpr, deleteStmt, scope }; 504 // Ensure that auto-generated ctor/dtor/assignment are deleted if necessary 505 if ( ! removeSpecialOverrides( data, mangleTable ) ) return; 506 *stats().map_mutations += 2; 507 idTable = idTable->set( name, mangleTable->set( mangleName, std::move(data) ) ); 550 } 551 552 // Skip repeat declarations of the same identifier 553 IdData * existing = lookupIdAtScope( name, mangleName, scope ); 554 if ( existing && existing->id && addedIdConflicts( *existing, decl, deleteStmt, handleConflicts ) ) return; 555 556 // add to indexer 557 tables->idTable[ name ][ mangleName ] = IdData{ decl, baseExpr, deleteStmt }; 558 ++tables->size; 508 559 } 509 560 510 561 void Indexer::addId( DeclarationWithType * decl, Expression * baseExpr ) { 511 562 // default handling of conflicts is to raise an error 512 addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );563 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, baseExpr, decl->isDeleted ? decl : nullptr ); 513 564 } 514 565 515 566 void Indexer::addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ) { 516 567 // default handling of conflicts is to raise an error 517 addId( decl, OnConflict::error(), nullptr, deleteStmt );568 addId( decl, [decl](IdData &, const std::string & msg) { SemanticError( decl, msg ); return true; }, nullptr, deleteStmt ); 518 569 } 519 570 … … 530 581 } 531 582 } 532 // does not need to be added to the table if both existing and added have a base that are 533 // the same 583 // does not need to be added to the table if both existing and added have a base that are the same 534 584 return true; 535 585 } 536 586 537 587 void Indexer::addType( NamedTypeDecl *decl ) { 538 ++*stats().add_calls; 588 debugPrint( "Adding type " << decl->name << std::endl ); 589 makeWritable(); 590 539 591 const std::string &id = decl->name; 540 541 if ( ! typeTable ) { 542 typeTable = TypeTable::new_ptr(); 543 } else { 544 ++*stats().map_lookups; 545 auto existing = typeTable->find( id ); 546 if ( existing != typeTable->end() 547 && existing->second.scope == scope 548 && addedTypeConflicts( existing->second.decl, decl ) ) return; 549 } 550 551 lazyInitScope(); 552 ++*stats().map_mutations; 553 typeTable = typeTable->set( id, Scoped<NamedTypeDecl>{ decl, scope } ); 592 TypeTable::iterator existing = tables->typeTable.find( id ); 593 if ( existing == tables->typeTable.end() ) { 594 NamedTypeDecl *parent = tables->base.lookupTypeAtScope( id, scope ); 595 if ( ! parent || ! addedTypeConflicts( parent, decl ) ) { 596 tables->typeTable.insert( existing, std::make_pair( id, decl ) ); 597 ++tables->size; 598 } 599 } else { 600 if ( ! addedTypeConflicts( existing->second, decl ) ) { 601 existing->second = decl; 602 } 603 } 554 604 } 555 605 … … 564 614 565 615 void Indexer::addStruct( const std::string &id ) { 616 debugPrint( "Adding fwd decl for struct " << id << std::endl ); 566 617 addStruct( new StructDecl( id ) ); 567 618 } 568 619 569 620 void Indexer::addStruct( StructDecl *decl ) { 570 ++*stats().add_calls; 621 debugPrint( "Adding struct " << decl->name << std::endl ); 622 makeWritable(); 623 571 624 const std::string &id = decl->name; 572 573 if ( ! structTable ) { 574 structTable = StructTable::new_ptr(); 575 } else { 576 ++*stats().map_lookups; 577 auto existing = structTable->find( id ); 578 if ( existing != structTable->end() 579 && existing->second.scope == scope 580 && addedDeclConflicts( existing->second.decl, decl ) ) return; 581 } 582 583 lazyInitScope(); 584 ++*stats().map_mutations; 585 structTable = structTable->set( id, Scoped<StructDecl>{ decl, scope } ); 625 StructTable::iterator existing = tables->structTable.find( id ); 626 if ( existing == tables->structTable.end() ) { 627 StructDecl *parent = tables->base.lookupStructAtScope( id, scope ); 628 if ( ! parent || ! addedDeclConflicts( parent, decl ) ) { 629 tables->structTable.insert( existing, std::make_pair( id, decl ) ); 630 ++tables->size; 631 } 632 } else { 633 if ( ! addedDeclConflicts( existing->second, decl ) ) { 634 existing->second = decl; 635 } 636 } 586 637 } 587 638 588 639 void Indexer::addEnum( EnumDecl *decl ) { 589 ++*stats().add_calls; 640 debugPrint( "Adding enum " << decl->name << std::endl ); 641 makeWritable(); 642 590 643 const std::string &id = decl->name; 591 592 if ( ! enumTable ) { 593 enumTable = EnumTable::new_ptr(); 594 } else { 595 ++*stats().map_lookups; 596 auto existing = enumTable->find( id ); 597 if ( existing != enumTable->end() 598 && existing->second.scope == scope 599 && addedDeclConflicts( existing->second.decl, decl ) ) return; 600 } 601 602 lazyInitScope(); 603 ++*stats().map_mutations; 604 enumTable = enumTable->set( id, Scoped<EnumDecl>{ decl, scope } ); 644 EnumTable::iterator existing = tables->enumTable.find( id ); 645 if ( existing == tables->enumTable.end() ) { 646 EnumDecl *parent = tables->base.lookupEnumAtScope( id, scope ); 647 if ( ! parent || ! addedDeclConflicts( parent, decl ) ) { 648 tables->enumTable.insert( existing, std::make_pair( id, decl ) ); 649 ++tables->size; 650 } 651 } else { 652 if ( ! addedDeclConflicts( existing->second, decl ) ) { 653 existing->second = decl; 654 } 655 } 605 656 } 606 657 607 658 void Indexer::addUnion( const std::string &id ) { 659 debugPrint( "Adding fwd decl for union " << id << std::endl ); 608 660 addUnion( new UnionDecl( id ) ); 609 661 } 610 662 611 663 void Indexer::addUnion( UnionDecl *decl ) { 612 ++*stats().add_calls; 664 debugPrint( "Adding union " << decl->name << std::endl ); 665 makeWritable(); 666 613 667 const std::string &id = decl->name; 614 615 if ( ! unionTable ) { 616 unionTable = UnionTable::new_ptr(); 617 } else { 618 ++*stats().map_lookups; 619 auto existing = unionTable->find( id ); 620 if ( existing != unionTable->end() 621 && existing->second.scope == scope 622 && addedDeclConflicts( existing->second.decl, decl ) ) return; 623 } 624 625 lazyInitScope(); 626 ++*stats().map_mutations; 627 unionTable = unionTable->set( id, Scoped<UnionDecl>{ decl, scope } ); 668 UnionTable::iterator existing = tables->unionTable.find( id ); 669 if ( existing == tables->unionTable.end() ) { 670 UnionDecl *parent = tables->base.lookupUnionAtScope( id, scope ); 671 if ( ! parent || ! addedDeclConflicts( parent, decl ) ) { 672 tables->unionTable.insert( existing, std::make_pair( id, decl ) ); 673 ++tables->size; 674 } 675 } else { 676 if ( ! addedDeclConflicts( existing->second, decl ) ) { 677 existing->second = decl; 678 } 679 } 628 680 } 629 681 630 682 void Indexer::addTrait( TraitDecl *decl ) { 631 ++*stats().add_calls; 683 debugPrint( "Adding trait " << decl->name << std::endl ); 684 makeWritable(); 685 632 686 const std::string &id = decl->name; 633 634 if ( ! traitTable ) { 635 traitTable = TraitTable::new_ptr(); 636 } else { 637 ++*stats().map_lookups; 638 auto existing = traitTable->find( id ); 639 if ( existing != traitTable->end() 640 && existing->second.scope == scope 641 && addedDeclConflicts( existing->second.decl, decl ) ) return; 642 } 643 644 lazyInitScope(); 645 ++*stats().map_mutations; 646 traitTable = traitTable->set( id, Scoped<TraitDecl>{ decl, scope } ); 647 } 648 649 void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, 650 OnConflict handleConflicts ) { 687 TraitTable::iterator existing = tables->traitTable.find( id ); 688 if ( existing == tables->traitTable.end() ) { 689 TraitDecl *parent = tables->base.lookupTraitAtScope( id, scope ); 690 if ( ! parent || ! addedDeclConflicts( parent, decl ) ) { 691 tables->traitTable.insert( existing, std::make_pair( id, decl ) ); 692 ++tables->size; 693 } 694 } else { 695 if ( ! addedDeclConflicts( existing->second, decl ) ) { 696 existing->second = decl; 697 } 698 } 699 } 700 701 void Indexer::addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction handleConflicts ) { 651 702 for ( Declaration * decl : aggr->members ) { 652 703 if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) { … … 654 705 if ( dwt->name == "" ) { 655 706 Type * t = dwt->get_type()->stripReferences(); 656 if ( dynamic_cast< StructInstType*>( t ) || dynamic_cast<UnionInstType*>( t ) ) {707 if ( dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t ) ) { 657 708 Expression * base = expr->clone(); 658 709 ResolvExpr::Cost cost = ResolvExpr::Cost::zero; // xxx - carry this cost into the indexer as a base cost? … … 671 722 assertf( aggr, "WithStmt expr has non-aggregate type: %s", toString( expr->result ).c_str() ); 672 723 673 addMembers( aggr, expr, OnConflict::deleteWith( withStmt ) ); 724 addMembers( aggr, expr, [withStmt](IdData & existing, const std::string &) { 725 // on conflict, delete the identifier 726 existing.deleteStmt = withStmt; 727 return true; 728 }); 674 729 } 675 730 } … … 693 748 addIds( ftype->returnVals ); 694 749 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 695 810 } 696 811 -
src/SymTab/Indexer.h
rf343c6b r69c37cc 9 9 // Author : Richard C. Bilson 10 10 // Created On : Sun May 17 21:38:55 2015 11 // Last Modified By : Aaron B. Moss12 // Last Modified On : Fri Mar 8 13:55:00 201913 // Update Count : 911 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Aug 17 16:09:12 2017 13 // Update Count : 8 14 14 // 15 15 16 16 #pragma once 17 17 18 #include < functional> // for function19 #include <list> // for list20 #include < memory> // for shared_ptr, enable_shared_from_this21 #include < string> // for string18 #include <iosfwd> // for ostream 19 #include <list> // for list 20 #include <string> // for string 21 #include <functional> // for function 22 22 23 #include " Common/PersistentMap.h" // for PersistentMap24 #include "SynTree/SynTree.h" // for AST nodes23 #include "SynTree/Visitor.h" // for Visitor 24 #include "SynTree/SynTree.h" // for AST nodes 25 25 26 26 namespace ResolvExpr { 27 class Cost;27 class Cost; 28 28 } 29 29 30 30 namespace SymTab { 31 class Indexer : public std::enable_shared_from_this<SymTab::Indexer>{32 public:31 class Indexer { 32 public: 33 33 explicit Indexer(); 34 35 Indexer( const Indexer &that ); 36 Indexer( Indexer &&that ); 34 37 virtual ~Indexer(); 38 Indexer& operator= ( const Indexer &that ); 39 Indexer& operator= ( Indexer &&that ); 35 40 36 // when using an indexer manually (e.g., within a mutator traversal), it is necessary to 37 // tell the indexerexplicitly when scopes begin and end41 // 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 38 43 void enterScope(); 39 44 void leaveScope(); … … 45 50 /// non-null if this declaration is deleted 46 51 BaseSyntaxNode * deleteStmt = nullptr; 47 /// scope of identifier48 unsigned long scope = 0;49 52 50 53 // NOTE: shouldn't need either of these constructors, but gcc-4 does not properly support initializer lists with default members. 51 54 IdData() = default; 52 IdData( 53 DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt, 54 unsigned long scope ) 55 : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ), scope( scope ) {} 56 IdData( const IdData& o, BaseSyntaxNode * deleteStmt ) 57 : id( o.id ), baseExpr( o.baseExpr ), deleteStmt( deleteStmt ), scope( o.scope ) {} 55 IdData( DeclarationWithType * id, Expression * baseExpr, BaseSyntaxNode * deleteStmt ) : id( id ), baseExpr( baseExpr ), deleteStmt( deleteStmt ) {} 58 56 59 57 Expression * combine( ResolvExpr::Cost & cost ) const; … … 82 80 EnumDecl *globalLookupEnum( const std::string &id ) const; 83 81 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 84 100 void addId( DeclarationWithType * decl, Expression * baseExpr = nullptr ); 85 101 void addDeletedId( DeclarationWithType * decl, BaseSyntaxNode * deleteStmt ); … … 96 112 void addWith( std::list< Expression * > & withExprs, BaseSyntaxNode * withStmt ); 97 113 114 /// adds all of the members of the Aggregate (addWith helper) 115 void addMembers( AggregateDecl * aggr, Expression * expr, ConflictFunction ); 116 98 117 /// convenience function for adding a list of Ids to the indexer 99 118 void addIds( const std::list< DeclarationWithType * > & decls ); … … 105 124 void addFunctionType( FunctionType * ftype ); 106 125 126 bool doDebug = false; ///< Display debugging trace? 107 127 private: 108 /// Wraps a Decl* with a scope 109 template<typename Decl> 110 struct Scoped { 111 Decl* decl; ///< declaration 112 unsigned long scope; ///< scope of this declaration 128 struct Impl; 113 129 114 Scoped(Decl* d, unsigned long s) : decl(d), scope(s) {}115 };130 Impl *tables; ///< Copy-on-write instance of table data structure 131 unsigned long scope; ///< Scope index of this pointer 116 132 117 using Ptr = std::shared_ptr<const Indexer>; 133 /// Takes a new ref to a table (returns null if null) 134 static Impl *newRef( Impl *toClone ); 135 /// Clears a ref to a table (does nothing if null) 136 static void deleteRef( Impl *toFree ); 118 137 119 using MangleTable = PersistentMap< std::string, IdData >; 120 using IdTable = PersistentMap< std::string, MangleTable::Ptr >; 121 using TypeTable = PersistentMap< std::string, Scoped<NamedTypeDecl> >; 122 using StructTable = PersistentMap< std::string, Scoped<StructDecl> >; 123 using EnumTable = PersistentMap< std::string, Scoped<EnumDecl> >; 124 using UnionTable = PersistentMap< std::string, Scoped<UnionDecl> >; 125 using TraitTable = PersistentMap< std::string, Scoped<TraitDecl> >; 138 // Removes matching autogenerated constructors and destructors 139 // so that they will not be selected 140 // void removeSpecialOverrides( FunctionDecl *decl ); 141 void removeSpecialOverrides( const std::string &id, std::list< IdData > & out ) const; 126 142 127 IdTable::Ptr idTable; ///< identifier namespace 128 TypeTable::Ptr typeTable; ///< type namespace 129 StructTable::Ptr structTable; ///< struct namespace 130 EnumTable::Ptr enumTable; ///< enum namespace 131 UnionTable::Ptr unionTable; ///< union namespace 132 TraitTable::Ptr traitTable; ///< trait namespace 133 134 Ptr prevScope; ///< reference to indexer for parent scope 135 unsigned long scope; ///< Scope index of this indexer 136 unsigned long repScope; ///< Scope index of currently represented scope 137 138 /// Ensures that a proper backtracking scope exists before a mutation 139 void lazyInitScope(); 140 141 /// Gets the indexer at the given scope 142 const Indexer* atScope( unsigned long scope ) const; 143 144 /// Removes matching autogenerated constructors and destructors so that they will not be 145 /// selected. If returns false, passed decl should not be added. 146 bool removeSpecialOverrides( IdData& decl, MangleTable::Ptr& mangleTable ); 147 148 /// Options for handling identifier conflicts 149 struct OnConflict { 150 enum { 151 Error, ///< Throw a semantic error 152 Delete ///< Delete the earlier version with the delete statement 153 } mode; 154 BaseSyntaxNode * deleteStmt; ///< Statement that deletes this expression 155 156 private: 157 OnConflict() : mode(Error), deleteStmt(nullptr) {} 158 OnConflict( BaseSyntaxNode * d ) : mode(Delete), deleteStmt(d) {} 159 public: 160 OnConflict( const OnConflict& ) = default; 161 162 static OnConflict error() { return {}; } 163 static OnConflict deleteWith( BaseSyntaxNode * d ) { return { d }; } 164 }; 165 166 /// true if the existing identifier conflicts with the added identifier 167 bool addedIdConflicts( 168 const IdData& existing, DeclarationWithType * added, OnConflict handleConflicts, 169 BaseSyntaxNode * deleteStmt ); 143 /// Ensures that tables variable is writable (i.e. allocated, uniquely owned by this Indexer, and at the current scope) 144 void makeWritable(); 170 145 171 146 /// common code for addId, addDeletedId, etc. 172 void addId( 173 DeclarationWithType * decl, OnConflict handleConflicts, 174 Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr ); 175 176 /// adds all of the members of the Aggregate (addWith helper) 177 void addMembers( AggregateDecl * aggr, Expression * expr, OnConflict handleConflicts ); 178 179 /// returns true if there exists a declaration with C linkage and the given name with the same mangled name 180 bool hasCompatibleCDecl( const std::string &id, const std::string &mangleName ) const; 181 /// returns true if there exists a declaration with C linkage and the given name with a different mangled name 182 bool hasIncompatibleCDecl( const std::string &id, const std::string &mangleName ) const; 147 void addId( DeclarationWithType * decl, ConflictFunction, Expression * baseExpr = nullptr, BaseSyntaxNode * deleteStmt = nullptr ); 183 148 }; 184 149 } // namespace SymTab -
src/SynTree/Attribute.cc
rf343c6b r69c37cc 21 21 #include "Expression.h" // for Expression 22 22 23 Attribute::Attribute( const Attribute &other ) : BaseSyntaxNode( other ),name( other.name ) {23 Attribute::Attribute( const Attribute &other ) : name( other.name ) { 24 24 cloneAll( other.parameters, parameters ); 25 25 } -
src/SynTree/BaseSyntaxNode.h
rf343c6b r69c37cc 18 18 #include "Common/CodeLocation.h" 19 19 #include "Common/Indenter.h" 20 #include "Common/Stats.h"21 22 20 class Visitor; 23 21 class Mutator; … … 25 23 class BaseSyntaxNode { 26 24 public: 27 static Stats::Counters::SimpleCounter* new_nodes;28 29 25 CodeLocation location; 30 31 BaseSyntaxNode() { ++*new_nodes; }32 BaseSyntaxNode( const BaseSyntaxNode& o ) : location(o.location) { ++*new_nodes; }33 26 34 27 virtual ~BaseSyntaxNode() {} -
src/SynTree/Constant.cc
rf343c6b r69c37cc 25 25 Constant::Constant( Type * type, std::string rep, double val ) : type( type ), rep( rep ), val( val ) {} 26 26 27 Constant::Constant( const Constant &other ) : BaseSyntaxNode( other ),rep( other.rep ), val( other.val ) {27 Constant::Constant( const Constant &other ) : rep( other.rep ), val( other.val ) { 28 28 type = other.type->clone(); 29 29 } -
src/SynTree/Declaration.h
rf343c6b r69c37cc 211 211 TypeDecl::Kind kind; 212 212 bool isComplete; 213 214 213 Data() : kind( (TypeDecl::Kind)-1 ), isComplete( false ) {} 215 214 Data( TypeDecl * typeDecl ) : Data( typeDecl->get_kind(), typeDecl->isComplete() ) {} 216 215 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 220 216 bool operator==(const Data & other) const { return kind == other.kind && isComplete == other.isComplete; } 221 217 bool operator!=(const Data & other) const { return !(*this == other);} -
src/SynTree/Statement.h
rf343c6b r69c37cc 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Mar 12 09:01:53 201913 // Update Count : 8312 // Last Modified On : Thu Mar 8 14:53:02 2018 13 // Update Count : 78 14 14 // 15 15 … … 19 19 #include <list> // for list 20 20 #include <memory> // for allocator 21 #include <vector> // for vector21 #include <vector> // for vector 22 22 23 23 #include "BaseSyntaxNode.h" // for BaseSyntaxNode … … 43 43 const std::list<Label> & get_labels() const { return labels; } 44 44 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; 49 49 }; 50 50 … … 55 55 CompoundStmt(); 56 56 CompoundStmt( std::list<Statement *> stmts ); 57 CompoundStmt( const CompoundStmt & other );57 CompoundStmt( const CompoundStmt &other ); 58 58 virtual ~CompoundStmt(); 59 59 … … 62 62 void push_front( Statement * stmt ) { kids.push_front( stmt ); } 63 63 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; 68 68 }; 69 69 … … 72 72 NullStmt( const std::list<Label> & labels = {} ); 73 73 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; 78 78 }; 79 79 80 80 class ExprStmt : public Statement { 81 81 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 ); 86 86 virtual ~ExprStmt(); 87 87 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; 95 95 }; 96 96 … … 98 98 public: 99 99 bool voltile; 100 Expression * instruction;100 Expression *instruction; 101 101 std::list<Expression *> output, input; 102 102 std::list<ConstantExpr *> clobber; 103 103 std::list<Label> gotolabels; 104 104 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 ); 107 107 virtual ~AsmStmt(); 108 108 … … 114 114 void set_output( const std::list<Expression *> & newValue ) { output = newValue; } 115 115 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; } 117 117 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; } 119 119 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; } 121 121 122 122 virtual AsmStmt * clone() const { return new AsmStmt( *this ); } … … 141 141 class IfStmt : public Statement { 142 142 public: 143 Expression * condition;144 Statement * thenPart;145 Statement * elsePart;143 Expression *condition; 144 Statement *thenPart; 145 Statement *elsePart; 146 146 std::list<Statement *> initialization; 147 147 148 IfStmt( Expression * condition, Statement * thenPart, Statement *elsePart,148 IfStmt( Expression *condition, Statement *thenPart, Statement *elsePart, 149 149 std::list<Statement *> initialization = std::list<Statement *>() ); 150 IfStmt( const IfStmt & other );150 IfStmt( const IfStmt &other ); 151 151 virtual ~IfStmt(); 152 152 153 std::list<Statement *> & get_initialization() { return initialization; }154 Expression * get_condition() { return condition; }155 void set_condition( Expression * newValue ) { condition = newValue; }156 Statement * get_thenPart() { return thenPart; }157 void set_thenPart( Statement * newValue ) { thenPart = newValue; }158 Statement * get_elsePart() { return elsePart; }159 void set_elsePart( Statement * newValue ) { elsePart = newValue; }160 161 virtual IfStmt * clone() const override { return new IfStmt( *this ); }162 virtual void accept( Visitor & v ) override { v.visit( this ); }163 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }164 virtual void print( std::ostream & os, Indenter indent = {} ) const override;153 std::list<Statement *> &get_initialization() { return initialization; } 154 Expression *get_condition() { return condition; } 155 void set_condition( Expression *newValue ) { condition = newValue; } 156 Statement *get_thenPart() { return thenPart; } 157 void set_thenPart( Statement *newValue ) { thenPart = newValue; } 158 Statement *get_elsePart() { return elsePart; } 159 void set_elsePart( Statement *newValue ) { elsePart = newValue; } 160 161 virtual IfStmt *clone() const override { return new IfStmt( *this ); } 162 virtual void accept( Visitor &v ) override { v.visit( this ); } 163 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 164 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 165 165 }; 166 166 … … 170 170 std::list<Statement *> statements; 171 171 172 SwitchStmt( Expression * condition, const std::list<Statement *> &statements );173 SwitchStmt( const SwitchStmt & other );172 SwitchStmt( Expression *condition, const std::list<Statement *> &statements ); 173 SwitchStmt( const SwitchStmt &other ); 174 174 virtual ~SwitchStmt(); 175 175 176 Expression * get_condition() { return condition; }177 void set_condition( Expression * newValue ) { condition = newValue; }176 Expression *get_condition() { return condition; } 177 void set_condition( Expression *newValue ) { condition = newValue; } 178 178 179 179 std::list<Statement *> & get_statements() { return statements; } 180 180 181 virtual void accept( Visitor & v ) override { v.visit( this ); }182 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }183 184 virtual SwitchStmt * clone() const override { return new SwitchStmt( *this ); }185 virtual void print( std::ostream & os, Indenter indent = {} ) const override;181 virtual void accept( Visitor &v ) override { v.visit( this ); } 182 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 183 184 virtual SwitchStmt *clone() const override { return new SwitchStmt( *this ); } 185 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 186 186 187 187 }; … … 192 192 std::list<Statement *> stmts; 193 193 194 CaseStmt( Expression * conditions, const std::list<Statement *> &stmts, bool isdef = false ) throw (SemanticErrorException);195 CaseStmt( const CaseStmt & other );194 CaseStmt( Expression *conditions, const std::list<Statement *> &stmts, bool isdef = false ) throw (SemanticErrorException); 195 CaseStmt( const CaseStmt &other ); 196 196 virtual ~CaseStmt(); 197 197 … … 201 201 void set_default(bool b) { _isDefault = b; } 202 202 203 Expression * & get_condition() { return condition; }204 void set_condition( Expression * newValue ) { condition = newValue; }205 206 std::list<Statement *> & get_statements() { return stmts; }207 void set_statements( std::list<Statement *> & newValue ) { stmts = newValue; }208 209 virtual void accept( Visitor & v ) override { v.visit( this ); }210 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }211 212 virtual CaseStmt * clone() const override { return new CaseStmt( *this ); }213 virtual void print( std::ostream & os, Indenter indent = {} ) const override;203 Expression * &get_condition() { return condition; } 204 void set_condition( Expression *newValue ) { condition = newValue; } 205 206 std::list<Statement *> &get_statements() { return stmts; } 207 void set_statements( std::list<Statement *> &newValue ) { stmts = newValue; } 208 209 virtual void accept( Visitor &v ) override { v.visit( this ); } 210 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 211 212 virtual CaseStmt *clone() const override { return new CaseStmt( *this ); } 213 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 214 214 private: 215 215 bool _isDefault; … … 218 218 class WhileStmt : public Statement { 219 219 public: 220 Expression * condition;221 Statement * body;220 Expression *condition; 221 Statement *body; 222 222 std::list<Statement *> initialization; 223 223 bool isDoWhile; 224 224 225 WhileStmt( Expression * condition, Statement * body, std::list<Statement *> & initialization, bool isDoWhile = false ); 226 WhileStmt( const WhileStmt & other ); 225 WhileStmt( Expression *condition, 226 Statement *body, std::list<Statement *> & initialization, bool isDoWhile = false ); 227 WhileStmt( const WhileStmt &other ); 227 228 virtual ~WhileStmt(); 228 229 229 Expression * get_condition() { return condition; }230 void set_condition( Expression * newValue ) { condition = newValue; }231 Statement * get_body() { return body; }232 void set_body( Statement * newValue ) { body = newValue; }230 Expression *get_condition() { return condition; } 231 void set_condition( Expression *newValue ) { condition = newValue; } 232 Statement *get_body() { return body; } 233 void set_body( Statement *newValue ) { body = newValue; } 233 234 bool get_isDoWhile() { return isDoWhile; } 234 235 void set_isDoWhile( bool newValue ) { isDoWhile = newValue; } 235 236 236 virtual WhileStmt * clone() const override { return new WhileStmt( *this ); }237 virtual void accept( Visitor & v ) override { v.visit( this ); }238 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }239 virtual void print( std::ostream & os, Indenter indent = {} ) const override;237 virtual WhileStmt *clone() const override { return new WhileStmt( *this ); } 238 virtual void accept( Visitor &v ) override { v.visit( this ); } 239 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 240 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 240 241 }; 241 242 … … 243 244 public: 244 245 std::list<Statement *> initialization; 245 Expression * condition; 246 Expression * increment; 247 Statement * body; 248 249 ForStmt( std::list<Statement *> initialization, Expression * condition = 0, Expression * increment = 0, Statement * body = 0 ); 250 ForStmt( const ForStmt & other ); 246 Expression *condition; 247 Expression *increment; 248 Statement *body; 249 250 ForStmt( std::list<Statement *> initialization, 251 Expression *condition = 0, Expression *increment = 0, Statement *body = 0 ); 252 ForStmt( const ForStmt &other ); 251 253 virtual ~ForStmt(); 252 254 253 std::list<Statement *> & get_initialization() { return initialization; }254 Expression * get_condition() { return condition; }255 void set_condition( Expression * newValue ) { condition = newValue; }256 Expression * get_increment() { return increment; }257 void set_increment( Expression * newValue ) { increment = newValue; }258 Statement * get_body() { return body; }259 void set_body( Statement * newValue ) { body = newValue; }260 261 virtual ForStmt * clone() const override { return new ForStmt( *this ); }262 virtual void accept( Visitor & v ) override { v.visit( this ); }263 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }264 virtual void print( std::ostream & os, Indenter indent = {} ) const override;255 std::list<Statement *> &get_initialization() { return initialization; } 256 Expression *get_condition() { return condition; } 257 void set_condition( Expression *newValue ) { condition = newValue; } 258 Expression *get_increment() { return increment; } 259 void set_increment( Expression *newValue ) { increment = newValue; } 260 Statement *get_body() { return body; } 261 void set_body( Statement *newValue ) { body = newValue; } 262 263 virtual ForStmt *clone() const override { return new ForStmt( *this ); } 264 virtual void accept( Visitor &v ) override { v.visit( this ); } 265 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 266 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 265 267 }; 266 268 … … 272 274 const Label originalTarget; 273 275 Label target; 274 Expression * computedTarget;276 Expression *computedTarget; 275 277 Type type; 276 278 277 279 BranchStmt( Label target, Type ) throw (SemanticErrorException); 278 BranchStmt( Expression * computedTarget, Type ) throw (SemanticErrorException);280 BranchStmt( Expression *computedTarget, Type ) throw (SemanticErrorException); 279 281 280 282 Label get_originalTarget() { return originalTarget; } … … 282 284 void set_target( Label newValue ) { target = newValue; } 283 285 284 Expression * get_computedTarget() { return computedTarget; }286 Expression *get_computedTarget() { return computedTarget; } 285 287 void set_target( Expression * newValue ) { computedTarget = newValue; } 286 288 287 289 Type get_type() { return type; } 288 const char * get_typename() { return brType[ type ]; }289 290 virtual BranchStmt * clone() const override { return new BranchStmt( *this ); }291 virtual void accept( Visitor & v ) override { v.visit( this ); }292 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }293 virtual void print( std::ostream & os, Indenter indent = {} ) const override;290 const char *get_typename() { return brType[ type ]; } 291 292 virtual BranchStmt *clone() const override { return new BranchStmt( *this ); } 293 virtual void accept( Visitor &v ) override { v.visit( this ); } 294 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 295 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 294 296 private: 295 static const char * brType[];297 static const char *brType[]; 296 298 }; 297 299 298 300 class ReturnStmt : public Statement { 299 301 public: 300 Expression * expr;301 302 ReturnStmt( Expression * expr );303 ReturnStmt( const ReturnStmt & other );302 Expression *expr; 303 304 ReturnStmt( Expression *expr ); 305 ReturnStmt( const ReturnStmt &other ); 304 306 virtual ~ReturnStmt(); 305 307 306 Expression * get_expr() { return expr; }307 void set_expr( Expression * newValue ) { expr = newValue; }308 309 virtual ReturnStmt * clone() const override { return new ReturnStmt( *this ); }310 virtual void accept( Visitor & v ) override { v.visit( this ); }311 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }312 virtual void print( std::ostream & os, Indenter indent = {} ) const override;308 Expression *get_expr() { return expr; } 309 void set_expr( Expression *newValue ) { expr = newValue; } 310 311 virtual ReturnStmt *clone() const override { return new ReturnStmt( *this ); } 312 virtual void accept( Visitor &v ) override { v.visit( this ); } 313 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 314 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 313 315 }; 314 316 … … 322 324 323 325 ThrowStmt( Kind kind, Expression * expr, Expression * target = nullptr ); 324 ThrowStmt( const ThrowStmt & other );326 ThrowStmt( const ThrowStmt &other ); 325 327 virtual ~ThrowStmt(); 326 328 … … 331 333 void set_target( Expression * newTarget ) { target = newTarget; } 332 334 333 virtual ThrowStmt * clone() const override { return new ThrowStmt( *this ); }334 virtual void accept( Visitor & v ) override { v.visit( this ); }335 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }336 virtual void print( std::ostream & os, Indenter indent = {} ) const override;335 virtual ThrowStmt *clone() const override { return new ThrowStmt( *this ); } 336 virtual void accept( Visitor &v ) override { v.visit( this ); } 337 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 338 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 337 339 }; 338 340 … … 343 345 FinallyStmt * finallyBlock; 344 346 345 TryStmt( CompoundStmt * tryBlock, std::list<CatchStmt *> & handlers, FinallyStmt *finallyBlock = 0 );346 TryStmt( const TryStmt & other );347 TryStmt( CompoundStmt *tryBlock, std::list<CatchStmt *> &handlers, FinallyStmt *finallyBlock = 0 ); 348 TryStmt( const TryStmt &other ); 347 349 virtual ~TryStmt(); 348 350 349 CompoundStmt * get_block() const { return block; }350 void set_block( CompoundStmt * newValue ) { block = newValue; }351 CompoundStmt *get_block() const { return block; } 352 void set_block( CompoundStmt *newValue ) { block = newValue; } 351 353 std::list<CatchStmt *>& get_catchers() { return handlers; } 352 354 353 FinallyStmt * get_finally() const { return finallyBlock; }354 void set_finally( FinallyStmt * newValue ) { finallyBlock = newValue; }355 356 virtual TryStmt * clone() const override { return new TryStmt( *this ); }357 virtual void accept( Visitor & v ) override { v.visit( this ); }358 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }359 virtual void print( std::ostream & os, Indenter indent = {} ) const override;355 FinallyStmt *get_finally() const { return finallyBlock; } 356 void set_finally( FinallyStmt *newValue ) { finallyBlock = newValue; } 357 358 virtual TryStmt *clone() const override { return new TryStmt( *this ); } 359 virtual void accept( Visitor &v ) override { v.visit( this ); } 360 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 361 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 360 362 }; 361 363 … … 365 367 366 368 const Kind kind; 367 Declaration * decl;368 Expression * cond;369 Statement * body;370 371 CatchStmt( Kind kind, Declaration * decl,372 Expression * cond, Statement *body );373 CatchStmt( const CatchStmt & other );369 Declaration *decl; 370 Expression *cond; 371 Statement *body; 372 373 CatchStmt( Kind kind, Declaration *decl, 374 Expression *cond, Statement *body ); 375 CatchStmt( const CatchStmt &other ); 374 376 virtual ~CatchStmt(); 375 377 376 378 Kind get_kind() { return kind; } 377 Declaration * get_decl() { return decl; }378 void set_decl( Declaration * newValue ) { decl = newValue; }379 Expression * get_cond() { return cond; }380 void set_cond( Expression * newCond ) { cond = newCond; }381 Statement * get_body() { return body; }382 void set_body( Statement * newValue ) { body = newValue; }383 384 virtual CatchStmt * clone() const override { return new CatchStmt( *this ); }385 virtual void accept( Visitor & v ) override { v.visit( this ); }386 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }387 virtual void print( std::ostream & os, Indenter indent = {} ) const override;379 Declaration *get_decl() { return decl; } 380 void set_decl( Declaration *newValue ) { decl = newValue; } 381 Expression *get_cond() { return cond; } 382 void set_cond( Expression *newCond ) { cond = newCond; } 383 Statement *get_body() { return body; } 384 void set_body( Statement *newValue ) { body = newValue; } 385 386 virtual CatchStmt *clone() const override { return new CatchStmt( *this ); } 387 virtual void accept( Visitor &v ) override { v.visit( this ); } 388 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 389 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 388 390 }; 389 391 390 392 class FinallyStmt : public Statement { 391 393 public: 392 CompoundStmt * block;393 394 FinallyStmt( CompoundStmt * block );395 FinallyStmt( const FinallyStmt & other );394 CompoundStmt *block; 395 396 FinallyStmt( CompoundStmt *block ); 397 FinallyStmt( const FinallyStmt &other ); 396 398 virtual ~FinallyStmt(); 397 399 398 CompoundStmt * get_block() const { return block; }399 void set_block( CompoundStmt * newValue ) { block = newValue; }400 401 virtual FinallyStmt * clone() const override { return new FinallyStmt( *this ); }402 virtual void accept( Visitor & v ) override { v.visit( this ); }403 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }404 virtual void print( std::ostream & os, Indenter indent = {} ) const override;400 CompoundStmt *get_block() const { return block; } 401 void set_block( CompoundStmt *newValue ) { block = newValue; } 402 403 virtual FinallyStmt *clone() const override { return new FinallyStmt( *this ); } 404 virtual void accept( Visitor &v ) override { v.visit( this ); } 405 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 406 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 405 407 }; 406 408 … … 436 438 } orelse; 437 439 438 virtual WaitForStmt * clone() const override { return new WaitForStmt( *this ); }439 virtual void accept( Visitor & v ) override { v.visit( this ); }440 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }441 virtual void print( std::ostream & os, Indenter indent = {} ) const override;440 virtual WaitForStmt *clone() const override { return new WaitForStmt( *this ); } 441 virtual void accept( Visitor &v ) override { v.visit( this ); } 442 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 443 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 442 444 443 445 }; … … 462 464 class DeclStmt : public Statement { 463 465 public: 464 Declaration * decl;465 466 DeclStmt( Declaration * decl );467 DeclStmt( const DeclStmt & other );466 Declaration *decl; 467 468 DeclStmt( Declaration *decl ); 469 DeclStmt( const DeclStmt &other ); 468 470 virtual ~DeclStmt(); 469 471 470 Declaration * get_decl() const { return decl; } 471 void set_decl( Declaration * newValue ) { decl = newValue; } 472 473 virtual DeclStmt * clone() const override { return new DeclStmt( *this ); } 474 virtual void accept( Visitor & v ) override { v.visit( this ); } 475 virtual Statement * acceptMutator( Mutator & m ) override { return m.mutate( this ); } 476 virtual void print( std::ostream & os, Indenter indent = {} ) const override; 477 }; 478 479 480 /// represents an implicit application of a constructor or destructor. Qualifiers are replaced immediately before and 481 /// after the call so that qualified objects can be constructed with the same functions as unqualified objects. 472 Declaration *get_decl() const { return decl; } 473 void set_decl( Declaration *newValue ) { decl = newValue; } 474 475 virtual DeclStmt *clone() const override { return new DeclStmt( *this ); } 476 virtual void accept( Visitor &v ) override { v.visit( this ); } 477 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 478 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 479 }; 480 481 482 /// represents an implicit application of a constructor or destructor. Qualifiers are replaced 483 /// immediately before and after the call so that qualified objects can be constructed 484 /// with the same functions as unqualified objects. 482 485 class ImplicitCtorDtorStmt : public Statement { 483 486 public: … … 489 492 virtual ~ImplicitCtorDtorStmt(); 490 493 491 Statement * get_callStmt() const { return callStmt; }494 Statement *get_callStmt() const { return callStmt; } 492 495 void set_callStmt( Statement * newValue ) { callStmt = newValue; } 493 496 494 virtual ImplicitCtorDtorStmt * clone() const override { return new ImplicitCtorDtorStmt( *this ); }495 virtual void accept( Visitor & v ) override { v.visit( this ); }496 virtual Statement * acceptMutator( Mutator &m ) override { return m.mutate( this ); }497 virtual void print( std::ostream & os, Indenter indent = {} ) const override;497 virtual ImplicitCtorDtorStmt *clone() const override { return new ImplicitCtorDtorStmt( *this ); } 498 virtual void accept( Visitor &v ) override { v.visit( this ); } 499 virtual Statement *acceptMutator( Mutator &m ) override { return m.mutate( this ); } 500 virtual void print( std::ostream &os, Indenter indent = {} ) const override; 498 501 }; 499 502 -
src/main.cc
rf343c6b r69c37cc 65 65 using namespace std; 66 66 67 67 68 void NewPass(const char * const name) { 68 69 Stats::Heap::newPass(name); 69 70 using namespace Stats::Counters; 70 71 { 72 static auto group = build<CounterGroup>("Pass Visitor"); 73 auto pass = build<CounterGroup>(name, group); 74 pass_visitor_stats.depth = 0; 75 pass_visitor_stats.avg = build<AverageCounter<double>>("Average Depth", pass); 76 pass_visitor_stats.max = build<MaxCounter<double>>("Max Depth", pass); 77 } 78 79 { 80 static auto group = build<CounterGroup>("Syntax Node"); 81 auto pass = build<CounterGroup>(name, group); 82 BaseSyntaxNode::new_nodes = build<SimpleCounter>("Allocs", pass); 83 } 71 static auto pass_visitor_group = build<CounterGroup>("Pass Visitor"); 72 auto pass = build<CounterGroup>(name, pass_visitor_group); 73 pass_visitor_stats.depth = 0; 74 pass_visitor_stats.avg = build<AverageCounter<double>>("Average Depth", pass); 75 pass_visitor_stats.max = build<MaxCounter<double>>("Max Depth", pass); 84 76 } 85 77 -
tests/.expect/KRfunctions.x64.txt
rf343c6b r69c37cc 82 82 signed int _X1ai_2; 83 83 signed int _X1bi_2; 84 signed int *(*_tmp_cp_ret 4)(signed int _X1xi_1, signed int _X1yi_1);85 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret 4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));86 ((void)(_tmp_cp_ret 4) /* ^?{} */);84 signed int *(*_tmp_cp_ret2)(signed int _X1xi_1, signed int _X1yi_1); 85 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret2=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret2))); 86 ((void)(_tmp_cp_ret2) /* ^?{} */); 87 87 const signed int _X2f1Fi_iPiPi__2(signed int _X1ai_2, signed int *_X1bPi_2, signed int *_X1cPi_2){ 88 88 __attribute__ ((unused)) const signed int _X10_retval_f1Ki_2; -
tests/.expect/KRfunctions.x86.txt
rf343c6b r69c37cc 82 82 signed int _X1ai_2; 83 83 signed int _X1bi_2; 84 signed int *(*_tmp_cp_ret 4)(signed int _X1xi_1, signed int _X1yi_1);85 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret 4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));86 ((void)(_tmp_cp_ret 4) /* ^?{} */);84 signed int *(*_tmp_cp_ret2)(signed int _X1xi_1, signed int _X1yi_1); 85 ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret2=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret2))); 86 ((void)(_tmp_cp_ret2) /* ^?{} */); 87 87 const signed int _X2f1Fi_iPiPi__2(signed int _X1ai_2, signed int *_X1bPi_2, signed int *_X1cPi_2){ 88 88 __attribute__ ((unused)) const signed int _X10_retval_f1Ki_2; -
tests/.expect/completeTypeError.txt
rf343c6b r69c37cc 1 completeTypeError.cfa:34:1 error: Cannot choose between 2 alternatives for expression 2 Generated Cast of: 3 Applying untyped: 4 Name: *? 5 ...to: 6 Name: x 1 completeTypeError.cfa:33:1 error: No reasonable alternatives for expression Applying untyped: 2 Name: *? 3 ...to: 4 Name: v 7 5 8 ... to: nothing Alternatives are: 9 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of: 10 Application of 11 Variable Expression: *?: forall 12 DT: object type 13 function 14 ... with parameters 15 intrinsic pointer to instance of type DT (not function type) 16 ... returning 17 _retval__operator_deref: reference to instance of type DT (not function type) 18 ... with attributes: 19 Attribute with name: unused 20 21 22 ... to arguments 23 Variable Expression: x: pointer to instance of struct A with body 0 24 25 ... to: nothing 26 (types: 27 void 28 ) 29 Environment:( _80_4_DT ) -> instance of struct A with body 0 (no widening) 30 31 32 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of: 33 Application of 34 Variable Expression: *?: forall 35 DT: object type 36 function 37 ... with parameters 38 intrinsic pointer to instance of type DT (not function type) 39 ... returning 40 _retval__operator_deref: reference to instance of type DT (not function type) 41 ... with attributes: 42 Attribute with name: unused 43 44 45 ... to arguments 46 Variable Expression: x: pointer to instance of struct B with body 1 47 48 ... to: nothing 49 (types: 50 void 51 ) 52 Environment:( _80_4_DT ) -> instance of struct B with body 1 (no widening) 53 54 6 completeTypeError.cfa:34:1 error: No reasonable alternatives for expression Applying untyped: 7 Name: *? 8 ...to: 9 Name: y 55 10 56 11 completeTypeError.cfa:35:1 error: No reasonable alternatives for expression Applying untyped: … … 69 24 Name: v 70 25 71 completeTypeError.cfa:5 9:1 error: No reasonable alternatives for expression Applying untyped:26 completeTypeError.cfa:58:1 error: No reasonable alternatives for expression Applying untyped: 72 27 Name: baz 73 28 ...to: 74 29 Name: y 75 30 76 completeTypeError.cfa: 60:1 error: No reasonable alternatives for expression Applying untyped:31 completeTypeError.cfa:59:1 error: No reasonable alternatives for expression Applying untyped: 77 32 Name: quux 78 33 ...to: 79 34 Name: y 80 35 81 completeTypeError.cfa:72:1 error: No alternatives with satisfiable assertions for Applying untyped: 36 completeTypeError.cfa:60:1 error: No reasonable alternatives for expression Applying untyped: 37 Name: *? 38 ...to: 39 Name: y 40 41 completeTypeError.cfa:72:1 error: No resolvable alternatives for expression Applying untyped: 82 42 Name: baz 83 43 ...to: 84 44 Name: z 85 45 86 Unsatisfiable alternative:46 Alternatives with failing assertions are: 87 47 Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of 88 Variable Expression: baz: forall89 T: sized object type90 ... with assertions91 ?=?: pointer to function92 ... with parameters93 reference to instance of type T (not function type)94 instance of type T (not function type)95 ... returning96 _retval__operator_assign: instance of type T (not function type)97 ... with attributes:98 Attribute with name: unused48 Variable Expression: baz: forall 49 T: sized object type 50 ... with assertions 51 ?=?: pointer to function 52 ... with parameters 53 reference to instance of type T (not function type) 54 instance of type T (not function type) 55 ... returning 56 _retval__operator_assign: instance of type T (not function type) 57 ... with attributes: 58 Attribute with name: unused 99 59 100 60 101 ?{}: pointer to function102 ... with parameters103 reference to instance of type T (not function type)104 ... returning nothing61 ?{}: pointer to function 62 ... with parameters 63 reference to instance of type T (not function type) 64 ... returning nothing 105 65 106 ?{}: pointer to function107 ... with parameters108 reference to instance of type T (not function type)109 instance of type T (not function type)110 ... returning nothing66 ?{}: pointer to function 67 ... with parameters 68 reference to instance of type T (not function type) 69 instance of type T (not function type) 70 ... returning nothing 111 71 112 ^?{}: pointer to function113 ... with parameters114 reference to instance of type T (not function type)115 ... returning nothing72 ^?{}: pointer to function 73 ... with parameters 74 reference to instance of type T (not function type) 75 ... returning nothing 116 76 117 77 118 function119 ... with parameters120 pointer to instance of type T (not function type)121 ... returning nothing78 function 79 ... with parameters 80 pointer to instance of type T (not function type) 81 ... returning nothing 122 82 123 ... to arguments124 Variable Expression: z: pointer to instance of type T (not function type)83 ... to arguments 84 Variable Expression: z: pointer to instance of type T (not function type) 125 85 126 (types: 127 void 128 ) 129 Environment:( _99_0_T ) -> instance of type T (not function type) (no widening) 130 131 Could not satisfy assertion: 132 ?=?: pointer to function 133 ... with parameters 134 reference to instance of type _99_0_T (not function type) 135 instance of type _99_0_T (not function type) 136 ... returning 137 _retval__operator_assign: instance of type _99_0_T (not function type) 138 ... with attributes: 139 Attribute with name: unused 86 (types: 87 void 88 ) 89 Environment:( _74_0_T ) -> instance of type T (not function type) (no widening) 140 90 141 91 92 -
tests/.expect/declarationSpecifier.x64.txt
rf343c6b r69c37cc 698 698 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){ 699 699 __attribute__ ((unused)) signed int _X12_retval_maini_1; 700 signed int _tmp_cp_ret 4;701 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);702 ((void)(_tmp_cp_ret 4) /* ^?{} */);700 signed int _tmp_cp_ret2; 701 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret2)) /* ?{} */); 702 ((void)(_tmp_cp_ret2) /* ^?{} */); 703 703 return _X12_retval_maini_1; 704 704 } -
tests/.expect/declarationSpecifier.x86.txt
rf343c6b r69c37cc 698 698 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){ 699 699 __attribute__ ((unused)) signed int _X12_retval_maini_1; 700 signed int _tmp_cp_ret 4;701 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);702 ((void)(_tmp_cp_ret 4) /* ^?{} */);700 signed int _tmp_cp_ret2; 701 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret2)) /* ?{} */); 702 ((void)(_tmp_cp_ret2) /* ^?{} */); 703 703 return _X12_retval_maini_1; 704 704 } -
tests/.expect/extension.x64.txt
rf343c6b r69c37cc 186 186 __extension__ signed int _X1ci_2; 187 187 ((void)(__extension__ _X1ai_2=(__extension__ _X1bi_2+__extension__ _X1ci_2))); 188 signed int _tmp_cp_ret 4;189 ((void)(((void)(_tmp_cp_ret 4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));190 ((void)(_tmp_cp_ret 4) /* ^?{} */);188 signed int _tmp_cp_ret2; 189 ((void)(((void)(_tmp_cp_ret2=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret2)); 190 ((void)(_tmp_cp_ret2) /* ^?{} */); 191 191 __extension__ signed int _X4maryFi_i__2(signed int _X1pi_2){ 192 192 __attribute__ ((unused)) signed int _X12_retval_maryi_2; -
tests/.expect/extension.x86.txt
rf343c6b r69c37cc 186 186 __extension__ signed int _X1ci_2; 187 187 ((void)(__extension__ _X1ai_2=(__extension__ _X1bi_2+__extension__ _X1ci_2))); 188 signed int _tmp_cp_ret 4;189 ((void)(((void)(_tmp_cp_ret 4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));190 ((void)(_tmp_cp_ret 4) /* ^?{} */);188 signed int _tmp_cp_ret2; 189 ((void)(((void)(_tmp_cp_ret2=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret2)); 190 ((void)(_tmp_cp_ret2) /* ^?{} */); 191 191 __extension__ signed int _X4maryFi_i__2(signed int _X1pi_2){ 192 192 __attribute__ ((unused)) signed int _X12_retval_maryi_2; -
tests/.expect/gccExtensions.x64.txt
rf343c6b r69c37cc 171 171 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){ 172 172 __attribute__ ((unused)) signed int _X12_retval_maini_1; 173 signed int _tmp_cp_ret 4;174 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);175 ((void)(_tmp_cp_ret 4) /* ^?{} */);173 signed int _tmp_cp_ret2; 174 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret2)) /* ?{} */); 175 ((void)(_tmp_cp_ret2) /* ^?{} */); 176 176 return _X12_retval_maini_1; 177 177 } -
tests/.expect/gccExtensions.x86.txt
rf343c6b r69c37cc 171 171 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){ 172 172 __attribute__ ((unused)) signed int _X12_retval_maini_1; 173 signed int _tmp_cp_ret 4;174 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret 4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);175 ((void)(_tmp_cp_ret 4) /* ^?{} */);173 signed int _tmp_cp_ret2; 174 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret2=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret2)) /* ?{} */); 175 ((void)(_tmp_cp_ret2) /* ^?{} */); 176 176 return _X12_retval_maini_1; 177 177 } -
tests/.expect/loopctrl.txt
rf343c6b r69c37cc 19 19 10 8 6 4 2 20 20 21 1 2 3 4 5 6 7 8 9 1022 10 9 8 7 6 5 4 3 2 1 023 21 2 4 6 8 10 24 22 2.1 3.8 5.5 7.2 8.9 … … 44 42 (10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0) 45 43 (10 10)(9 9)(8 8)(7 7)(6 6)(5 5)(4 4)(3 3)(2 2)(1 1)(0 0) 46 47 0 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 448 0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -1449 0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 1350 0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -2351 52 0 -5 1 -4 2 -3 3 -2 4 -1 5 0 6 1 7 2 8 3 9 453 0 -5 1 -6 2 -7 3 -8 4 -9 5 -10 6 -11 7 -12 8 -13 9 -1454 0 -5 1 -3 2 -1 3 1 4 3 5 5 6 7 7 9 8 11 9 1355 0 -5 1 -7 2 -9 3 -11 4 -13 5 -15 6 -17 7 -19 8 -21 9 -2356 57 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.558 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.559 0 -5 1.5 1 -7 2.5 2 -9 3.5 3 -11 4.5 4 -13 5.5 5 -15 6.5 6 -17 7.5 7 -19 8.5 8 -21 9.5 9 -23 10.5 -
tests/.expect/math1.txt
rf343c6b r69c37cc 10 10 expm1:1.71828 1.71828182845905 1.71828182845904524 11 11 pow:1 1 1 0.273957+0.583701i 0.273957253830121+0.583700758758615i -0.638110484918098871+0.705394566961838155i 12 16 \ 2 = 256 13 912673 256 64 -64 0 0 14 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i 15 0 0 18.3791736799526 0.264715-1.1922i 16 16 17 4 16 12 \ 16 256 13 \ 912673 256 64 -64 0.015625 -0.015625 18.3791736799526 0.264715-1.1922i -
tests/Makefile.am
rf343c6b r69c37cc 28 28 timeouts= 29 29 30 TEST_PY = python 3${builddir}/test.py30 TEST_PY = python ${builddir}/test.py 31 31 32 32 # applies to both programs … … 36 36 -Wno-unused-function \ 37 37 -quiet @CFA_FLAGS@ \ 38 -DIN_DIR="${ abs_srcdir}/.in/"38 -DIN_DIR="${srcdir}/.in/" 39 39 40 40 AM_CFLAGS += ${DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS} 41 41 CC = @CFACC@ 42 42 43 PRETTY_PATH= mkdir -p $(dir $(abspath ${@})) &&cd ${srcdir} &&43 PRETTY_PATH=cd ${srcdir} && 44 44 45 45 .PHONY: list .validate … … 48 48 49 49 avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa 50 # automake doesn't know we still need C /CPPrules so pretend like we have a C program51 _dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp50 # automake doesn't know we still need C rules so pretend like we have a C program 51 _dummy_hack_SOURCES = .dummy_hack.c 52 52 53 53 #---------------------------------------------------------------------------------------------------------------- … … 74 74 @echo "int main() { return 0; }" > ${@} 75 75 76 .dummy_hackxx.cpp:77 @echo "int bar() { return 0; }" > ${@}78 79 76 concurrency : 80 77 @+${TEST_PY} --debug=${debug} --install=${installed} -Iconcurrent … … 82 79 #---------------------------------------------------------------------------------------------------------------- 83 80 84 # Use for all tests, make sure the path are correct and all flags are added85 CFACOMPILETEST=$(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) $($(shell echo "${@}_FLAGS" | sed 's/-\|\//_/g'))86 87 # Use for tests that either generate an executable, print directyl to stdout or the make command is expected to fail88 CFATEST_STDOUT=$(CFACOMPILETEST) -o $(abspath ${@})89 90 # Use for tests where the make command is expecte to succeed but the expected.txt should be compared to stderr91 CFATEST_STDERR=$(CFACOMPILETEST) 2> $(abspath ${@})92 93 #----------------------------------------------------------------------------------------------------------------94 95 81 # implicit rule so not all test require a rule 96 82 % : %.cfa $(CFACC) 97 $( CFATEST_STDOUT)83 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 98 84 99 % : %.cpp 100 $(PRETTY_PATH) $(C XXCOMPILE)$(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@})85 declarationSpecifier: declarationSpecifier.cfa $(CFACC) 86 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 101 87 102 #------------------------------------------------------------------------------ 103 # TARGET WITH STANDARD RULE BUT CUSTOM FLAGS 104 #------------------------------------------------------------------------------ 105 # Expected failures 106 declarationSpecifier_FLAGS= -CFA -XCFA -p 107 gccExtensions_FLAGS= -CFA -XCFA -p 108 extension_FLAGS= -CFA -XCFA -p 109 attributes_FLAGS= -CFA -XCFA -p 110 functions_FLAGS= -CFA -XCFA -p 111 KRfunctions_FLAGS= -CFA -XCFA -p 112 gmp_FLAGS= -lgmp 88 gccExtensions : gccExtensions.cfa $(CFACC) 89 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 113 90 114 #------------------------------------------------------------------------------ 115 # Expected failures 116 completeTypeError_FLAGS= -DERR1 91 extension : extension.cfa $(CFACC) 92 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 117 93 118 #------------------------------------------------------------------------------ 119 # CUSTOM TARGET 120 #------------------------------------------------------------------------------ 121 typedefRedef-ERR1: typedefRedef.cfa $(CFACC) 122 $(CFATEST_STDOUT) -DERR1 94 attributes : attributes.cfa $(CFACC) 95 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 123 96 124 alloc-ERROR: alloc.cfa $(CFACC)125 $( CFATEST_STDOUT) -DERR197 functions: functions.cfa $(CFACC) 98 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 126 99 127 nested-types-ERR1: nested-types.cfa $(CFACC)128 $( CFATEST_STDOUT) -DERR1100 KRfunctions : KRfunctions.cfa $(CFACC) 101 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 129 102 130 nested-types-ERR2: nested-types.cfa$(CFACC)131 $( CFATEST_STDOUT) -DERR2103 sched-ext-parse : sched-ext-parse.c $(CFACC) 104 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 132 105 133 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC) 134 $(CFATEST_STDOUT) -DERR1 135 136 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC) 137 $(CFATEST_STDOUT) -DERR2 138 139 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC) 140 $(CFATEST_STDOUT) -DERR1 141 142 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC) 143 $(CFATEST_STDOUT) -DERR1 106 gmp : gmp.cfa $(CFACC) 107 $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 144 108 145 109 #builtins 146 110 builtins/sync: builtins/sync.cfa $(CFACC) 147 $(CFATEST_STDERR) -fsyntax-only 111 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only 112 113 #------------------------------------------------------------------------------ 114 115 #To make errors path independent we need to cd into the correct directories 116 completeTypeError : completeTypeError.cfa $(CFACC) 117 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 118 119 typedefRedef-ERR1: typedefRedef.cfa $(CFACC) 120 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 121 122 alloc-ERROR: alloc.cfa $(CFACC) 123 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 124 125 fallthrough-ERROR: fallthrough.cfa $(CFACC) 126 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 127 128 nested-types-ERR1: nested-types.cfa $(CFACC) 129 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 130 131 nested-types-ERR2: nested-types.cfa $(CFACC) 132 $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 133 134 # Constructor/destructor tests 135 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC) 136 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 137 138 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC) 139 $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 140 141 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC) 142 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 143 144 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC) 145 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 148 146 149 147 # Warnings 150 148 warnings/self-assignment: warnings/self-assignment.cfa $(CFACC) 151 $( CFATEST_STDERR) -fsyntax-only149 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only -
tests/Makefile.in
rf343c6b r69c37cc 107 107 CONFIG_CLEAN_FILES = config.py 108 108 CONFIG_CLEAN_VPATH_FILES = test.py 109 am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT) .dummy_hackxx.$(OBJEXT)109 am__dummy_hack_OBJECTS = .dummy_hack.$(OBJEXT) 110 110 _dummy_hack_OBJECTS = $(am__dummy_hack_OBJECTS) 111 111 _dummy_hack_LDADD = $(LDADD) … … 155 155 am__v_CCLD_0 = @echo " CCLD " $@; 156 156 am__v_CCLD_1 = 157 CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \158 $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)159 LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \160 $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \161 $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \162 $(AM_CXXFLAGS) $(CXXFLAGS)163 AM_V_CXX = $(am__v_CXX_@AM_V@)164 am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)165 am__v_CXX_0 = @echo " CXX " $@;166 am__v_CXX_1 =167 CXXLD = $(CXX)168 CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \169 $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \170 $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@171 AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)172 am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)173 am__v_CXXLD_0 = @echo " CXXLD " $@;174 am__v_CXXLD_1 =175 157 SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES) 176 158 DIST_SOURCES = $(_dummy_hack_SOURCES) $(avl_test_SOURCES) … … 378 360 concurrent = 379 361 timeouts = 380 TEST_PY = python 3${builddir}/test.py362 TEST_PY = python ${builddir}/test.py 381 363 382 364 # applies to both programs 383 365 AM_CFLAGS = $(if $(test), 2> $(test), ) -g -Wall -Wno-unused-function \ 384 -quiet @CFA_FLAGS@ -DIN_DIR="${ abs_srcdir}/.in/"\385 ${ DEBUG_FLAGS} ${INSTALL_FLAGS} ${ARCH_FLAGS}386 PRETTY_PATH = mkdir -p $(dir $(abspath ${@})) &&cd ${srcdir} &&366 -quiet @CFA_FLAGS@ -DIN_DIR="${srcdir}/.in/" ${DEBUG_FLAGS} \ 367 ${INSTALL_FLAGS} ${ARCH_FLAGS} 368 PRETTY_PATH = cd ${srcdir} && 387 369 avl_test_SOURCES = avltree/avl_test.cfa avltree/avl0.cfa avltree/avl1.cfa avltree/avl2.cfa avltree/avl3.cfa avltree/avl4.cfa avltree/avl-private.cfa 388 # automake doesn't know we still need C/CPP rules so pretend like we have a C program 389 _dummy_hack_SOURCES = .dummy_hack.c .dummy_hackxx.cpp 390 391 #---------------------------------------------------------------------------------------------------------------- 392 393 # Use for all tests, make sure the path are correct and all flags are added 394 CFACOMPILETEST = $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) $($(shell echo "${@}_FLAGS" | sed 's/-\|\//_/g')) 395 396 # Use for tests that either generate an executable, print directyl to stdout or the make command is expected to fail 397 CFATEST_STDOUT = $(CFACOMPILETEST) -o $(abspath ${@}) 398 399 # Use for tests where the make command is expecte to succeed but the expected.txt should be compared to stderr 400 CFATEST_STDERR = $(CFACOMPILETEST) 2> $(abspath ${@}) 401 402 #------------------------------------------------------------------------------ 403 # TARGET WITH STANDARD RULE BUT CUSTOM FLAGS 404 #------------------------------------------------------------------------------ 405 # Expected failures 406 declarationSpecifier_FLAGS = -CFA -XCFA -p 407 gccExtensions_FLAGS = -CFA -XCFA -p 408 extension_FLAGS = -CFA -XCFA -p 409 attributes_FLAGS = -CFA -XCFA -p 410 functions_FLAGS = -CFA -XCFA -p 411 KRfunctions_FLAGS = -CFA -XCFA -p 412 gmp_FLAGS = -lgmp 413 414 #------------------------------------------------------------------------------ 415 # Expected failures 416 completeTypeError_FLAGS = -DERR1 370 # automake doesn't know we still need C rules so pretend like we have a C program 371 _dummy_hack_SOURCES = .dummy_hack.c 417 372 all: all-am 418 373 419 374 .SUFFIXES: 420 .SUFFIXES: .c .cfa . cpp .dummy_hack .dummy_hackxx.lo .o .obj .validate375 .SUFFIXES: .c .cfa .dummy_hack .lo .o .obj .validate 421 376 $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/src/cfa.make $(am__configure_deps) 422 377 @for dep in $?; do \ … … 454 409 .dummy_hack$(EXEEXT): $(_dummy_hack_OBJECTS) $(_dummy_hack_DEPENDENCIES) $(EXTRA__dummy_hack_DEPENDENCIES) 455 410 @rm -f .dummy_hack$(EXEEXT) 456 $(AM_V_C XXLD)$(CXXLINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS)411 $(AM_V_CCLD)$(LINK) $(_dummy_hack_OBJECTS) $(_dummy_hack_LDADD) $(LIBS) 457 412 avltree/$(am__dirstamp): 458 413 @$(MKDIR_P) avltree … … 488 443 489 444 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/.dummy_hack.Po@am__quote@ 490 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/.dummy_hackxx.Po@am__quote@491 445 492 446 .c.o: … … 513 467 @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ 514 468 @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< 515 516 .cpp.o:517 @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\518 @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\519 @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po520 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@521 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@522 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<523 524 .cpp.obj:525 @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\526 @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\527 @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po528 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@529 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@530 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`531 532 .cpp.lo:533 @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\534 @am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\535 @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo536 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@537 @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@538 @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<539 469 540 470 mostlyclean-libtool: … … 787 717 @echo "int main() { return 0; }" > ${@} 788 718 789 .dummy_hackxx.cpp:790 @echo "int bar() { return 0; }" > ${@}791 792 719 concurrency : 793 720 @+${TEST_PY} --debug=${debug} --install=${installed} -Iconcurrent … … 797 724 # implicit rule so not all test require a rule 798 725 % : %.cfa $(CFACC) 799 $(CFATEST_STDOUT) 800 801 % : %.cpp 802 $(PRETTY_PATH) $(CXXCOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 803 804 #------------------------------------------------------------------------------ 805 # CUSTOM TARGET 806 #------------------------------------------------------------------------------ 807 typedefRedef-ERR1: typedefRedef.cfa $(CFACC) 808 $(CFATEST_STDOUT) -DERR1 809 810 alloc-ERROR: alloc.cfa $(CFACC) 811 $(CFATEST_STDOUT) -DERR1 812 813 nested-types-ERR1: nested-types.cfa $(CFACC) 814 $(CFATEST_STDOUT) -DERR1 815 816 nested-types-ERR2: nested-types.cfa $(CFACC) 817 $(CFATEST_STDOUT) -DERR2 818 819 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC) 820 $(CFATEST_STDOUT) -DERR1 821 822 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC) 823 $(CFATEST_STDOUT) -DERR2 824 825 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC) 826 $(CFATEST_STDOUT) -DERR1 827 828 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC) 829 $(CFATEST_STDOUT) -DERR1 726 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 727 728 declarationSpecifier: declarationSpecifier.cfa $(CFACC) 729 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 730 731 gccExtensions : gccExtensions.cfa $(CFACC) 732 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 733 734 extension : extension.cfa $(CFACC) 735 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 736 737 attributes : attributes.cfa $(CFACC) 738 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 739 740 functions: functions.cfa $(CFACC) 741 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 742 743 KRfunctions : KRfunctions.cfa $(CFACC) 744 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 745 746 sched-ext-parse : sched-ext-parse.c $(CFACC) 747 $(PRETTY_PATH) $(CFACOMPILE) -CFA -XCFA -p $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 748 749 gmp : gmp.cfa $(CFACC) 750 $(PRETTY_PATH) $(CFACOMPILE) -lgmp $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 830 751 831 752 #builtins 832 753 builtins/sync: builtins/sync.cfa $(CFACC) 833 $(CFATEST_STDERR) -fsyntax-only 754 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only 755 756 #------------------------------------------------------------------------------ 757 758 #To make errors path independent we need to cd into the correct directories 759 completeTypeError : completeTypeError.cfa $(CFACC) 760 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 761 762 typedefRedef-ERR1: typedefRedef.cfa $(CFACC) 763 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 764 765 alloc-ERROR: alloc.cfa $(CFACC) 766 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 767 768 fallthrough-ERROR: fallthrough.cfa $(CFACC) 769 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 770 771 nested-types-ERR1: nested-types.cfa $(CFACC) 772 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 773 774 nested-types-ERR2: nested-types.cfa $(CFACC) 775 $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 776 777 # Constructor/destructor tests 778 raii/dtor-early-exit-ERR1: raii/dtor-early-exit.cfa $(CFACC) 779 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 780 781 raii/dtor-early-exit-ERR2: raii/dtor-early-exit.cfa $(CFACC) 782 $(PRETTY_PATH) $(CFACOMPILE) -DERR2 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 783 784 raii/memberCtors-ERR1: raii/memberCtors.cfa $(CFACC) 785 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 786 787 raii/ctor-autogen-ERR1: raii/ctor-autogen.cfa $(CFACC) 788 $(PRETTY_PATH) $(CFACOMPILE) -DERR1 $(shell realpath --relative-to=${srcdir} ${<}) -o $(abspath ${@}) 834 789 835 790 # Warnings 836 791 warnings/self-assignment: warnings/self-assignment.cfa $(CFACC) 837 $( CFATEST_STDERR) -fsyntax-only792 $(PRETTY_PATH) $(CFACOMPILE) $(shell realpath --relative-to=${srcdir} ${<}) 2> $(abspath ${@}) -fsyntax-only 838 793 839 794 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
tests/completeTypeError.cfa
rf343c6b r69c37cc 5 5 forall(dtype T | sized(T)) void quux(T *); 6 6 7 struct A; // incomplete8 struct B {}; // complete7 struct A; // incomplete 8 struct B {}; // complete 9 9 10 10 int main() { 11 int * i;12 void * v;11 int *i; 12 void *v; 13 13 14 14 A * x; … … 19 19 // okay 20 20 *i; 21 * y;21 *x; // picks B 22 22 *z; 23 23 foo(i); … … 32 32 // bad 33 33 *v; 34 * x; // ambiguous34 *y; 35 35 foo(v); 36 36 baz(v); … … 52 52 void qux(T * y) { 53 53 // okay 54 *y;55 54 bar(y); 56 55 qux(y); … … 59 58 baz(y); 60 59 quux(y); 60 *y; 61 61 } 62 62 -
tests/concurrent/examples/boundedBufferEXT.cfa
rf343c6b r69c37cc 10 10 // Created On : Wed Apr 18 22:52:12 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:33201913 // Update Count : 1 212 // Last Modified On : Wed Feb 20 08:36:45 2019 13 // Update Count : 11 14 14 // 15 15 … … 122 122 // Local Variables: // 123 123 // tab-width: 4 // 124 // compile-command: "cfa boundedBufferEXT.c fa" //124 // compile-command: "cfa boundedBufferEXT.c" // 125 125 // End: // -
tests/concurrent/examples/boundedBufferINT.cfa
rf343c6b r69c37cc 10 10 // Created On : Mon Oct 30 12:45:13 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:52201913 // Update Count : 8 812 // Last Modified On : Wed Feb 20 08:37:24 2019 13 // Update Count : 87 14 14 // 15 15 … … 123 123 // Local Variables: // 124 124 // tab-width: 4 // 125 // compile-command: "cfa boundedBufferINT.c fa" //125 // compile-command: "cfa boundedBufferINT.c" // 126 126 // End: // -
tests/concurrent/examples/datingService.cfa
rf343c6b r69c37cc 10 10 // Created On : Mon Oct 30 12:56:20 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:39201913 // Update Count : 3 112 // Last Modified On : Wed Feb 20 08:37:12 2019 13 // Update Count : 30 14 14 // 15 15 … … 112 112 // Local Variables: // 113 113 // tab-width: 4 // 114 // compile-command: "cfa datingService.c fa" //114 // compile-command: "cfa datingService.c" // 115 115 // End: // -
tests/concurrent/examples/quickSort.cfa
rf343c6b r69c37cc 11 11 // Created On : Wed Dec 6 12:15:52 2017 12 12 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Fri Mar 22 13:42:01201914 // Update Count : 1 7013 // Last Modified On : Wed Feb 20 08:38:24 2019 14 // Update Count : 169 15 15 // 16 16 … … 180 180 // Local Variables: // 181 181 // tab-width: 4 // 182 // compile-command: "cfa quickSort.c fa" //182 // compile-command: "cfa quickSort.c" // 183 183 // End: // -
tests/concurrent/waitfor/parse2.cfa
rf343c6b r69c37cc 10 10 // Created On : Wed Aug 30 17:53:29 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:42:11 201913 // Update Count : 312 // Last Modified On : Wed Aug 30 17:55:17 2017 13 // Update Count : 2 14 14 // 15 15 … … 246 246 // Local Variables: // 247 247 // tab-width: 4 // 248 // compile-command: "cfa waitfor.c fa" //248 // compile-command: "cfa waitfor.c" // 249 249 // End: // -
tests/config.py.in
rf343c6b r69c37cc 1 #!/usr/bin/env python 31 #!/usr/bin/env python 2 2 # encoding: utf-8 3 3 """ -
tests/coroutine/.expect/fmtLines.txt
rf343c6b r69c37cc 16 16 difi ed B y : Pete r A. 17 17 Buh r// Last Mod ifie 18 d On : F ri M ar 2 2 1319 : 41: 03 2 019/ / Up date20 Cou nt : 3 3/ /#in18 d On : T ue D ec 1 1 23 19 :31: 12 2 018/ / Up date 20 Cou nt : 32/ /#in 21 21 clud e <f stre am.h fa># 22 22 incl ude <cor outi ne.h … … 76 76 th: 4 // // c ompi le-c 77 77 omma nd: "cfa fmt Line 78 s.c f a" / /// End: //78 s.c" /// / En d: / / -
tests/coroutine/.in/fmtLines.txt
rf343c6b r69c37cc 10 10 // Created On : Sun Sep 17 21:56:15 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:03 201913 // Update Count : 3 312 // Last Modified On : Tue Dec 11 23:31:12 2018 13 // Update Count : 32 14 14 // 15 15 … … 64 64 // Local Variables: // 65 65 // tab-width: 4 // 66 // compile-command: "cfa fmtLines.c fa" //66 // compile-command: "cfa fmtLines.c" // 67 67 // End: // -
tests/coroutine/fibonacci.cfa
rf343c6b r69c37cc 10 10 // Created On : Thu Jun 8 07:29:37 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:40:35 201913 // Update Count : 2 612 // Last Modified On : Tue Dec 11 21:57:33 2018 13 // Update Count : 25 14 14 // 15 15 … … 45 45 // Local Variables: // 46 46 // tab-width: 4 // 47 // compile-command: "cfa fibonacci.c fa" //47 // compile-command: "cfa fibonacci.c" // 48 48 // End: // -
tests/coroutine/fibonacci_1.cfa
rf343c6b r69c37cc 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // fibonacci_1.c fa -- 1-state finite-state machine: precomputed first two states returning f(n - 1)7 // fibonacci_1.c -- 1-state finite-state machine: precomputed first two states returning f(n - 2) 8 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Thu Apr 26 23:20:08 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Mar 21 08:10:45 201913 // Update Count : 2512 // Last Modified On : Tue Dec 11 21:57:54 2018 13 // Update Count : 14 14 14 // 15 15 … … 17 17 #include <coroutine.hfa> 18 18 19 coroutine Fibonacci { int fn1; }; // used for communication19 coroutine Fibonacci { int ret; }; // used for communication 20 20 21 21 void main( Fibonacci & fib ) with( fib ) { // called on first resume 22 int fn; 23 [fn1, fn] = [0, 1]; // precompute first two states 22 int fn, fn1 = 1, fn2 = 0; // precompute first two states 24 23 for () { 24 ret = fn2; 25 fn = fn1 + fn2; fn2 = fn1; fn1 = fn; // general case 25 26 suspend(); // restart last resume 26 [fn1, fn] = [fn, fn1 + fn]; // general case27 27 } // for 28 28 } … … 30 30 int next( Fibonacci & fib ) with( fib ) { 31 31 resume( fib ); // restart last suspend 32 return fn1;32 return ret; 33 33 } 34 34 … … 42 42 // Local Variables: // 43 43 // tab-width: 4 // 44 // compile-command: "cfa fibonacci_1.c fa" //44 // compile-command: "cfa fibonacci_1.c" // 45 45 // End: // -
tests/coroutine/fmtLines.cfa
rf343c6b r69c37cc 10 10 // Created On : Sun Sep 17 21:56:15 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:16 201913 // Update Count : 5 812 // Last Modified On : Sat Dec 22 18:27:00 2018 13 // Update Count : 57 14 14 // 15 15 … … 63 63 // Local Variables: // 64 64 // tab-width: 4 // 65 // compile-command: "cfa fmtLines.c fa" //65 // compile-command: "cfa fmtLines.c" // 66 66 // End: // -
tests/coroutine/pingpong.cfa
rf343c6b r69c37cc 10 10 // Created On : Wed Sep 20 11:55:23 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Mar 26 17:54:14 201913 // Update Count : 3512 // Last Modified On : Tue Dec 11 21:58:06 2018 13 // Update Count : 29 14 14 // 15 15 … … 20 20 const char * name; 21 21 /* const */ unsigned int N; 22 PingPong ∂22 PingPong * part; 23 23 }; 24 24 25 25 void ?{}( PingPong & this, const char * name, unsigned int N, PingPong & part ) { 26 this.[name, N] = [name, N]; &this.part = ∂ 26 (this.__cor){name}; 27 this.name = name; 28 this.N = N; 29 this.part = ∂ 27 30 } 28 31 void ?{}( PingPong & this, const char * name, unsigned int N ) { 29 this{ name, N, * 0p }; // call first constructor32 this{ name, N, *(PingPong *)0 }; 30 33 } 31 34 void cycle( PingPong & pingpong ) { … … 33 36 } 34 37 void partner( PingPong & this, PingPong & part ) { 35 &this.part = ∂38 this.part = ∂ 36 39 resume( this ); 37 40 } 38 void main( PingPong & pingpong ) with(pingpong) {// ping's starter ::main, pong's starter ping39 for ( N ) {// N ping-pongs40 sout | name;41 cycle( part );41 void main( PingPong & pingpong ) { // ping's starter ::main, pong's starter ping 42 for ( pingpong.N ) { // N ping-pongs 43 sout | pingpong.name; 44 cycle( *pingpong.part ); 42 45 } // for 43 46 } … … 50 53 // Local Variables: // 51 54 // tab-width: 4 // 52 // compile-command: "cfa pingpong.c fa" //55 // compile-command: "cfa pingpong.c" // 53 56 // End: // -
tests/coroutine/prodcons.cfa
rf343c6b r69c37cc 10 10 // Created On : Mon Sep 18 12:23:39 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:10 201913 // Update Count : 5 412 // Last Modified On : Wed Dec 12 23:04:49 2018 13 // Update Count : 53 14 14 // 15 15 … … 91 91 // Local Variables: // 92 92 // tab-width: 4 // 93 // compile-command: "cfa prodcons.c fa" //93 // compile-command: "cfa prodcons.c" // 94 94 // End: // -
tests/coroutine/runningTotal.cfa
rf343c6b r69c37cc 10 10 // Created On : Wed Dec 6 08:05:27 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:40:49 201913 // Update Count : 512 // Last Modified On : Tue Dec 11 21:59:00 2018 13 // Update Count : 4 14 14 // 15 15 … … 48 48 // Local Variables: // 49 49 // tab-width: 4 // 50 // compile-command: "cfa runningTotal.c fa" //50 // compile-command: "cfa runningTotal.c" // 51 51 // End: // -
tests/forall.cfa
rf343c6b r69c37cc 10 10 // Created On : Wed May 9 08:48:15 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Mar 19 08:29:38 201913 // Update Count : 3 212 // Last Modified On : Tue Nov 6 17:53:43 2018 13 // Update Count : 31 14 14 // 15 15 … … 53 53 right = temp; 54 54 } 55 56 void ?{}( int & c, zero_t ) { c = 0; } // not in prelude 55 57 56 58 trait sumable( otype T ) { -
tests/function-operator.cfa
rf343c6b r69c37cc 10 10 // Created On : Fri Aug 25 15:21:11 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Apr 11 18:27:45 201913 // Update Count : 1012 // Last Modified On : Tue Dec 4 21:37:09 2018 13 // Update Count : 9 14 14 // 15 15 … … 62 62 63 63 // test ?()(T, ...) -- ?() with function call-by-reference 64 forall(otype Generator, otype GenRet | { GenRet ?()(Generator &); }, dtype Iter, otype T | Iterator(Iter, T) | Assignable(T, GenRet))64 forall(otype Generator, otype GenRet | { GenRet ?()(Generator &); }, dtype Iter, otype T| Iterator(Iter, T) | Assignable(T, GenRet)) 65 65 void generate(Iter first, Iter last, Generator & gen) { 66 66 int i = 0; -
tests/io2.cfa
rf343c6b r69c37cc 10 10 // Created On : Wed Mar 2 16:56:02 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Apr 18 08:03:30 201913 // Update Count : 11 312 // Last Modified On : Fri Dec 21 08:20:14 2018 13 // Update Count : 112 14 14 // 15 15 … … 97 97 sout | 1 | sepOff | 2 | 3; // locally turn off implicit separator 98 98 sout | sepOn | sepOn | 1 | 2 | 3 | sepOn | sepOff | sepOn | '\n' | nonl; // no separator at start/end of line 99 sout | 1 | 2 | 3 | "\n\n" | sepOn | nonl; // no separator at start of next line99 sout | 1 | 2 | 3 | "\n\n" | sepOn | nonl; // no separator at start of next line 100 100 sout | 1 | 2 | 3; 101 101 sout | nl; -
tests/loopctrl.cfa
rf343c6b r69c37cc 10 10 // Created On : Wed Aug 8 18:32:59 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Apr 13 11:03:09201913 // Update Count : 10412 // Last Modified On : Thu Feb 21 08:54:47 2019 13 // Update Count : 86 14 14 // 15 15 … … 56 56 for ( ui; 10u -~= 2u ~ 2u ) { sout | ui; } sout | nl | nl; 57 57 58 // @ means do nothing59 for ( i; 1 ~ @ ) {60 if ( i > 10 ) break;61 sout | i;62 } sout | nl;63 for ( i; 10 -~ @ ) {64 if ( i < 0 ) break;65 sout | i;66 } sout | nl;67 58 for ( i; 2 ~ @ ~ 2 ) { 68 59 if ( i > 10 ) break; … … 103 94 for ( s; (S){10,10} -~ (S){0} ~ (S){1} ) { sout | s; } sout | nl; 104 95 for ( s; (S){10,10} -~= (S){0} ) { sout | s; } sout | nl; 105 for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { sout | s; } sout | nl | nl; 106 107 for ( i; 10 : j; -5 ~ @ ) { sout | i | j; } sout | nl; 108 for ( i; 10 : j; -5 -~ @ ) { sout | i | j; } sout | nl; 109 for ( i; 10 : j; -5 ~ @ ~ 2 ) { sout | i | j; } sout | nl; 110 for ( i; 10 : j; -5 -~ @ ~ 2 ) { sout | i | j; } sout | nl | nl; 111 112 for ( j; -5 ~ @ : i; 10 ) { sout | i | j; } sout | nl; 113 for ( j; -5 -~ @ : i; 10 ) { sout | i | j; } sout | nl; 114 for ( j; -5 ~ @ ~ 2 : i; 10 ) { sout | i | j; } sout | nl; 115 for ( j; -5 -~ @ ~ 2 : i; 10 ) { sout | i | j; } sout | nl | nl; 116 117 for ( j; -5 -~ @ ~ 2 : i; 10 : k; 1.5 ~ @ ) { sout | i | j | k; } sout | nl; 118 for ( j; -5 -~ @ ~ 2 : k; 1.5 ~ @ : i; 10 ) { sout | i | j | k; } sout | nl; 119 for ( k; 1.5 ~ @ : j; -5 -~ @ ~ 2 : i; 10 ) { sout | i | j | k; } sout | nl; 96 for ( s; (S){10,10} -~= (S){0} ~ (S){1} ) { sout | s; } sout | nl; 120 97 } 121 98 -
tests/math1.cfa
rf343c6b r69c37cc 10 10 // Created On : Fri Apr 22 14:59:21 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 25 22:56:47 201913 // Update Count : 10912 // Last Modified On : Wed Dec 12 16:28:49 2018 13 // Update Count : 89 14 14 // 15 15 … … 49 49 unsigned int e = 2; 50 50 b \= e; 51 sout | b | "\\" | e | "= " | b \ e; 52 sout | 'a' \ 3 | 2 \ 8 | 4 \ 3 | -4 \ 3 | 4 \ -3 | -4 \ -3; 53 sout | 4.0 \ -3 | -4.0 \ -3 | 4.0 \ 2.1 | (1.0f+2.0fi) \ (3.0f+2.0fi); 51 sout | "\\" | b | b \ e; 52 sout | "\\" | 'a' \ 3u | 2 \ 8u | 4 \ 3u | -4 \ 3u | nonl; 54 53 sout | 4 \ -3 | -4 \ -3 | 4.0 \ 2.1 | (1.0f+2.0fi) \ (3.0f+2.0fi); 55 56 struct S { int i; };57 double ?*?( double d, S s ) { return d * s.i; }58 double ?/?( double d, S s ) { return d / s.i; }59 S ?\?( S s, unsigned long y ) { return (S){ s.i \ y }; }60 ofstream & ?|?( ofstream & os, S s ) { return os | s.i; }61 void ?|?( ofstream & os, S s ) { (ofstream &)(os | s); nl( os ); }62 S s = { 4 };63 S x = s \ 2;64 sout | x;65 sout | s.i | s \ 2u;66 54 } // main 67 55 -
tests/pybin/settings.py
rf343c6b r69c37cc 1 from __future__ import print_function 2 1 3 import os 2 import subprocess3 4 import sys 4 from .import tools5 import tools 5 6 6 7 try : … … 38 39 def __init__(self, arch): 39 40 try: 40 canonical_host = Architecture.make _canonical( config.HOSTARCH )41 canonical_host = Architecture.makeCanonical( config.HOSTARCH ) 41 42 except KeyError: 42 43 print("Unkown host architecture %s" % config.HOSTARCH, file=sys.stderr) … … 45 46 if arch: 46 47 try: 47 arch = Architecture.make _canonical( arch )48 arch = Architecture.makeCanonical( arch ) 48 49 except KeyError: 49 50 print("Unkown architecture %s" % arch, file=sys.stderr) … … 76 77 77 78 @classmethod 78 def make _canonical(_, arch):79 def makeCanonical(_, arch): 79 80 return Architecture.KnownArchitectures[arch] 80 81 … … 83 84 def __init__(self, value): 84 85 self.string = "debug" if value else "no debug" 85 self.flags = """DEBUG_FLAGS= %s""" % ("-debug -O0" if value else "-nodebug -O2")86 self.flags = """DEBUG_FLAGS="%s" """ % ("-debug -O0" if value else "-nodebug -O2") 86 87 87 88 class Install: 88 89 def __init__(self, value): 89 90 self.string = "installed" if value else "in-tree" 90 self.flags = """INSTALL_FLAGS= %s""" % ("" if value else "-in-tree")91 self.flags = """INSTALL_FLAGS="%s" """ % ("" if value else "-in-tree") 91 92 92 93 class Timeouts: … … 111 112 global install 112 113 global timeout 113 global output_width114 114 115 dry_run = options.dry_run 116 generating = options.regenerate_expected 117 make = ['make'] 118 debug = Debug(options.debug) 119 install = Install(options.install) 120 arch = Architecture(options.arch) 121 timeout = Timeouts(options.timeout, options.global_timeout) 122 output_width = 24 115 dry_run = options.dry_run 116 generating = options.regenerate_expected 117 make = 'make' 118 debug = Debug(options.debug) 119 install = Install(options.install) 120 arch = Architecture(options.arch) 121 timeout = Timeouts(options.timeout, options.global_timeout) 123 122 124 123 125 def update _make_cmd(force, jobs):124 def updateMakeCmd(force, jobs): 126 125 global make 127 126 128 make = ['make'] if not force else ['make', "-j%i" % jobs]127 make = "make" if not force else ("make -j%i" % jobs) 129 128 130 129 def validate(): 131 130 errf = os.path.join(BUILDDIR, ".validate.err") 132 make_ret, out = tools.make( ".validate", error_file = errf, output=subprocess.DEVNULL, error=subprocess.DEVNULL)131 make_ret, _ = tools.make( ".validate", error_file = errf, redirects = "2> /dev/null 1> /dev/null", ) 133 132 if make_ret != 0: 134 133 with open (errf, "r") as myfile: … … 140 139 141 140 tools.rm(errf) 142 143 def prep_output(tests):144 global output_width145 output_width = max(map(lambda t: len(t.target()), tests)) -
tests/pybin/test_run.py
rf343c6b r69c37cc 4 4 5 5 import pybin.settings 6 import datetime 7 8 from string import Template 9 10 class DeltaTemplate(Template): 11 delimiter = "%" 12 13 def strfdelta(tdelta, fmt): 14 d["H"], rem = divmod(tdelta.seconds, 3600) 15 d["M"], d["S"] = divmod(rem, 60) 16 t = DeltaTemplate(fmt) 17 return t.substitute(**d) 6 18 7 19 # Test class that defines what a test is -
tests/pybin/tools.py
rf343c6b r69c37cc 1 from __future__ import print_function 2 1 3 import __main__ 2 4 import argparse 3 import contextlib4 5 import fileinput 5 6 import multiprocessing … … 9 10 import signal 10 11 import stat 11 import subprocess12 12 import sys 13 import tempfile14 13 import time 15 import types16 14 17 15 from pybin import settings 16 from subprocess import Popen, PIPE, STDOUT 18 17 19 18 ################################################################################ … … 22 21 23 22 # helper functions to run terminal commands 24 def sh(*cmd, timeout = False, output = None, input = None, error = subprocess.STDOUT): 25 cmd = list(cmd) 23 def sh(cmd, print2stdout = True, input = None): 24 # add input redirection if needed 25 if input and os.path.isfile(input): 26 cmd += " < %s" % input 26 27 27 28 # if this is a dry_run, only print the commands that would be ran 28 29 if settings.dry_run : 29 cmd = "{} cmd: {}".format(os.getcwd(), ' '.join(cmd)) 30 if output and not isinstance(output, int): 31 cmd += " > " 32 cmd += output 33 34 if error and not isinstance(error, int): 35 cmd += " 2> " 36 cmd += error 37 38 if input and not isinstance(input, int) and os.path.isfile(input): 39 cmd += " < " 40 cmd += input 41 42 print(cmd) 30 print("cmd: %s" % cmd) 43 31 return 0, None 44 32 45 with contextlib.ExitStack() as onexit: 46 # add input redirection if needed 47 input = openfd(input, 'r', onexit, True) 48 49 # add output redirection if needed 50 output = openfd(output, 'w', onexit, False) 51 52 # add error redirection if needed 53 error = openfd(error, 'w', onexit, False) 54 55 # run the desired command 56 try: 57 proc = subprocess.run( 58 cmd, 59 stdin =input, 60 stdout=output, 61 stderr=error, 62 timeout=settings.timeout.single if timeout else None 63 ) 64 return proc.returncode, proc.stdout.decode("utf-8") if proc.stdout else None 65 except subprocess.TimeoutExpired: 66 return 124, str(None) 33 # otherwise create a pipe and run the desired command 34 else : 35 proc = Popen(cmd, stdout=None if print2stdout else PIPE, stderr=STDOUT, shell=True) 36 out, err = proc.communicate() 37 return proc.returncode, out 67 38 68 39 def is_ascii(fname): … … 74 45 return False 75 46 76 code, out = sh("file %s" % fname, output=subprocess.PIPE)47 code, out = sh("file %s" % fname, print2stdout = False) 77 48 if code != 0: 78 49 return False … … 84 55 85 56 return match.group(1).startswith("ASCII text") 86 87 def is_exe(fname):88 return os.path.isfile(fname) and os.access(fname, os.X_OK)89 90 def openfd(file, mode, exitstack, checkfile):91 if not file:92 return file93 94 if isinstance(file, int):95 return file96 97 if checkfile and not os.path.isfile(file):98 return None99 100 file = open(file, mode)101 exitstack.push(file)102 return file103 57 104 58 # Remove 1 or more files silently 105 59 def rm( files ): 106 if isinstance(files, str ): files = [ files ] 107 for file in files: 108 sh( 'rm', '-f', file, output=subprocess.DEVNULL, error=subprocess.DEVNULL ) 60 if isinstance( files, basestring ): 61 sh("rm -f %s > /dev/null 2>&1" % files ) 62 else: 63 for file in files: 64 sh("rm -f %s > /dev/null 2>&1" % file ) 109 65 110 66 # Create 1 or more directory 111 67 def mkdir( files ): 112 if isinstance( files, str ): files = [ files ]113 for file in files:114 p = os.path.normpath( file )115 d = os.path.dirname ( p )116 sh( 'mkdir', '-p', d, output=subprocess.DEVNULL, error=subprocess.DEVNULL)68 if isinstance( files, basestring ): 69 sh("mkdir -p %s" % os.path.dirname(files) ) 70 else: 71 for file in files: 72 sh("mkdir -p %s" % os.path.dirname(file) ) 117 73 118 74 … … 124 80 # diff two files 125 81 def diff( lhs, rhs ): 82 # diff the output of the files 83 diff_cmd = ("diff --text " 84 # "--ignore-all-space " 85 # "--ignore-blank-lines " 86 "--old-group-format='\t\tmissing lines :\n" 87 "%%<' \\\n" 88 "--new-group-format='\t\tnew lines :\n" 89 "%%>' \\\n" 90 "--unchanged-group-format='%%=' \\" 91 "--changed-group-format='\t\texpected :\n" 92 "%%<" 93 "\t\tgot :\n" 94 "%%>\n' \\\n" 95 "--new-line-format='\t\t%%dn\t%%L' \\\n" 96 "--old-line-format='\t\t%%dn\t%%L' \\\n" 97 "--unchanged-line-format='' \\\n" 98 "%s %s") 99 126 100 # fetch return code and error from the diff command 127 return sh( 128 '''diff''', 129 '''--text''', 130 '''--old-group-format=\t\tmissing lines :\n%<''', 131 '''--new-line-format=\t\t%dn\t%L''', 132 '''--new-group-format=\t\tnew lines : \n%>''', 133 '''--old-line-format=\t\t%dn\t%L''', 134 '''--unchanged-group-format=%=''', 135 '''--changed-group-format=\t\texpected :\n%<\t\tgot :\n%>''', 136 '''--unchanged-line-format=''', 137 lhs, 138 rhs, 139 output=subprocess.PIPE 140 ) 101 return sh(diff_cmd % (lhs, rhs), False) 141 102 142 103 # call make 143 def make(target, *, flags = '', output = None, error = None, error_file = None, silent = False):144 test_param = """test="%s" """ % (error_file) if error_file else None145 cmd = [146 *settings.make,147 '-s' if silent else None,104 def make(target, flags = '', redirects = '', error_file = None, silent = False): 105 test_param = """test="%s" """ % (error_file) if error_file else '' 106 cmd = ' '.join([ 107 settings.make, 108 '-s' if silent else '', 148 109 test_param, 149 110 settings.arch.flags, … … 151 112 settings.install.flags, 152 113 flags, 153 target 154 ]155 cmd = [s for s in cmd if s]156 return sh( *cmd, output=output, error=error)114 target, 115 redirects 116 ]) 117 return sh(cmd) 157 118 158 119 def which(program): 120 import os 121 def is_exe(fpath): 122 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 123 159 124 fpath, fname = os.path.split(program) 160 125 if fpath: … … 169 134 return None 170 135 171 @contextlib.contextmanager 172 def tempdir(): 173 cwd = os.getcwd() 174 with tempfile.TemporaryDirectory() as temp: 175 os.chdir(temp) 176 try: 177 yield temp 178 finally: 179 os.chdir(cwd) 136 def run(exe, output, input): 137 ret, _ = sh("timeout %d %s > %s 2>&1" % (settings.timeout.single, exe, output), input = input) 138 return ret 180 139 181 140 ################################################################################ … … 184 143 # move a file 185 144 def mv(source, dest): 186 ret, _ = sh("mv ", source, dest)145 ret, _ = sh("mv %s %s" % (source, dest)) 187 146 return ret 188 147 189 148 # cat one file into the other 190 149 def cat(source, dest): 191 ret, _ = sh("cat ", source, output=dest)150 ret, _ = sh("cat %s > %s" % (source, dest)) 192 151 return ret 193 152 … … 204 163 205 164 # helper function to check if a files contains only a specific string 206 def file _contains_only(file, text) :165 def fileContainsOnly(file, text) : 207 166 with open(file) as f: 208 167 ff = f.read().strip() 209 168 result = ff == text.strip() 210 169 211 return result 170 return result; 171 172 # check whether or not a file is executable 173 def fileIsExecutable(file) : 174 try : 175 fileinfo = os.stat(file) 176 return bool(fileinfo.st_mode & stat.S_IXUSR) 177 except Exception as inst: 178 print(type(inst)) # the exception instance 179 print(inst.args) # arguments stored in .args 180 print(inst) 181 return False 212 182 213 183 # transform path to canonical form 214 def canonical _path(path):184 def canonicalPath(path): 215 185 abspath = os.path.abspath(__main__.__file__) 216 186 dname = os.path.dirname(abspath) … … 218 188 219 189 # compare path even if form is different 220 def path _cmp(lhs, rhs):221 return canonical _path( lhs ) == canonical_path( rhs )190 def pathCmp(lhs, rhs): 191 return canonicalPath( lhs ) == canonicalPath( rhs ) 222 192 223 193 # walk all files in a path 224 def path_walk( op ): 225 dname = settings.SRCDIR 226 for dirname, _, names in os.walk(dname): 194 def pathWalk( op ): 195 def step(_, dirname, names): 227 196 for name in names: 228 197 path = os.path.join(dirname, name) 229 198 op( path ) 230 199 200 # Start the walk 201 dname = settings.SRCDIR 202 os.path.walk(dname, step, '') 203 231 204 ################################################################################ 232 205 # system 233 206 ################################################################################ 234 207 # count number of jobs to create 235 def job _count( options, tests ):208 def jobCount( options, tests ): 236 209 # check if the user already passed in a number of jobs for multi-threading 237 210 if not options.jobs: … … 255 228 return min( options.jobs, len(tests) ), force 256 229 230 # setup a proper processor pool with correct signal handling 231 def setupPool(jobs): 232 original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) 233 pool = multiprocessing.Pool(jobs) 234 signal.signal(signal.SIGINT, original_sigint_handler) 235 236 return pool 237 238 # handle signals in scope 239 class SignalHandling(): 240 def __enter__(self): 241 # enable signal handling 242 signal.signal(signal.SIGINT, signal.SIG_DFL) 243 244 def __exit__(self, type, value, traceback): 245 # disable signal handling 246 signal.signal(signal.SIGINT, signal.SIG_IGN) 247 248 257 249 # enable core dumps for all the test children 258 250 resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY)) … … 269 261 return False 270 262 raise argparse.ArgumentTypeError(msg) 263 return False 271 264 272 265 def fancy_print(text): 273 266 column = which('column') 274 267 if column: 275 subprocess.run(column, input=bytes(text + "\n", "UTF-8")) 268 cmd = "%s 2> /dev/null" % column 269 proc = Popen(cmd, stdin=PIPE, stderr=None, shell=True) 270 proc.communicate(input=text + "\n") 276 271 else: 277 272 print(text) 278 273 279 274 280 def core_info(path): 281 if not os.path.isfile(path): 282 return 1, "ERR Executable path is wrong" 283 275 def coreInfo(path): 284 276 cmd = os.path.join(settings.SRCDIR, "pybin/print-core.gdb") 285 277 if not os.path.isfile(cmd): 286 278 return 1, "ERR Printing format for core dumps not found" 287 279 288 core = os.path.join(os.getcwd(), "core" ) 280 dname = os.path.dirname(path) 281 core = os.path.join(dname, "core" ) 282 if not os.path.isfile(path): 283 return 1, "ERR Executable path is wrong" 289 284 290 285 if not os.path.isfile(core): 291 286 return 1, "ERR No core dump" 292 287 293 return sh( 'gdb', '-n', path, core, '-batch', '-x', cmd, output=subprocess.PIPE)288 return sh("gdb -n %s %s -batch -x %s" % (path, core, cmd), print2stdout=False) 294 289 295 290 class Timed: -
tests/raii/init_once.cfa
rf343c6b r69c37cc 10 10 // Created On : Tue Jun 14 15:43:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 22 13:41:26 201913 // Update Count : 412 // Last Modified On : Sat Jul 9 11:30:29 2016 13 // Update Count : 3 14 14 // 15 15 … … 192 192 // Local Variables: // 193 193 // tab-width: 4 // 194 // compile-command: "cfa init_once.c fa" //194 // compile-command: "cfa init_once.c" // 195 195 // End: // -
tests/rational.cfa
rf343c6b r69c37cc 10 10 // Created On : Mon Mar 28 08:43:12 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Mar 27 07:37:17 201913 // Update Count : 8012 // Last Modified On : Tue Dec 4 21:46:42 2018 13 // Update Count : 69 14 14 // 15 15 … … 19 19 #include <fstream.hfa> 20 20 21 // UNNECESSARY, FIX ME 22 void ?{}( int & this ) { this = 0; } 23 void ?{}( int & this, zero_t ) { this = 0; } 24 void ?{}( int & this, one_t ) { this = 1; } 21 25 double convert( int i ) { return (double)i; } 22 26 int convert( double d ) { return (int)d; } … … 54 58 sout | a * b; 55 59 sout | a / b; 56 // sout | a \ 2 | b \ 2; // FIX ME57 // sout | a \ -2 | b \ -2;58 60 59 61 sout | "conversion"; -
tests/test.py
rf343c6b r69c37cc 1 #!/usr/bin/python3 1 #!/usr/bin/python 2 from __future__ import print_function 2 3 3 4 from pybin.tools import * … … 8 9 import re 9 10 import sys 10 import tempfile11 11 import time 12 12 … … 15 15 ################################################################################ 16 16 17 def find _tests():17 def findTests(): 18 18 expected = [] 19 19 20 def match _test(path):20 def matchTest(path): 21 21 match = re.search("^%s\/([\w\/\-_]*).expect\/([\w\-_]+)(\.[\w\-_]+)?\.txt$" % settings.SRCDIR, path) 22 22 if match : … … 28 28 expected.append(test) 29 29 30 path _walk( match_test )30 pathWalk( matchTest ) 31 31 32 32 return expected 33 33 34 34 # reads the directory ./.expect and indentifies the tests 35 def list _tests( includes, excludes ):35 def listTests( includes, excludes ): 36 36 # tests directly in the .expect folder will always be processed 37 test_list = find _tests()37 test_list = findTests() 38 38 39 39 # if we have a limited number of includes, filter by them … … 52 52 53 53 # from the found tests, filter all the valid tests/desired tests 54 def valid _tests( options ):54 def validTests( options ): 55 55 tests = [] 56 56 … … 59 59 if options.regenerate_expected : 60 60 for testname in options.tests : 61 testname = canonical _path( testname )61 testname = canonicalPath( testname ) 62 62 if Test.valid_name(testname): 63 found = [test for test in all _tests if canonical_path( test.target() ) == testname]63 found = [test for test in allTests if canonicalPath( test.target() ) == testname] 64 64 tests.append( found[0] if len(found) == 1 else Test.from_target(testname) ) 65 65 else : … … 69 69 # otherwise we only need to validate that all tests are present in the complete list 70 70 for testname in options.tests: 71 test = [t for t in all _tests if path_cmp( t.target(), testname )]71 test = [t for t in allTests if pathCmp( t.target(), testname )] 72 72 73 73 if test : … … 79 79 80 80 # parses the option 81 def parse_args():81 def getOptions(): 82 82 # create a parser with the arguments for the tests script 83 83 parser = argparse.ArgumentParser(description='Script which runs cforall tests') … … 102 102 print('ERROR: invalid arguments', file=sys.stderr) 103 103 parser.print_help(sys.stderr) 104 sys.exit(1)104 sys.exit(1) 105 105 106 106 # script must have at least some tests to run or be listing … … 112 112 # check that exactly one of the booleans is set to true 113 113 if not sum( (listing, all_tests, some_tests, some_dirs) ) > 0 : 114 print(' ''ERROR: must have option '--all', '--list', '--include', '-I' or non-empty test list''', file=sys.stderr)114 print('ERROR: must have option \'--all\', \'--list\', \'--include\', \'-I\' or non-empty test list', file=sys.stderr) 115 115 parser.print_help() 116 116 sys.exit(1) … … 124 124 return val == 0 or settings.dry_run 125 125 126 def no_rule(file, target): 127 return not settings.dry_run and file_contains_only(file, "make: *** No rule to make target `%s'. Stop." % target) 126 def isExe(file): 127 return settings.dry_run or fileIsExecutable(file) 128 129 def noRule(file, target): 130 return not settings.dry_run and fileContainsOnly(file, "make: *** No rule to make target `%s'. Stop." % target) 128 131 129 132 # logic to run a single test and return the result (No handling of printing or other test framework logic) … … 142 145 # build, skipping to next test on error 143 146 with Timed() as comp_dur: 144 make_ret, _ = make( test.target(), output=subprocess.DEVNULL, error=out_file, error_file = err_file ) 145 147 make_ret, _ = make( test.target(), redirects = ("2> %s 1> /dev/null" % out_file), error_file = err_file ) 148 149 # if the make command succeds continue otherwise skip to diff 146 150 run_dur = None 147 # run everything in a temp directory to make sure core file are handled properly 148 with tempdir(): 149 # if the make command succeds continue otherwise skip to diff 150 if success(make_ret): 151 with Timed() as run_dur: 152 if settings.dry_run or is_exe(exe_file): 153 # run test 154 retcode, _ = sh(exe_file, output=out_file, input=in_file, timeout=True) 155 else : 156 # simply cat the result into the output 157 retcode = cat(exe_file, out_file) 158 else: 159 retcode = mv(err_file, out_file) 160 161 if success(retcode): 162 if settings.generating : 163 # if we are ounly generating the output we still need to check that the test actually exists 164 if no_rule(out_file, test.target()) : 165 retcode = 1 166 error = "\t\tNo make target for test %s!" % test.target() 167 rm(out_file) 168 else: 169 error = None 151 if success(make_ret): 152 with Timed() as run_dur: 153 if isExe(exe_file): 154 # run test 155 retcode = run(exe_file, out_file, in_file) 170 156 else : 171 # fetch return code and error from the diff command 172 retcode, error = diff(cmp_file, out_file) 173 174 else: 175 with open (out_file, "r") as myfile: 176 error = myfile.read() 177 178 ret, info = core_info(exe_file) 179 error = error + info if error else info 157 # simply cat the result into the output 158 retcode = cat(exe_file, out_file) 159 else: 160 retcode = mv(err_file, out_file) 161 162 if success(retcode): 163 if settings.generating : 164 # if we are ounly generating the output we still need to check that the test actually exists 165 if noRule(out_file, test.target()) : 166 retcode = 1 167 error = "\t\tNo make target for test %s!" % test.target() 168 rm(out_file) 169 else: 170 error = None 171 else : 172 # fetch return code and error from the diff command 173 retcode, error = diff(cmp_file, out_file) 174 175 else: 176 with open (out_file, "r") as myfile: 177 error = myfile.read() 178 179 ret, info = coreInfo(exe_file) 180 error = error + info 180 181 181 182 … … 188 189 # run a single test and handle the errors, outputs, printing, exception handling, etc. 189 190 def run_test_worker(t) : 190 try : 191 192 with SignalHandling(): 191 193 # print formated name 192 name_txt = '{0:{width}} '.format(t.target(), width=settings.output_width)194 name_txt = "%24s " % t.name 193 195 194 196 retcode, error, duration = run_single_test(t) … … 198 200 199 201 #print result with error if needed 200 text = '\t' +name_txt + result_txt202 text = name_txt + result_txt 201 203 out = sys.stdout 202 204 if error : 203 text = text + '\n'+ error205 text = text + "\n" + error 204 206 out = sys.stderr 205 207 … … 208 210 sys.stderr.flush() 209 211 210 return retcode != TestResult.SUCCESS 211 except KeyboardInterrupt: 212 False 212 return retcode != TestResult.SUCCESS 213 213 214 214 # run the given list of tests with the given parameters 215 215 def run_tests(tests, jobs) : 216 216 # clean the sandbox from previous commands 217 make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL)217 make('clean', redirects = '> /dev/null 2>&1') 218 218 219 219 # create the executor for our jobs and handle the signal properly 220 pool = multiprocessing.Pool(jobs)220 pool = setupPool(jobs) 221 221 222 222 # for each test to run … … 233 233 234 234 # clean the workspace 235 make('clean', output=subprocess.DEVNULL, error=subprocess.DEVNULL)235 make('clean', redirects = '> /dev/null 2>&1') 236 236 237 237 for failed in results: … … 248 248 249 249 # parse the command line arguments 250 options = parse_args()250 options = getOptions() 251 251 252 252 # init global settings … … 254 254 255 255 # fetch the liest of all valid tests 256 all _tests = list_tests( options.include, options.exclude )256 allTests = listTests( options.include, options.exclude ) 257 257 258 258 259 259 # if user wants all tests than no other treatement of the test list is required 260 260 if options.all or options.list or options.list_comp or options.include : 261 tests = all _tests261 tests = allTests 262 262 263 263 #otherwise we need to validate that the test list that was entered is valid 264 264 else : 265 tests = valid _tests( options )265 tests = validTests( options ) 266 266 267 267 # make sure we have at least some test to run … … 281 281 elif options.list : 282 282 print("Listing for %s:%s"% (settings.arch.string, settings.debug.string)) 283 fancy_print("\n".join(map(lambda t: t.toString(), tests)))283 fancy_print("\n".join(map(lambda t: "%s" % (t.toString()), tests))) 284 284 285 285 else : 286 286 # check the build configuration works 287 settings.prep_output(tests)288 287 settings.validate() 289 288 290 options.jobs, forceJobs = job_count( options, tests ) 291 settings.update_make_cmd(forceJobs, options.jobs) 292 293 print('%s %i tests on %i cores (%s:%s)' % ( 294 'Regenerating' if settings.generating else 'Running', 295 len(tests), 296 options.jobs, 289 options.jobs, forceJobs = jobCount( options, tests ) 290 settings.updateMakeCmd(forceJobs, options.jobs) 291 292 print('%s (%s:%s) on %i cores' % ( 293 'Regenerate tests' if settings.generating else 'Running', 297 294 settings.arch.string, 298 settings.debug.string 295 settings.debug.string, 296 options.jobs 299 297 )) 300 298
Note:
See TracChangeset
for help on using the changeset viewer.