├── .github └── workflows │ └── test-arch.yaml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── Taskfile.yaml ├── architecture.md ├── architecture_tldr.jpg ├── build.sh ├── compile.sh ├── conanfile.txt ├── cpp ├── Makefile ├── deps.cpp ├── predefined.hpp ├── test-a.cpp ├── test-b.hpp └── test.cpp ├── devnotes.org ├── hcparse.nimble ├── index.rst ├── it_works.jpg ├── old ├── src │ ├── .gitignore │ ├── FindNIM.cmake │ ├── hcparse.nim │ ├── hcparse │ │ ├── codegen │ │ │ └── hc_codegen.nim │ │ ├── hc_impls.nim │ │ ├── hc_irgen.nim │ │ ├── hc_parsefront.nim │ │ ├── hc_save.nim │ │ ├── hc_typeconv.nim │ │ ├── hcparse_cli.nim │ │ ├── post │ │ │ ├── closure_override.nim │ │ │ └── closure_override.rst │ │ ├── processor │ │ │ ├── hc_grouping.nim │ │ │ ├── hc_postprocess.nim │ │ │ ├── wrap_icpp.nim │ │ │ └── wrap_store.nim │ │ ├── read_boost_wave │ │ │ ├── .fdignore │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── boost_wave.cpp │ │ │ ├── boost_wave.hpp │ │ │ ├── boost_wave.nim │ │ │ ├── boost_wave_global.hpp │ │ │ ├── boost_wave_test.cpp │ │ │ ├── boost_wave_tokens.nim │ │ │ ├── boost_wave_wrap.nim │ │ │ ├── conanfile.txt │ │ │ ├── hc_wavereader.nim │ │ │ ├── nim.cfg │ │ │ ├── scratch.cpp │ │ │ ├── wave_c_api.h │ │ │ └── xmake.lua │ │ ├── read_deps │ │ │ └── conan.nim │ │ ├── read_doxygen │ │ │ ├── dox_codegen.nim │ │ │ ├── dox_compound.nim │ │ │ ├── dox_compound.xsd │ │ │ ├── dox_index.nim │ │ │ ├── dox_index.xsd │ │ │ └── dox_xml.nim │ │ ├── read_libclang │ │ │ ├── cxcommon.nim │ │ │ ├── cxtypes.nim │ │ │ ├── cxvisitors.nim │ │ │ ├── hc_clangreader.nim │ │ │ ├── hc_depresolve.nim │ │ │ ├── hc_genhelper.nim │ │ │ ├── hc_types.nim │ │ │ ├── hc_visitors.nim │ │ │ ├── header.hpp │ │ │ ├── libclang_extensions.cpp │ │ │ ├── libclang_extensions.nim │ │ │ ├── libclang_wrap.nim │ │ │ └── readme.org │ │ └── read_tree_sitter │ │ │ ├── hc_tsconvert.nim │ │ │ └── hc_tsreader.nim │ ├── nim.cfg │ └── test.cpp ├── tests │ ├── .gdbinit │ ├── .gitignore │ ├── __tQWindow.nim │ ├── ccode.yaml │ ├── files │ │ ├── libgit_test │ │ │ ├── stdcopy.h │ │ │ └── types.h │ │ ├── wavereader_main.h │ │ └── wavereader_subcontext.h │ ├── header.hpp │ ├── incpp.cpp │ ├── nim.cfg │ ├── runall.nim │ ├── sfinae_header.hpp │ ├── tBoostWaveExecute.nim │ ├── tBoostWaveGenerate.nim │ ├── tBoostWaveReader.nim │ ├── tConvertBitsTs.nim │ ├── tConvertLibs.nim │ ├── tHcparseCli.nim │ ├── tLibclangBasic.nim │ ├── tMergeGroups.nim │ ├── tReadConan.nim │ ├── tWip.nim │ ├── wip_in.cpp │ └── wip_in.hpp └── wip │ ├── .gitignore │ ├── build.nims │ ├── build.sh │ ├── fixshit.sh │ ├── libclang-2.cpp │ ├── libclang-3.cpp │ ├── libclang_2.nim │ └── nim.cfg ├── readme.org ├── src ├── embedded_includes.hpp.in ├── main.cpp ├── projectmanager.cpp ├── projectmanager.hpp └── stringbuilder.hpp └── todo.org /.github/workflows/test-arch.yaml: -------------------------------------------------------------------------------- 1 | name: "CI arch" 2 | on: [push] 3 | jobs: 4 | compile: 5 | # !contains(github.event.head_commit.message, 'SKIP') 6 | if: false 7 | runs-on: ubuntu-latest 8 | container: archlinux:latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - run: pacman --noconfirm -Syu 12 | - run: | 13 | pacman --noconfirm -S \ 14 | gcc \ 15 | tree-sitter \ 16 | clang \ 17 | python-pip \ 18 | wget \ 19 | git \ 20 | cmake \ 21 | make \ 22 | graphviz 23 | 24 | - name: "Install conan" 25 | run: pip install conan 26 | - name: "Install boost wave reader dependencies and build library" 27 | run: | 28 | cd src/hcparse/read_boost_wave 29 | conan install . --build=missing --settings compiler.libcxx="libstdc++11" 30 | mkdir build 31 | cd build 32 | cmake .. 33 | make -j8 34 | cd .. 35 | 36 | - name: "Install nim" 37 | run: | 38 | wget https://nim-lang.org/choosenim/init.sh 39 | chmod +x init.sh 40 | sh init.sh -y 41 | 42 | - name: "Install nim dependencies" 43 | run: | 44 | export PATH=$HOME/.nimble/bin:$PATH 45 | echo $PATH 46 | nimble -y develop 47 | 48 | - name: "Execute tests and build documentation" 49 | shell: bash 50 | run: | 51 | export PATH=$HOME/.nimble/bin:$PATH 52 | echo $PATH 53 | 54 | # Setup paths to the wavereader library and llvm installation 55 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH$(pwd)/lib 56 | export LIBRARY_PATH=$LIBRARY_PATH:$(pwd)/lib 57 | 58 | echo $LD_LIBRARY_PATH 59 | echo $LIBRARY_PATH 60 | 61 | # Setup paths for conan dependencies 62 | cat src/hcparse/read_boost_wave/activate_run.sh 63 | source src/hcparse/read_boost_wave/activate_run.sh 64 | 65 | # Add path to the current nim compiler installation 66 | echo '--path="$nim"' > nim.cfg 67 | cat nim.cfg 68 | 69 | # Run tests 70 | nim r tests/runall.nim test $(pwd)/hcparse.nimble 71 | 72 | # Run documentation generation 73 | nim r tests/runall.nim doc $(pwd)/hcparse.nimble --ignore="**/dox*.nim" 74 | 75 | - name: "Deploy documentation" 76 | uses: crazy-max/ghaction-github-pages@v1 77 | with: 78 | build_dir: htmldocs 79 | env: 80 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 81 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nimcache/ 2 | **/*.bin 3 | **/*.png 4 | **/*.dot 5 | **/*.tmp.* 6 | **/*.tmp 7 | **/*.html 8 | **/*.css 9 | 10 | /scripts/.circuit 11 | /scripts/.latex 12 | callgrind.out.* 13 | nimdoc.cfg 14 | wrap-examples.rst 15 | **/*.out 16 | **/*cache* 17 | 18 | 19 | # Created by https://www.toptal.com/developers/gitignore/api/c++ 20 | # Edit at https://www.toptal.com/developers/gitignore?templates=c++ 21 | 22 | ### C++ ### 23 | # Prerequisites 24 | *.d 25 | 26 | # Compiled Object files 27 | *.slo 28 | *.lo 29 | *.o 30 | *.obj 31 | 32 | # Precompiled Headers 33 | *.gch 34 | *.pch 35 | 36 | # Compiled Dynamic libraries 37 | *.so 38 | *.dylib 39 | *.dll 40 | 41 | # Fortran module files 42 | *.mod 43 | *.smod 44 | 45 | # Compiled Static libraries 46 | *.lai 47 | *.la 48 | *.a 49 | *.lib 50 | 51 | # Executables 52 | *.exe 53 | *.out 54 | *.app 55 | 56 | # End of https://www.toptal.com/developers/gitignore/api/c++ 57 | 58 | **/.gdb_history 59 | *.code-workspace 60 | 61 | 62 | **/.xmake/* 63 | htmldocs/* 64 | 65 | perf.* 66 | **/TAGS 67 | bin 68 | build 69 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/hcxx_common"] 2 | path = external/hcxx_common 3 | url = ../hcxx_common 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(hcparse) 3 | set(CMAKE_CXX_COMPILER clang++) 4 | 5 | find_package(LLVM REQUIRED CONFIG) 6 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION} in ${LLVM_INSTALL_PREFIX}") 7 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 8 | find_package(Clang REQUIRED CONFIG HINTS 9 | "${LLVM_INSTALL_PREFIX}/lib/cmake/clang") 10 | message(STATUS "Found Clang in ${CLANG_INSTALL_PREFIX}") 11 | 12 | file(GLOB SRC_FILES ${CMAKE_SOURCE_DIR}/src/*.cpp) 13 | 14 | add_executable( 15 | hcparse 16 | # Regular sources 17 | ${SRC_FILES} 18 | # `configure_file` projects 19 | ${CMAKE_CURRENT_BINARY_DIR}/projectmanager_systemprojects.cpp) 20 | 21 | # Add include directories in order for `configure_file`-based `.cpp` files to 22 | # work properly. 23 | target_include_directories(hcparse PRIVATE "${CMAKE_CURRENT_LIST_DIR}/src") 24 | 25 | target_link_libraries( 26 | hcparse 27 | PRIVATE # I'm targeting only with recent clang versions - they are packaged in 28 | # a single linkable library. 29 | clang-cpp LLVM) 30 | 31 | install(TARGETS hcparse RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 32 | target_include_directories(hcparse PUBLIC ${CLANG_INCLUDE_DIRS}) 33 | set_property(TARGET hcparse PROPERTY CXX_STANDARD 20) 34 | 35 | target_compile_options(hcparse PRIVATE "-ferror-limit=1" "-fcoroutines-ts") 36 | 37 | # Don't link with libs that overlaps our options 38 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") 39 | 40 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti") 41 | 42 | # Embed the clang header into the binary: 43 | string(REPLACE "svn" "" LLVM_VERSION "${LLVM_VERSION}") 44 | string(REGEX REPLACE "git.*$" "" LLVM_VERSION "${LLVM_VERSION}") 45 | 46 | if(NOT CLANG_BUILTIN_HEADERS_DIR) 47 | set(CLANG_BUILTIN_HEADERS_DIR 48 | "${LLVM_LIBRARY_DIR}/clang/${LLVM_VERSION}/include") 49 | endif() 50 | 51 | file(GLOB BUILTINS_HEADERS "${CLANG_BUILTIN_HEADERS_DIR}/*.h") 52 | if(NOT BUILTINS_HEADERS) 53 | message( 54 | FATAL_ERROR 55 | "Could not find any clang builtins headers in ${CLANG_BUILTIN_HEADERS_DIR}" 56 | ) 57 | endif() 58 | 59 | foreach(BUILTIN_HEADER ${BUILTINS_HEADERS}) 60 | # filter files that are way to big 61 | if(NOT BUILTIN_HEADER MATCHES 62 | ".*/(arm_neon.h|altivec.h|vecintrin.h|avx512.*intrin.h)") 63 | file(READ ${BUILTIN_HEADER} BINARY_DATA) 64 | string(REPLACE "\\" "\\\\" BINARY_DATA "${BINARY_DATA}") 65 | string(REPLACE "\"" "\\\"" BINARY_DATA "${BINARY_DATA}") 66 | string(REPLACE "\n" "\\n\"\n\"" BINARY_DATA "${BINARY_DATA}") 67 | # workaround the fact that stdint.h includes itself 68 | string(REPLACE "__CLANG_STDINT_H" "__CLANG_STDINT_H2" BINARY_DATA 69 | "${BINARY_DATA}") 70 | string(REPLACE "${CLANG_BUILTIN_HEADERS_DIR}/" "/builtins/" FN 71 | "${BUILTIN_HEADER}") 72 | set(EMBEDDED_DATA 73 | "${EMBEDDED_DATA} { \"${FN}\" , \"${BINARY_DATA}\" } , \n") 74 | endif() 75 | endforeach() 76 | 77 | configure_file(src/embedded_includes.hpp.in embedded_includes.hpp) 78 | target_include_directories(hcparse PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) 79 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity exercising 25 | permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but not 33 | limited to compiled object code, generated documentation, and 34 | conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or Object 37 | form, made available under the License, as indicated by a copyright 38 | notice that is included in or attached to the work (an example is 39 | provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other 44 | modifications represent, as a whole, an original work of authorship. 45 | For the purposes of this License, Derivative Works shall not include 46 | works that remain separable from, or merely link (or bind by name) to 47 | the interfaces of, the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including the 50 | original version of the Work and any modifications or additions to 51 | that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright 53 | owner or by an individual or Legal Entity authorized to submit on 54 | behalf of the copyright owner. For the purposes of this definition, 55 | "submitted" means any form of electronic, verbal, or written 56 | communication sent to the Licensor or its representatives, including 57 | but not limited to communication on electronic mailing lists, source 58 | code control systems, and issue tracking systems that are managed by, 59 | or on behalf of, the Licensor for the purpose of discussing and 60 | improving the Work, but excluding communication that is conspicuously 61 | marked or otherwise designated in writing by the copyright owner as 62 | "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, publicly 72 | display, publicly perform, sublicense, and distribute the Work and 73 | such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of this 76 | License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable by 81 | such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) with 83 | the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 86 | Contribution incorporated within the Work constitutes direct or 87 | contributory patent infringement, then any patent licenses granted to 88 | You under this License for that Work shall terminate as of the date 89 | such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the Work 92 | or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You meet 94 | the following conditions: 95 | 96 | a) You must give any other recipients of the Work or Derivative Works 97 | a copy of this License; and 98 | 99 | b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | c) You must retain, in the Source form of any Derivative Works that 103 | You distribute, all copyright, patent, trademark, and attribution 104 | notices from the Source form of the Work, excluding those notices 105 | that do not pertain to any part of the Derivative Works; and 106 | 107 | d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one of 112 | the following places: within a NOTICE text file distributed as 113 | part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents of 117 | the NOTICE file are for informational purposes only and do not 118 | modify the License. You may add Your own attribution notices 119 | within Derivative Works that You distribute, alongside or as an 120 | addendum to the NOTICE text from the Work, provided that such 121 | additional attribution notices cannot be construed as modifying 122 | the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions for 126 | use, reproduction, or distribution of Your modifications, or for any 127 | such Derivative Works as a whole, provided Your use, reproduction, 128 | and distribution of the Work otherwise complies with the conditions 129 | stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work by 133 | You to the Licensor shall be under the terms and conditions of this 134 | License, without any additional terms or conditions. Notwithstanding 135 | the above, nothing herein shall supersede or modify the terms of any 136 | separate license agreement you may have executed with Licensor 137 | regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed 145 | to in writing, Licensor provides the Work (and each Contributor 146 | provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES 147 | OR CONDITIONS OF ANY KIND, either express or implied, including, 148 | without limitation, any warranties or conditions of TITLE, 149 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR 150 | PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this 153 | License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the Work 162 | (including but not limited to damages for loss of goodwill, work 163 | stoppage, computer failure or malfunction, or any and all other 164 | commercial damages or losses), even if such Contributor has been 165 | advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing the 168 | Work or Derivative Works thereof, You may choose to offer, and charge 169 | a fee for, acceptance of support, warranty, indemnity, or other 170 | liability obligations and/or rights consistent with this License. 171 | However, in accepting such obligations, You may act only on Your own 172 | behalf and on Your sole responsibility, not on behalf of any other 173 | Contributor, and only if You agree to indemnify, defend, and hold 174 | each Contributor harmless for any liability incurred by, or claims 175 | asserted against, such Contributor by reason of your accepting any 176 | such warranty or additional liability. 177 | 178 | END OF TERMS AND CONDITIONS 179 | 180 | Copyright 2021 haxscramper 181 | 182 | Licensed under the Apache License, Version 2.0 (the "License"); you may 183 | not use this file except in compliance with the License. You may obtain 184 | a copy of the License at 185 | 186 | http://www.apache.org/licenses/LICENSE-2.0 187 | 188 | Unless required by applicable law or agreed to in writing, software 189 | distributed under the License is distributed on an "AS IS" BASIS, 190 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 191 | See the License for the specific language governing permissions and 192 | limitations under the License. 193 | -------------------------------------------------------------------------------- /Taskfile.yaml: -------------------------------------------------------------------------------- 1 | version: 3 2 | vars: 3 | REL_CONAN: "build/dependencies/conan" 4 | CONAN_DIR: | 5 | {{env "PWD"}}/build/dependencies/conan 6 | 7 | tasks: 8 | conan_install: 9 | cmds: 10 | - conan install . -if {{.REL_CONAN}} --build=missing --settings compiler.libcxx="libstdc++11" 11 | status: 12 | - test -e {{.CONAN_DIR}} 13 | 14 | main: 15 | dir: build 16 | desc: "Build main project" 17 | deps: [conan_install] 18 | cmds: 19 | - cmake .. 20 | - make -j8 21 | - cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 22 | - > 23 | ./hcparse 24 | -o db.sqlite 25 | -a 26 | -b compile_commands.json 27 | -p hcparse:{{.PWD}}/src 28 | -------------------------------------------------------------------------------- /architecture.md: -------------------------------------------------------------------------------- 1 | ![tldr](architecture_tldr.jpg) -------------------------------------------------------------------------------- /architecture_tldr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haxscramper/hcparse/1e1a68a49192c0a3731ae3279be56c2a24542bb0/architecture_tldr.jpg -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # -*- coding: utf-8 -*- 3 | set -o nounset 4 | set -o errexit 5 | 6 | ./compile.sh \ 7 | -o=hc_tsreader.bin \ 8 | ./src/hcparse/read_tree_sitter/hc_tsconvert.nim 9 | 10 | ./hc_tsreader.bin 11 | -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # -*- coding: utf-8 -*- 3 | set -o nounset 4 | set -o errexit 5 | 6 | SRC_DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")") 7 | SKULL=$SRC_DIR/../nimskull 8 | 9 | nim c \ 10 | --lib=$SKULL/lib \ 11 | --define=useNodeIds \ 12 | --debugger=native \ 13 | --excludePath=$HOME/.choosenim/toolchains/nim-1.6.4 \ 14 | -d=nimDebugUtils \ 15 | --path=$SKULL \ 16 | $@ 17 | 18 | echo "compilation done" 19 | -------------------------------------------------------------------------------- /conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | fmt/9.0.0 3 | yaml-cpp/0.7.0 4 | range-v3/0.12.0 5 | sqlite_orm/1.7.1 6 | indicators/2.2 7 | range-v3/0.12.0 8 | 9 | [generators] 10 | cmake 11 | json 12 | gcc 13 | qmake 14 | cmake_find_package 15 | -------------------------------------------------------------------------------- /cpp/Makefile: -------------------------------------------------------------------------------- 1 | deps: 2 | clang++ -lboost_system -lboost_filesystem -lboost_thread -lboost_wave -o../bin/deps deps.cpp 3 | -------------------------------------------------------------------------------- /cpp/deps.cpp: -------------------------------------------------------------------------------- 1 | #define STRINGIFY(x) #x 2 | #define XSTRINGIFY(x) STRINGIFY(x) 3 | 4 | // adapted from https://github.com/katahiromz/BoostWaveExample 5 | // to build run `clang++ -lboost_system -lboost_filesystem -lboost_thread 6 | // -lboost_wave -o../bin/deps deps.cpp` 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | // #include 23 | 24 | #include "predefined.hpp" 25 | 26 | class BasicInputPolicy 27 | { 28 | public: 29 | template 30 | class inner 31 | { 32 | public: 33 | static std::string readFile(const char* filePath) { 34 | // Open file 35 | std::ifstream fs(filePath); 36 | if (!fs) { 37 | std::string msg = "Cannot open file '"; 38 | msg += (filePath == nullptr) ? "(nullptr)" : filePath; 39 | msg += "'."; 40 | throw std::runtime_error(msg.c_str()); 41 | } 42 | 43 | // Read 44 | fs.unsetf(std::ios::skipws); 45 | std::string text( 46 | std::istreambuf_iterator(fs.rdbuf()), 47 | std::istreambuf_iterator()); 48 | 49 | return text; 50 | } 51 | 52 | template 53 | static void init_iterators( 54 | IterContextT& iterContext, 55 | const PositionT& pos, 56 | boost::wave::language_support language) { 57 | try { 58 | iterContext.code = readFile(iterContext.filename.c_str()); 59 | iterContext.code += "\n"; 60 | } catch (const std::exception&) { 61 | BOOST_WAVE_THROW_CTX( 62 | iterContext.ctx, 63 | boost::wave::preprocess_exception, 64 | bad_include_file, 65 | iterContext.filename.c_str(), 66 | pos); 67 | return; 68 | } 69 | 70 | typedef typename IterContextT::iterator_type iterator_type; 71 | iterContext.first = iterator_type( 72 | iterContext.code.begin(), 73 | iterContext.code.end(), 74 | PositionT(iterContext.filename), 75 | language); 76 | iterContext.last = iterator_type(); 77 | } 78 | 79 | protected: 80 | std::string code; 81 | }; 82 | }; 83 | 84 | inline void show_help(void) { 85 | std::cout 86 | << "Usage: cpp [options] input-file\n" 87 | "Generate tree of dependencies for file \n\n" 88 | "WARNING: no assumptions about include paths is made - " 89 | "you need to manually include locations for the system include " 90 | "headers and your project's include paths. " 91 | "\n\n" 92 | "** System variable & default paths\n\n" 93 | "`$CPATH` is added to sytem paths and either of " 94 | "`$C_INCLUDE_PATH` or `$CPLUS_INCLUDE_PATH` " 95 | "(mutally exclusive!) variables. `/usr/include` is " 96 | "added to system include path if none of the above variables " 97 | "are defined\n" 98 | "Basically you have two ways for using this - either set none " 99 | "of the variables and supply all options through the " 100 | "command-line flags (+ /usr/include added by default), or set " 101 | "`$CPATH` for common include directories (both C++ and C) and " 102 | "one of the `C/CPLUS` variables. C one is queried first" 103 | "\n\n" 104 | "** Options:\n\n" 105 | " -Dmacro Defines a macro\n" 106 | " -Dmacro=def Defines a macro\n" 107 | " -Umacro Undefines a macro\n" 108 | " -Ipath Adds include path\n" 109 | " -Spath Adds system include path\n\n" 110 | "** Output format\n\n" 111 | "Output consists of nested opening/closing parenthesis {} with " 112 | "list of file. Each opening paren corresponds to opening " 113 | "#include directive, with all elements in the next layer being " 114 | "retrived from the #include'd file. Output example:\n\n" 115 | // clang-format off 116 | " /usr/include/c++/10.2.0/iostream\n" 117 | " {\n" 118 | " /usr/include/c++/10.2.0/x86_64-pc-linux-gnu/bits/c++config.h\n" 119 | " {\n" 120 | " /usr/include/c++/10.2.0/x86_64-pc-linux-gnu/bits/os_defines.h\n" 121 | " {\n" 122 | // clang-format on 123 | << std::endl; 124 | } 125 | std::vector split(const std::string& s, char delim) { 126 | std::vector elems; 127 | std::stringstream ss(s); 128 | std::string item; 129 | while (std::getline(ss, item, delim)) { 130 | elems.push_back(item); 131 | } 132 | 133 | return elems; 134 | } 135 | 136 | 137 | template 138 | inline bool setup_context(T_CONTEXT& ctx, int argc, char** argv) { 139 | using namespace boost; 140 | 141 | // Language options 142 | ctx.set_language(wave::language_support( 143 | wave::support_cpp | wave::support_option_long_long 144 | | wave::support_option_variadics)); 145 | 146 | add_predefined_macros(ctx); 147 | 148 | for (int i = 1; i < argc; ++i) { 149 | if (argv[i][0] == '-' && argv[i][1]) { 150 | std::string str = &(argv[i][2]); 151 | switch (argv[i][1]) { 152 | case 'D': { 153 | ctx.add_macro_definition(str); 154 | break; 155 | } 156 | case 'U': { 157 | ctx.remove_macro_definition(str); 158 | break; 159 | } 160 | case 'I': { 161 | std::cerr << "-I [ " << str << " ]\n"; 162 | ctx.add_include_path(str.c_str()); 163 | break; 164 | } 165 | case 'S': { 166 | std::cerr << "-S [ " << str << " ]\n"; 167 | ctx.add_sysinclude_path(str.c_str()); 168 | break; 169 | } 170 | default: 171 | fprintf( 172 | stderr, "ERROR: invalid argument '%s'\n", argv[i]); 173 | return false; 174 | } 175 | } 176 | } 177 | 178 | const char* path1 = getenv("CPATH"); 179 | const char* path2 = getenv("C_INCLUDE_PATH"); 180 | const char* path3 = getenv("CPLUS_INCLUDE_PATH"); 181 | if (path1) { 182 | for (auto& path : split(std::string(path1), ':')) { 183 | std::cerr << "-S [ " << path << " ]\n"; 184 | ctx.add_sysinclude_path(path.c_str()); 185 | } 186 | } 187 | if (path2) { 188 | for (auto& path : split(std::string(path2), ':')) { 189 | 190 | std::cerr << "-S [ " << path << " ]\n"; 191 | ctx.add_sysinclude_path(path.c_str()); 192 | } 193 | } else if (path3) { 194 | for (auto& path : split(std::string(path3), ':')) { 195 | 196 | std::cerr << "-S [ " << path << " ]\n"; 197 | ctx.add_sysinclude_path(path.c_str()); 198 | } 199 | } 200 | 201 | if (!path1 && !path2 && !path3) { 202 | 203 | std::cerr << "-S [ /usr/include ]\n"; 204 | ctx.add_sysinclude_path("/usr/include"); 205 | } 206 | 207 | return true; 208 | } 209 | 210 | 211 | // A hook class to output the tree 212 | class MakeIncludeTreeHook 213 | : public boost::wave::context_policies::default_preprocessing_hooks 214 | { 215 | private: 216 | typedef boost::reference_wrapper 217 | ref_ptree; 218 | 219 | public: 220 | MakeIncludeTreeHook(boost::property_tree::ptree& target) 221 | : _target(target) 222 | , _current(target) 223 | , _parentStack() 224 | , _lastIncFile() { 225 | } 226 | 227 | public: 228 | const boost::property_tree::ptree& getTarget() const { 229 | return _target; 230 | } 231 | 232 | public: 233 | template 234 | bool found_include_directive( 235 | ContextT const& ctx, 236 | std::string const& filename, 237 | bool include_next) { 238 | _lastIncFile = filename; 239 | 240 | return false; 241 | } 242 | 243 | template 244 | void opened_include_file( 245 | ContextT const&, 246 | std::string const&, 247 | std::string const& absname, 248 | bool) { 249 | // std::cout << "open " << absname << "\n"; 250 | using namespace boost::property_tree; 251 | 252 | _parentStack.push(_current); 253 | 254 | ptree::iterator itr = _current.get().push_back(ptree::value_type( 255 | _lastIncFile, boost::property_tree::ptree(absname))); 256 | _current = boost::ref((*itr).second); 257 | } 258 | 259 | template 260 | void returning_from_include_file(ContextT const&) { 261 | // std::cout << "return\n"; 262 | _current = _parentStack.top(); 263 | 264 | _parentStack.pop(); 265 | } 266 | 267 | private: 268 | ref_ptree _target; 269 | ref_ptree _current; 270 | std::stack _parentStack; 271 | std::string _lastIncFile; 272 | }; 273 | 274 | int main(int argc, char** argv) { 275 | using namespace std; 276 | namespace wave = boost::wave; 277 | using namespace boost::property_tree; 278 | 279 | if (argc < 2 || strcmp(argv[1], "--help") == 0) { 280 | show_help(); 281 | return 1; 282 | } 283 | 284 | // Load source 285 | std::string code; 286 | { 287 | std::ifstream fs(argv[argc - 1]); 288 | fs.unsetf(std::ios::skipws); 289 | code.assign( 290 | std::istreambuf_iterator(fs.rdbuf()), 291 | std::istreambuf_iterator()); 292 | } 293 | 294 | // Tree 295 | ptree incTree; 296 | 297 | // Prepare context 298 | typedef wave::context< 299 | std::string::const_iterator, 300 | wave::cpplexer::lex_iterator>, 301 | BasicInputPolicy, 302 | MakeIncludeTreeHook> // Original hook 303 | Context; 304 | Context ctx( 305 | code.begin(), 306 | code.end(), 307 | argv[argc - 1], 308 | MakeIncludeTreeHook(incTree)); // Pass the tree 309 | 310 | if (!setup_context(ctx, argc, argv)) { 311 | cerr << "Context setup failed"; 312 | return 2; 313 | } 314 | 315 | Context::iterator_type itrEnd = ctx.end(); 316 | Context::iterator_type itr = ctx.begin(); 317 | 318 | cerr << "Starting preprocessor\n"; 319 | try { 320 | auto tmp = (itr != itrEnd); 321 | } catch (const boost::wave::preprocess_exception& ex) { 322 | cerr << "ERROR in " << ex.file_name() << " : " << ex.line_no() 323 | << endl; 324 | cerr << ex.description() << endl; 325 | return 1; 326 | } 327 | 328 | 329 | while (itr != itrEnd) { 330 | try { 331 | ++itr; 332 | } catch (const wave::cpp_exception& ex) { 333 | if (!ex.is_recoverable()) { 334 | cerr << "ERROR in " << ex.file_name() << " : " 335 | << ex.line_no() << endl; 336 | cerr << " -> " << ex.description() << endl; 337 | 338 | cerr << "Severe error; stopping processing\n"; 339 | return 1; 340 | } else { 341 | // fucking "mIsSiNg iNcLuDe fIlE iS rEcOvErAbLe ErRoR" 342 | if (ex.get_errorcode() 343 | == boost::wave::macro_handling_exception:: 344 | bad_include_file) { 345 | cerr << ex.description() << endl; 346 | return 1; 347 | } 348 | } 349 | } catch (const wave::preprocess_exception& ex) { 350 | cerr << "Preprocessor exception"; 351 | cerr << "ERROR in " << ex.file_name() << " : " << ex.line_no() 352 | << endl; 353 | cerr << ex.description() << "\n"; 354 | // cerr << ex.what() << "\n"; 355 | return 1; 356 | } catch (...) { 357 | cerr << "Exception ocurred during preprocessing"; 358 | return 1; 359 | } 360 | } 361 | 362 | info_parser::write_info(cout, incTree); 363 | return 0; 364 | } 365 | -------------------------------------------------------------------------------- /cpp/test-a.cpp: -------------------------------------------------------------------------------- 1 | #include "test-b.hpp" 2 | -------------------------------------------------------------------------------- /cpp/test-b.hpp: -------------------------------------------------------------------------------- 1 | // hello 2 | class A 3 | { 4 | }; 5 | -------------------------------------------------------------------------------- /cpp/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | } 5 | -------------------------------------------------------------------------------- /devnotes.org: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haxscramper/hcparse/1e1a68a49192c0a3731ae3279be56c2a24542bb0/devnotes.org -------------------------------------------------------------------------------- /hcparse.nimble: -------------------------------------------------------------------------------- 1 | # Package 2 | 3 | version = "0.1.2" 4 | author = "haxscramper" 5 | description = "High-level nim wrapper for C/C++ parsing" 6 | license = "Apache-2.0" 7 | srcDir = "src" 8 | 9 | requires "nim >= 1.6.0" 10 | requires "hnimast" 11 | requires "htsparse >= 0.1.10" 12 | requires "https://github.com/haxscramper/frosty#use-cast" 13 | requires "hmisc >= 0.11.5" 14 | 15 | import std/[os, strutils] 16 | 17 | task test, "Run tests": 18 | let dir = currentSourcePath().parentDir() / "tests" 19 | for file in listFiles(dir): 20 | let (_, name, _) = splitFile(file) 21 | if name.startsWith("t") and file.endsWith(".nim"): 22 | echo "[[[[[[[[[[ file run start" 23 | echo file 24 | exec "nim r " & file 25 | echo "]]]]]]]]]] file run done" 26 | # exec "nim r tests/runall.nim test " & currentSourcePath() & " --parse-errors=false" 27 | 28 | task docgen, "Generate documentation": 29 | exec "nim c -r tests/runall.nim doc " & currentSourcePath() 30 | 31 | task push, "Execute checks and push ": 32 | exec "nim r tests/runall.nim push " & currentSourcePath() 33 | 34 | task newversion, "Tag new version and push it to git": 35 | exec "nim r tests/runall.nim newversion " & currentSourcePath() 36 | -------------------------------------------------------------------------------- /index.rst: -------------------------------------------------------------------------------- 1 | eee 2 | -------------------------------------------------------------------------------- /it_works.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haxscramper/hcparse/1e1a68a49192c0a3731ae3279be56c2a24542bb0/it_works.jpg -------------------------------------------------------------------------------- /old/src/.gitignore: -------------------------------------------------------------------------------- 1 | build* 2 | -------------------------------------------------------------------------------- /old/src/FindNIM.cmake: -------------------------------------------------------------------------------- 1 | execute_process( 2 | COMMAND nim --version 3 | OUTPUT_VARIABLE nim_version_out 4 | ) 5 | 6 | string(REGEX MATCH "Version ([0-9]+\\.[0-9]+\\.[0-9]+)" _ ${nim_version_out}) 7 | set(nim_version ${CMAKE_MATCH_1}) 8 | 9 | message(STATUS "Using nim version " ${nim_version}) 10 | 11 | set(NIM_INCLUDE_DIRS "$ENV{HOME}/.choosenim/toolchains/nim-${nim_version}/lib") 12 | 13 | message(DEBUG "Nim base include dirs" ${NIM_INCLUDE_DIRS}) 14 | -------------------------------------------------------------------------------- /old/src/hcparse.nim: -------------------------------------------------------------------------------- 1 | import hcparse/[hc_parsefront] 2 | 3 | export hc_parsefront 4 | 5 | import hmisc/core/all 6 | export all 7 | -------------------------------------------------------------------------------- /old/src/hcparse/hc_impls.nim: -------------------------------------------------------------------------------- 1 | ## Default implementation for user-definable callbacks 2 | import 3 | ./read_libclang/[ 4 | hc_types, 5 | cxcommon, 6 | cxtypes 7 | ], 8 | 9 | ./hc_typeconv, 10 | 11 | ./processor/[ 12 | wrap_store, 13 | hc_postprocess 14 | ] 15 | 16 | import 17 | std/[strutils, strformat, tables] 18 | 19 | import 20 | hmisc/core/all, 21 | hmisc/algo/[namegen, hstring_algo], 22 | hmisc/types/colorstring, 23 | hmisc/other/[oswrap, hlogger] 24 | 25 | import 26 | hnimast 27 | 28 | export namegen, wrap_store 29 | 30 | proc contains*(dir: AbsDir, file: AbsFile): bool = 31 | let dir = dir.getStr() 32 | let file = file.getStr() 33 | 34 | if file.len < dir.len: 35 | return false 36 | else: 37 | return file[0 .. dir.high] == dir 38 | 39 | proc skip*(cx: CxType): CxType = 40 | result = cx 41 | while true: 42 | case result.kind: 43 | of tkLValueReference, tkRValueReference, tkPointer: 44 | result = result[] 45 | 46 | else: 47 | return 48 | 49 | proc ignoreTypeDecl*(conf: WrapConf, cxType: CxType): bool = 50 | var decl = cxType.skip().getTypeDeclaration() 51 | while decl.kind in ckTypeDeclKinds + { ckNamespace }: 52 | result = conf.ignoreCursor(decl, conf) 53 | if result: 54 | break 55 | 56 | else: 57 | decl = decl.getCursorSemanticParent() 58 | 59 | 60 | proc ignoreProcCursor*( 61 | conf: WrapConf, cursor: CxCursor): bool {.logScope(conf.logger).} = 62 | if cursor.kind in { ckFunctionDecl, ckMethod, ckFunctionTemplate }: 63 | for argType in cursor.argTypes(): 64 | if conf.ignoreTypeDecl(argType): 65 | return true 66 | 67 | if conf.ignoreTypeDecl(cursor.retType()): 68 | return true 69 | 70 | 71 | 72 | proc asIncludeFromDir*( 73 | cursor: CXCursor | AbsFile, conf: WrapConf, dir: AbsDir): string = 74 | 75 | when cursor is CXCursor: 76 | let file: AbsFile = cursor.getSpellingLocation().get().file 77 | 78 | else: 79 | let file: AbsFile = cursor 80 | 81 | return file.getStr().dropPrefix(dir.getStr()).dropPrefix("/") 82 | 83 | proc asGlobalInclude*(cursor: CXCursor, conf: WrapConf): string = 84 | let loc = cursor.getSpellingLocation().get() 85 | for dir in conf.parseConf.includepaths: 86 | if loc.file in dir: 87 | return asIncludeFromDir(cursor, conf, dir) 88 | 89 | return $loc.file 90 | 91 | proc isFromDir*(cursor: CXCursor, dir: AbsDir): bool = 92 | cursor.getSpellingLocation().get().file in dir 93 | 94 | proc isFromFile*(cursor: CXCursor, file: AbsFile): bool = 95 | cursor.getSpellingLocation().get().file == file 96 | 97 | proc fixTypeName*(str: string, idx: int, conf: WrapConf): string = 98 | ## Correct C++ type name to be used in nim wrappers. Convert `::` to 99 | ## joined name, use correct upper/lowercasing (nep1 style). 100 | if str.len == 0: 101 | return "T" & $idx 102 | 103 | elif str.isReservedNimType(): 104 | return str 105 | 106 | else: 107 | let split = str.split("::") 108 | var idx = 0 109 | while idx < split.len: 110 | if (idx + 1 < split.len) and 111 | (split[idx] in conf.collapsibleNamespaces) and 112 | (split[idx + 1].normalize().startsWith(split[idx])): 113 | # For things like `sourcetrail::SourcetrailDBWrapper` 114 | discard 115 | else: 116 | result.add split[idx].toPascalCase() 117 | 118 | inc idx 119 | 120 | 121 | proc fixTypeName*(ntype: var NimType, conf: WrapConf, idx: int = 0) = 122 | case ntype.kind: 123 | of ctkAnonObject, ctkAnonEnum: 124 | raise newImplementKindError(ntype) 125 | 126 | of ctkWrapKinds: 127 | fixTypeName(ntype.wrapped, conf, idx) 128 | 129 | of ctkArrayKinds: 130 | fixTypeName(ntype.arrayElement, conf, idx) 131 | 132 | of ctkStaticParam, ctkPod, ctkDecltype: 133 | discard 134 | 135 | of ctkIdent: 136 | ntype.nimName = fixTypeName(ntype.nimName, idx, conf) 137 | var idx = idx 138 | for gen in mitems(ntype.genParams): 139 | conf.fixTypeName(gen, conf, idx) 140 | inc idx 141 | 142 | of ctkProc: 143 | conf.debug ntype.kind 144 | if notNil ntype.returnType: 145 | fixTypeName(ntype.returnType, conf) 146 | 147 | for idx, arg in mpairs(ntype.arguments): 148 | arg.name = 149 | if arg.name.len == 0: 150 | "a" & $idx 151 | 152 | else: 153 | arg.name 154 | 155 | conf.fixtypename(arg.nimType, conf, idx) 156 | 157 | proc fixContextedName*( 158 | name: CxxNamePair, 159 | base: string = name.nim, 160 | style: IdentStyle = idsCamel 161 | ): string = 162 | 163 | if name.cxx.scopes.len == 0: 164 | raise newArgumentError( 165 | "Invalid cxx name pair - empty scopes list") 166 | 167 | assert base.len > 0 168 | 169 | const map = toMapArray({ 170 | cncType: toMapArray({ 171 | idsCamel: ("", "T"), idsSnake: ("", "_t")}), 172 | cncArg: toMapArray({ 173 | idsCamel: ("arg", ""), idsSnake: ("arg_", "")}), 174 | cncProc: toMapArray({ 175 | idsCamel: ("c", ""), idsSnake: ("c", "")}), 176 | cncField: toMapArray({ 177 | idsCamel: ("f", ""), idsSnake: ("", "_f")}), 178 | cncMethod: toMapArray({ 179 | idsCamel: ("m", ""), idsSnake: ("", "_m")}), 180 | cncVar: toMapArray({ 181 | idsCamel: ("v", ""), idsSnake: ("", "_v")}), 182 | cncEnumField: toMapArray({ 183 | idsCamel: ("en", ""), idsSnake: ("", "_en")}) 184 | }) 185 | 186 | result = base.keepNimIdentChars() 187 | let (prefix, suffix) = map[name.context][style] 188 | 189 | if name.context != cncType and isReservedNimType(result): 190 | result = prefix & result & suffix 191 | 192 | assert result.len > 0 193 | if isReservedNimIdent(result): 194 | result = prefix & result & suffix 195 | 196 | proc fixContextedName*( 197 | cache: var StringNameCache, 198 | name: CxxNamePair, 199 | style: IdentStyle = idsSnake 200 | ): string = 201 | if name.nim.len > 0 and cache.knownRename(name.nim): 202 | return cache.getRename(name.nim) 203 | 204 | result = fixContextedName(name, name.nim, style) 205 | 206 | const conf = NameFixConf( 207 | strat: nfsNumerateNew 208 | ) 209 | 210 | if cache.knownGenerated(result): 211 | result = cache.fixDuplicated(name.nim, result, conf) 212 | 213 | cache.newRename(name.nim, result) 214 | 215 | 216 | 217 | 218 | proc getClangSemVersion*(): string = 219 | ($getClangVersion()).split(" ")[2] # WARNING 220 | 221 | proc getClangInclude*(): AbsDir = 222 | let version = getClangSemVersion() 223 | return AbsDir(&"/usr/lib/clang/{version}/include") 224 | 225 | 226 | proc getBuiltinHeaders*(): seq[AbsDir] = 227 | ## According to clang `documentation `_ 228 | ## libclang is needs additional precompiled headers paths in 229 | ## addition to default include. 230 | ## 231 | ## NOTE right now I have zero idea how it works on windows, so I 232 | ## will just hardcode unix-like paths. 233 | @[getClangInclude()] 234 | 235 | 236 | let baseCppParseConf* = ParseConf( 237 | includepaths: getBuiltinHeaders(), 238 | globalFlags: @["-xc++", "-std=c++11"] 239 | ) 240 | 241 | let baseCParseConf* = ParseConf( 242 | includePaths: getBuiltinHeaders(), 243 | sysIncludes: @[ 244 | "/usr/include/linux", 245 | "/usr/include/sys", 246 | "/usr/include", 247 | ], 248 | globalFlags: @[] 249 | ) 250 | 251 | let baseCppWrapConf* = WrapConf( 252 | isImportcpp: true, 253 | parseConf: baseCppParseConf, 254 | makeHeader: ( 255 | proc(cursor: CXCursor, conf: WrapConf): NimHeaderSpec {.closure.} = 256 | let file = cursor.asGlobalInclude(conf) 257 | if file.startsWith("/"): 258 | NimHeaderSpec(kind: cbkAbsolute, file: AbsFile(file)) 259 | 260 | else: 261 | NimHeaderSpec(kind: cbkGlobal, global: file) 262 | ), 263 | fixTypeName: ( 264 | proc(ntype: var NimType, conf: WrapConf, idx: int) {.closure.} = 265 | # Default implementation for type name fixes 266 | fixTypeName(ntype, conf, 0) 267 | ), 268 | 269 | ignoreCursor: ( 270 | proc(cursor: CXCursor, conf: WrapConf): bool {.closure.} = 271 | if not ($cursor).startsWith("__cxx11") and 272 | ( 273 | cursor.cxKind() notin { ckTypedefDecl } and 274 | ( 275 | # Default convention is to prefix private parts with underscores 276 | ($cursor).startsWith(@[ "__", "_" ]) and 277 | # But inline namespaces are still parsed by default 278 | (not (cursor.isInlineNamespace() == 1)) 279 | ) 280 | ): 281 | 282 | if cursor.cxKind() in {ckStructDecl, ckUnionDecl} and 283 | not startsWith($cursor.cxType(), @["__", "_"]): 284 | # `typedef struct _A {} A;` for C wrapping 285 | return false 286 | else: 287 | return true 288 | 289 | if cursor.cxKind == ckNamespace and 290 | ($cursor in @["detail", "internal"]): 291 | return true 292 | 293 | elif cursor.cxKind == ckFieldDecl: 294 | if startsWith($cursor, "private"): 295 | return true 296 | 297 | else: 298 | if conf.isTypeInternal(cursor.cxType(), conf): 299 | return true 300 | 301 | else: 302 | return false 303 | ), 304 | isTypeInternal: ( 305 | proc(cxt: CXType, conf: WrapConf): bool {.closure.} = 306 | case cxt.cxKind: 307 | of tkPodKinds: 308 | result = false 309 | of tkTypedef: 310 | # debug cxt.lispRepr() 311 | result = startsWith($cxt, "_") 312 | of tkPointer: 313 | result = conf.isTypeInternal(cxt[], conf) 314 | else: 315 | result = false 316 | 317 | ), 318 | depResolver: ( 319 | proc(cursor, referencedBy: CXCursor): DepResolutionKind {.closure.} = 320 | if cursor.isFromMainFile(): 321 | result = drkWrapDirectly 322 | 323 | else: 324 | result = drkImportUses 325 | ) 326 | ) 327 | 328 | let baseCWrapConf* = baseCPPWrapConf.withDeepIt do: 329 | it.isImportcpp = false 330 | it.wrapName = "base-c-wrap-conf" 331 | 332 | let baseFixConf* = CxxFixConf( 333 | fixNameImpl: 334 | proc( 335 | name: CxxNamePair, 336 | cache: var StringNameCache, 337 | context: CxxNameFixContext, 338 | conf: CxxFixConf 339 | ): string {.closure.} = 340 | 341 | result = cache.fixContextedName(name) 342 | ) 343 | 344 | template onIgnoreCursor*(inConf: var WrapConf, body: untyped): untyped = 345 | inConf.ignoreCursor = proc( 346 | cursor {.inject.}: CXCursor, 347 | conf {.inject.}: WrapConf 348 | ): bool = 349 | body 350 | -------------------------------------------------------------------------------- /old/src/hcparse/hc_irgen.nim: -------------------------------------------------------------------------------- 1 | import 2 | hmisc/core/all, 3 | hmisc/algo/[hstring_algo], 4 | hmisc/types/colorstring 5 | 6 | 7 | import 8 | ./processor/[wrap_store], 9 | ./read_libclang/[hc_types, cxtypes], 10 | ./hc_typeconv 11 | 12 | proc cxxName*(conf: WrapConf, decl: CDecl): CxxName = 13 | raise newImplementError() 14 | 15 | proc cxxName*(cxtype: CxType, cache: var WrapCache): CxxName = 16 | raise newImplementError() 17 | 18 | proc cxxPair*(conf: WrapConf, decl: CDecl): CxxNamePair = 19 | cxxPair(decl.getNimName(conf), conf.cxxName(decl)) 20 | 21 | proc cxxPair*(conf: WrapConf, cursor: CxCursor): CxxNamePair = 22 | cxxPair($cursor, cxxName(@[$cursor])) 23 | 24 | proc cxxPair*( 25 | conf: WrapConf, ident: CSCopedIdent, cache: var WrapCache): CxxNamePair = 26 | raise newImplementError() 27 | 28 | proc cxxPair*( 29 | conf: WrapConf, cxtype: CxType, cache: var WrapCache): CxxNamePair = 30 | raise newImplementError() 31 | # cxxPair(cxtype.getTypeName(conf)) 32 | 33 | proc toCxxUse*( 34 | conf: WrapConf, cxtype: CxType, cache: var WrapCache): CxxTypeUse 35 | 36 | proc cxxGenParams*( 37 | conf: WrapConf, ident: CSCopedIdent, cache: var WrapCache 38 | ): CxxGenParams = 39 | 40 | raise newImplementError() 41 | 42 | proc toCxxElaborated*( 43 | cxtype: CXType, conf: WrapConf, cache: var WrapCache): CxxTypeUse = 44 | 45 | let decl = cxtype.getTypeDeclaration() 46 | result = conf.cxxPair(cxtype, cache).cxxTypeUse() 47 | if cxtype.getNumTemplateArguments() > 0: 48 | case decl.cxKind: 49 | of ckTypedefDecl, ckTypeAliasDecl, ckTypeAliasTemplateDecl: 50 | # WARNING `template using` is not handled 51 | discard 52 | # result = conf.cxxPair(cxtype, @[]) # newNimType(cxtype.getTypeName(conf), cxtype) 53 | 54 | of ckTypeDeclKinds: 55 | # result = newNimType(cxtype.getTypeName(conf), cxtype) 56 | let params = cxtype.templateParams() 57 | for idx, parm in params: 58 | if parm.cxKind != tkInvalid: 59 | result.add conf.toCxxUse(parm, cache) # parm.toNimType(conf, cache) 60 | 61 | else: 62 | conf.warn "Conversion from elaborated type: ", decl 63 | conf.debug " ", decl.cxKind(), " in ", decl.getSpellingLocation() 64 | 65 | # else: 66 | # result = newNimType(getTypeName(cxtype, conf), cxtype) 67 | 68 | proc toCxxUse*(conf: WrapConf, cxtype: CxType, cache: var WrapCache): CxxTypeUse = 69 | if conf.isComplexType(cxtype, cache): 70 | raise newImplementError() 71 | # return conf.newComplexType(cxType, cache) 72 | 73 | var 74 | mutable: bool = false 75 | pair: CxxNamePair 76 | podKind: CxxPodTypeKind 77 | 78 | case cxtype.cxKind(): 79 | of tkBool, tkint, tkvoid, tkuint, tklonglong, tkulonglong, 80 | tkdouble, tkulong, tkuchar, tkchar16, tkchar32, tkwchar, 81 | tkchar_s, tklong, tkushort, tknullptr, tkfloat, tklongdouble, 82 | tkshort, tkschar: 83 | let name = $cxtype 84 | pair = cxxPair(name, mapPrimitiveName(name).cxxName()) 85 | 86 | podKind = 87 | case cxType.cxKind(): 88 | of tkBool: cptBool 89 | of tkVoid: cptVoid 90 | else: raise newImplementKindError(cxType.cxKind()) 91 | 92 | of tkTypedef: 93 | mutable = cxType.isMutableRef() 94 | pair = cxxPair(($cxtype).dropPrefix("const "), cxxName(cxtype, cache)) 95 | 96 | of tkElaborated, tkRecord, tkEnum: 97 | result = toCxxElaborated(cxtype, conf, cache) # fromElaboratedPType(cxtype, conf, cache) 98 | 99 | of tkPointer: 100 | result = toCxxUse(conf, cxtype[], cache) 101 | result = wrap(result, ctkPtr) 102 | 103 | # of tkConstantArray: 104 | # newNimType( 105 | # "ptr", [ 106 | # newNimType( 107 | # "array", @[ 108 | # newNimType($cxtype.getNumElements(), cxtype.getElementType()), 109 | # toNimType(cxtype.getElementType(), conf, cache) 110 | # ], cxType) 111 | # ], cxType) 112 | 113 | # of tkIncompleteArray: 114 | # # QUESTION maybe convert to `ptr UncheckedArray?` or add user-defined 115 | # # callback for switching between different behaviors. 116 | # newNimType("ptr", [toNimType( 117 | # cxtype.getElementType(), conf, cache)], cxType) 118 | 119 | # of tkFunctionProto: 120 | # newNimType( 121 | # cxtype.argTypes.mapIt(initCArg("", toNimType(it, conf, cache))), 122 | # cxtype.getResultType().toNimType(conf, cache) 123 | # ) 124 | 125 | # of tkLValueReference: 126 | # # NOTE this implementation does not work as expected, becuase `const 127 | # # T&` is not a const-qulified type. 128 | # # 129 | # # mutable = not cxType.isConstQualified() 130 | # mutable = not startsWith($cxType, "const") 131 | # special = ctskLValueRef 132 | 133 | # toNimType(cxType[], conf, cache) 134 | 135 | # of tkRValueReference: # WARNING I'm not 100% sure this is correct 136 | # # way to map rvalue references to nim type 137 | # # system. 138 | # mutable = cxType.isMutableRef() 139 | # special = ctskRValueRef 140 | # toNimType(cxType[], conf, cache) 141 | 142 | # of tkUnexposed: 143 | # let strval = ($cxType).dropPrefix("const ") # WARNING 144 | # let db = "string" in strval 145 | 146 | # if strval.validCxxIdentifier(): 147 | # newNimType(strval, cxtype) 148 | 149 | # else: 150 | # let 151 | # decl = cxtype.getTypeDeclaration() 152 | # name = cxType.namespacedName(conf) 153 | # typenameParts = toStrPart(@[ 154 | # "type-parameter", "typename type-parameter", 155 | # "typename rebind= 1.2.0" 136 | """ 137 | 138 | proc hcparseMain*(app: var CliApp, l: HLogger) = 139 | echov app.getCmd().treeRepr() 140 | 141 | case app.getCmdName(): 142 | of "init": 143 | let init = app.getCmd() 144 | case init.getCmdName(): 145 | of "conan": 146 | let 147 | conan = init.getCmd() 148 | name = conan.getArg("name") as string 149 | version = conan.getArg("version") as string 150 | 151 | initConanPackage(cwd(), name, version) 152 | 153 | else: 154 | raise newUnexpectedKindError(init.getCmdName()) 155 | 156 | else: 157 | raise newUnexpectedKindError(app.getCmdName()) 158 | 159 | 160 | proc addInitCmd*(app: var CliApp) = 161 | var cmd = cmd("init", "Init default project structure") 162 | 163 | block: 164 | var conan = cmd("conan", "Init wrapper for conan package") 165 | conan.add arg("name", "Target library name") 166 | conan.add arg("version", "Target library version") 167 | 168 | cmd.add conan 169 | 170 | app.add cmd 171 | 172 | proc hcparseCli*(args: seq[string], doRaise = false) = 173 | var 174 | app = newCliApp( 175 | "hcparse", 176 | (0, 1, 3), 177 | "haxscramper", 178 | "CLI driver for hcparse wrapper generator" 179 | ) 180 | 181 | logger = newTermLogger() 182 | 183 | app.addInitCmd() 184 | 185 | app.acceptArgsAndRunBody(logger, args): 186 | app.runMain(hcparseMain, logger, not doRaise, argpass(app, logger)) 187 | -------------------------------------------------------------------------------- /old/src/hcparse/post/closure_override.nim: -------------------------------------------------------------------------------- 1 | when false: 2 | ## Same issue as `hc_genhelper.nim` - I want to retain the code, but I 3 | ## don't quite have the time to fix things right now, so I will return to 4 | ## them sometimes later. 5 | import hcparse/[ 6 | cxtypes, 7 | cxcommon, 8 | hc_types, 9 | hc_wrapgen, 10 | hc_typeconv, 11 | hc_visitors 12 | ] 13 | 14 | ## .. include:: closure_override.rst 15 | 16 | 17 | 18 | import hnimast 19 | 20 | import hmisc/helpers 21 | import hmisc/other/oswrap 22 | import hmisc/other/hlogger 23 | 24 | import std/[decls, strutils, sequtils, tables, sugar, strformat] 25 | 26 | proc toNIdentDefs*(args: seq[CArg], conf: WrapConfig): seq[NIdentDefs[PNode]] = 27 | toNIdentDefs: collect(newSeq): 28 | for arg in args: 29 | let (ntype, mutable) = toNType(arg.cursor.cxType(), conf) 30 | (name: arg.name, 31 | atype: ntype, 32 | nvd: tern(mutable, nvdVar, nvdLet)) 33 | 34 | 35 | proc argsNIdents*(cursor: CXCursor, conf: WrapConfig): seq[NIdentDefs[PNode]] = 36 | cursor.getArguments().toNIdentDefs(conf) 37 | 38 | 39 | proc genConstructors( 40 | entry: WrappedEntry, conf: WrapConfig 41 | ): tuple[wrapped: seq[WrappedEntry], 42 | constructors: tuple[declarations, 43 | definitions: string]] = 44 | 45 | let eName = $entry.cursor 46 | let inclSpec = conf.makeHeader(entry.cursor, conf) 47 | 48 | proc makeConstructor(inArgs: seq[CArg], res: var typeof(result)) = 49 | let 50 | args = inArgs 51 | nargs = toNIdentDefs(args, conf) 52 | signArgs = argsSignature(args) 53 | 54 | 55 | let iinfo1 = currIInfo() 56 | res.constructors.declarations.add &""" 57 | 58 | // Declared in {iinfo1} 59 | {eName}NimRaw({signArgs}); 60 | 61 | """ 62 | 63 | let iinfo = currIInfo() 64 | res.constructors.definitions.add &""" 65 | 66 | // Declared in {iinfo} 67 | {eName}NimRaw::{eName}NimRaw({signArgs}) : 68 | {eName}({argsSignature(args, types = false)}) {{ 69 | 70 | }} 71 | 72 | """ 73 | 74 | block: 75 | var pr = newPProcDecl( 76 | name = "new" & eName & "NimRaw", 77 | rtyp = some(newPType("ptr", [eName & "NimRaw"])), 78 | pragma = newPPragma( 79 | newPIdent("constructor"), 80 | newExprColonExpr(newPident("header"), inclSpec.toNNode()), 81 | newPIdentColonString("importcpp", &"new {eName}NimRaw(@)") 82 | ) 83 | ) 84 | 85 | pr.signature.arguments = nargs 86 | 87 | res.wrapped.add newWrappedEntry(toNimDecl(pr), entry.original) 88 | 89 | block: 90 | let 91 | n1 = newPIdent(eName & "Nim") 92 | n2 = newPIdent("new" & eName & "NimRaw") 93 | 94 | var pr = newPProcDecl( 95 | name = "new" & eName & "Nim", 96 | genParams = @[newPType("T")], 97 | rtyp = some(newPType(eName & "Nim", ["T"])), 98 | iinfo = currIInfo(), 99 | impl = ( 100 | pquote do: 101 | `n1`[T](rawImpl: `n2`(@@@(args.mapIt(newPIdent(it.name))))) 102 | ) 103 | ) 104 | 105 | pr.signature.arguments = nargs 106 | 107 | # NOTE I have no fucking idea about `entry.original` 108 | res.wrapped.add newWrappedEntry( 109 | toNimDecl(pr), entry.original) 110 | 111 | var hasConstructors: bool = false 112 | for constructor in items(entry.cursor, {ckConstructor}): 113 | makeConstructor(constructor.getArguments(), result) 114 | hasConstructors = true 115 | 116 | if not hasConstructors: 117 | makeConstructor(newSeq[CArg](0), result) 118 | 119 | proc genObjects( 120 | entry: WrappedEntry, conf: WrapConfig, codegen: var seq[CxxCodegen] 121 | ): seq[WrappedEntry] = 122 | 123 | let eName = $entry.cursor 124 | let inclSpec = conf.makeHeader(entry.cursor, conf) 125 | 126 | block: 127 | var wrap = newPObjectDecl( 128 | $entry.cursor & "Nim", 129 | iinfo = currIInfo(), 130 | genParams = @[newPType("T")] 131 | ) 132 | 133 | wrap.addField("rawImpl", newPType("ptr", @[$entry.cursor & "NimRaw"])) 134 | wrap.addField("userData", newPType("T")) 135 | 136 | result.add newWrappedEntry(toNimDecl(wrap), entry.original) 137 | 138 | 139 | 140 | for meth in items(entry.cursor, {ckMethod}): 141 | var call = nnkCall.newPTree(newPIdent($meth & "Wrap")) 142 | var nimArgs: seq[(string, NType[PNode])] 143 | 144 | call.add nnkDotExpr.newPTree(newPIdent("derived"), 145 | newPIdent("rawImpl")) 146 | 147 | for arg in meth.getArguments(): 148 | call.add newPIdent(arg.name) 149 | nimArgs.add (arg.name, arg.cursor.cxType().toNType(conf).ntype) 150 | 151 | var subImpl = newPProcDecl( 152 | name = $meth & "Wrap", 153 | exported = false, 154 | args = ( 155 | "raw", 156 | newPType("ptr", [eName & "NimRaw"]) 157 | ) & nimArgs, 158 | pragma = newPPragma( 159 | newExprColonExpr(newPIdent("header"), inclSpec.toNNode()), 160 | newPidentColonString("importcpp", &"#.{meth}(@)") 161 | ) 162 | ) 163 | 164 | 165 | var pr = newPProcDecl( 166 | name = $meth, 167 | genParams = @[newPType("T")], 168 | args = ( 169 | "derived", 170 | newNType("var", [newPType(eName & "Nim", ["T"])]) 171 | 172 | ) & nimArgs, 173 | rtyp = some meth.retType().toNType(conf).ntype, 174 | impl = ( 175 | pquote do: 176 | `subImpl.toNNode()` 177 | `call` 178 | ) 179 | ) 180 | 181 | 182 | result.add newWrappedEntry(toNimDecl(pr), entry.original) 183 | 184 | 185 | 186 | proc callbackOverride*( 187 | we: var WrappedEntry, conf: WrapConfig, codegen: var seq[CxxCodegen] 188 | ): seq[WrappedEntry] {.nimcall.} = 189 | 190 | ## Generate additional derivation for each encountered class. 191 | if we.kind == wekMultitype: 192 | for entry in we.decls: 193 | if entry.wrapped.kind == nekObjectDecl: 194 | # info "Object decl", entry.cursor 195 | let eName = $entry.cursor 196 | let headerFile = entry.cursor.relSpellingFile().withExt("hpp") 197 | let inclSpec = conf.makeHeader(entry.cursor, conf) 198 | 199 | block: 200 | var obj = newPObjectDecl( 201 | $entry.cursor & "NimRaw", 202 | exported = true, 203 | annotate = newPPragma( 204 | newPIdent("importcpp"), 205 | newPIdentColonString("header", headerFile.string) 206 | ), 207 | iinfo = currIInfo() 208 | ) 209 | 210 | obj.addField("userData", newPType("pointer")) 211 | 212 | for meth in items(entry.cursor, {ckMethod}): 213 | var args: seq[(string, NType[PNode])] 214 | args.add ("userData", newPType("pointer")) 215 | 216 | args.add meth.getArguments.mapIt( 217 | (it.name, it.cursor.cxType.toNType(conf).ntype)) 218 | 219 | args.add ("closureEnv", newPType("pointer")) 220 | args.add ("closureProc", newPType("pointer")) 221 | 222 | 223 | obj.addField($meth & "Wrap", newProcNType[PNode]( 224 | args, 225 | meth.retType().toNType(conf).ntype, 226 | newPPragma("cdecl") 227 | )) 228 | 229 | obj.addField($meth & "Proc", newPType("pointer")) 230 | obj.addField($meth & "Env", newPType("pointer")) 231 | 232 | result.add newWrappedEntry(toNimDecl(obj), entry.original) 233 | 234 | result.add genObjects(entry, conf, codegen) 235 | let (wrapped, constructors) = genConstructors(entry, conf) 236 | result.add wrapped 237 | 238 | for meth in items(entry.cursor, {ckMethod}): 239 | let 240 | mn1 = capitalizeAscii($meth) 241 | mn2 = $meth 242 | prIdent = newPIdent("set" & mn1) 243 | nArgList: seq[PNode] = meth.getArguments().mapIt( 244 | nnkExprColonExpr.newPTree( 245 | newPIdent(it.name), 246 | it.cursor.cxType().toNType(conf).ntype.toNNode() 247 | ) 248 | ) 249 | 250 | 251 | let rawid = newPIdent(eName & "Nim") 252 | let impl = pquote do: 253 | proc `prIdent`*[T]( 254 | self: var `rawId`[T], 255 | cb: proc(this: var `rawId`[T], 256 | arg: @@@^nArgList 257 | ) {.closure.} 258 | ) = 259 | 260 | type 261 | ClosImplType = typeof(closureToCdecl(cb)) 262 | SelfType = typeof(self) 263 | 264 | # `{.cdecl.}` implementation callback that will be passed back to 265 | # raw derived class 266 | let wrap = proc( 267 | userData: pointer, arg: @@@^nArgList, 268 | cbEnv, cbImpl: pointer): void {.cdecl.} = 269 | 270 | # Uncast pointer to derived class 271 | var derived = cast[ptr SelfType](userData) 272 | 273 | # Call closure implementation, arguments and closure environment. 274 | cast[ClosImplType](cbImpl)( 275 | derived[], 276 | arg: @@@^(meth.getArguments().mapIt(newPIdent(it.name))), 277 | cbEnv 278 | ) 279 | 280 | 281 | self.rawImpl.@@@!(newPIdent(mn2 & "Wrap")) = wrap 282 | self.rawImpl.userData = addr self 283 | self.rawImpl.@@@!(newPIdent(mn2 & "Env")) = cb.rawEnv() 284 | self.rawImpl.@@@!(newPIdent(mn2 & "Proc")) = cb.rawProc() 285 | 286 | result.add newWrappedEntry(toNimDecl(impl)) 287 | 288 | 289 | 290 | let decls = collect(newSeq): 291 | for meth in items(entry.cursor, {ckMethod}): 292 | let args = ( 293 | "void* userData, " & 294 | meth.argsSignature(wrap = (false, true)) & " " & 295 | "void* closureEnv, " & 296 | "void* closureProc" 297 | ) 298 | 299 | # let overrideArgs = "void* userData, " & 300 | # meth.argsSignature(names = false, wrap = (false, true)) 301 | let iinfo = currIInfo() 302 | let name = meth.getSemanticNamespaces().join("::") 303 | &""" 304 | 305 | // Declared in {iinfo} 306 | // Override wrapper for `{name}` 307 | {meth.retType()} (*{meth}Wrap)({args}) = 0; 308 | void* {meth}Proc = 0; 309 | void* {meth}Env = 0; 310 | 311 | {meth.retType()} {meth}({meth.argsSignature()}) override; 312 | """ 313 | 314 | 315 | let inclFile = tern(inclSpec.kind == nhskGlobal, 316 | &"<{inclSpec.global}>", 317 | &"\"{inclSpec.file}\"") 318 | 319 | 320 | let res = &""" 321 | // Final overide struct 322 | struct {entry.cursor}NimRaw : public {entry.cursor} {{ 323 | // Pointer to wrapper object 324 | void* userData = 0; 325 | 326 | {constructors.declarations} 327 | 328 | {decls.joinl()} 329 | 330 | }}; 331 | """ 332 | codegen.add CxxCodegen( 333 | cursor: entry.cursor, 334 | code: res, 335 | header: &""" 336 | #pragma once 337 | #include {inclFile} 338 | """, 339 | filename: headerFile 340 | ) 341 | 342 | 343 | let impls = collect(newSeq): 344 | for meth in items(entry.cursor, {ckMethod}): 345 | let args = meth.getArguments() 346 | 347 | &""" 348 | // Declared in {currIInfo()} 349 | {meth.retType()} {entry.cursor}NimRaw::{meth}({meth.argsSignature()}) {{ 350 | if (this->{meth}Wrap == 0) {{ 351 | {entry.cursor}::{meth}({meth.argsSignature(types = false)}); 352 | 353 | }} else {{ 354 | this->{meth}Wrap( 355 | this->userData, 356 | {meth.argsSignature(types = false, wrap = (false, true))} 357 | this->{meth}Env, 358 | this->{meth}Proc 359 | ); 360 | }} 361 | }} 362 | 363 | """ 364 | 365 | let iinfo = currIInfo() 366 | codegen.add CxxCodegen( 367 | cursor: entry.cursor, 368 | header: &""" 369 | // Generated in {iinfo} 370 | #include "{headerFile}" 371 | """, 372 | code: &""" 373 | {constructors.definitions} 374 | 375 | {impls.join("\n")} 376 | """, 377 | filename: entry.cursor.relSpellingFile().withExt("cpp") 378 | ) 379 | -------------------------------------------------------------------------------- /old/src/hcparse/post/closure_override.rst: -------------------------------------------------------------------------------- 1 | Postprocessing pass to enable use of nim closures to override C++ methods. 2 | This allows to use OOP-heavy libraries that rely heavily on inheritance and 3 | method overrids to provide user-defined functionality. For each class entry 4 | passed to ``callbackOverride`` new class is generated, deriving from 5 | original one. Derived class overrides all methods of parent class (as well 6 | as method passed from superclass). Additionally, for each reimplemented 7 | method following fields are generated: 8 | 9 | .. code-block:: c++ 10 | 11 | // Closure callback 'caller' - `{.cdecl.}` procedure defined on nim side, 12 | // which performs more type-safe casting of `void*` before calling actual 13 | // implementation 14 | (*Wrap)(void*, , void*, void*) = 0; 15 | void* Proc = 0; // Closure callback implementation 16 | void* Env = 0; // Closure callback envrionment 17 | 18 | Which hold necessary pointers to closure, it's environment and wrapper 19 | implementation. On nim side ``set`` procedure is defined, for 20 | each method, which perfoms necessary casting and conversion between nim 21 | callback closure, and C++ ``void*`` part. 22 | 23 | In result, each method in the C++ object calls either default 24 | implementation (if override wasn't set), or closure overide, with 25 | respective environment. 26 | 27 | In addition to enabling use of OOP code from *mostly procedural* language 28 | this also makes behavior of the objects **instance-based** as opposed to 29 | **class-based**, which provides greater overall flexibility. 30 | 31 | To allow use of custom data associated with object generic wrapper type 32 | ``Nim`` is defined - 33 | 34 | .. code-block:: nim 35 | type 36 | Nim*[T] = object 37 | rawImpl*: ptr NimRaw 38 | userData*: T 39 | 40 | where ``userData`` is an arbitrary nim type and ``rawImpl`` is pointer to 41 | wrapper for `*NimRaw` class. Generate C++ class contains ``void*`` pointer 42 | to nim wrapper and is passed as first argument to closure implementation. 43 | Pointer to class is update each time `set` is called. 44 | 45 | -------------------------------------------------------------------------------- /old/src/hcparse/processor/wrap_icpp.nim: -------------------------------------------------------------------------------- 1 | import std/[strutils, with] 2 | import hmisc/core/all 3 | 4 | type 5 | IcppPartKind* = enum 6 | ipkArgSplice 7 | ipkTextPart 8 | ipkNextArg 9 | ipkNextDotArg ## `#.` 10 | ipkNextCnewArg 11 | 12 | ipkResultType 13 | ipkArgType 14 | 15 | IcppPart* = object 16 | case kind*: IcppPartKind 17 | of ipkTextPart: 18 | text*: string 19 | 20 | of ipkResultType, ipkArgType: 21 | argIdx*: int 22 | baseGet*: int 23 | 24 | else: 25 | discard 26 | 27 | IcppPattern* = object 28 | parts*: seq[IcppPart] 29 | 30 | func add*(icpp: var IcppPattern, part: IcppPart) = 31 | icpp.parts.add part 32 | 33 | func len*(icpp: IcppPattern): int = icpp.parts.len 34 | 35 | func icpp*(kind: IcppPartKind): IcppPart = IcppPart(kind: kind) 36 | func icpp*(text: string): IcppPart = IcppPart(kind: ipkTextPart, text: text) 37 | 38 | func initIcpp*(parts: varargs[IcppPart, icpp]): IcppPattern = 39 | for part in parts: 40 | result.add part 41 | 42 | 43 | func staticMethod*(className, methodName: string): IcppPattern = 44 | with result: 45 | add icpp(className) 46 | add icpp("::") 47 | add icpp(methodName) 48 | add icpp("(") 49 | add icpp(ipkArgSplice) 50 | add icpp(")") 51 | 52 | 53 | func dotMethod*(icpp: var IcppPattern, methodName: string) = 54 | icpp.add icpp(ipkNextDotArg) 55 | icpp.add icpp(methodName) 56 | icpp.add icpp("(") 57 | icpp.add icpp(ipkArgSplice) 58 | icpp.add icpp(")") 59 | 60 | func standaloneProc*(icpp: var IcppPattern, name: string) = 61 | icpp.add icpp(name) 62 | icpp.add icpp("(") 63 | icpp.add icpp(ipkArgSplice) 64 | icpp.add icpp(")") 65 | 66 | func icppInfix*(name: string): IcppPattern = 67 | initIcpp("(", ipkNextArg, " ", name, " ", ipkNextArg, ")") 68 | 69 | func joinName*( 70 | namespace: seq[string], name: string, prefix: string = ""): string = 71 | 72 | result = prefix 73 | result.add join(namespace & name, "::") 74 | 75 | func ctype*(icpp: var IcppPattern, typeName: string) = 76 | icpp.add icpp(typeName) 77 | 78 | func ctype*(icpp: var IcppPattern, namespace: seq[string], typeName: string) = 79 | icpp.add icpp(joinName(namespace, typeName)) 80 | 81 | func `[]`*(icpp: IcppPattern, idx: int): IcppPart = icpp.parts[idx] 82 | 83 | func `$`*(part: IcppPart): string = 84 | case part.kind: 85 | of ipkTextPart: result.add part.text 86 | of ipkNextDotArg: result.add "#." 87 | of ipkNextArg: result.add "#" 88 | of ipkArgSplice: result.add "@" 89 | else: raise newImplementKindError(part) 90 | 91 | 92 | func `$`*(icpp: IcppPattern): string = 93 | for part in icpp.parts: 94 | result.add $part 95 | 96 | proc parsePatternCall*(pat: string): IcppPattern = 97 | var i = 0 98 | var j = 1 99 | 100 | template pushText(str: string): untyped = 101 | if result.parts.len > 0 and 102 | result.parts[^1].kind == ipkTextPart: 103 | result.parts[^1].text.add str 104 | 105 | else: 106 | result.parts.add IcppPart(kind: ipkTextPart, text: str) 107 | 108 | while i < pat.len: 109 | case pat[i]: 110 | of '@': 111 | result.parts.add IcppPart(kind: ipkArgSplice) 112 | inc i 113 | 114 | of '#': 115 | if i + 1 < pat.len and pat[i + 1] in {'+', '@'}: 116 | assert pat[i + 1] != '+', 117 | "`+` is handled differently for importcpp, but " & 118 | "manual does not say what this combination means exactly " & 119 | "so it is not supported for now." 120 | 121 | result.parts.add IcppPart(kind: ipkNextCnewArg) 122 | 123 | inc i 124 | elif i + 1 < pat.len and pat[i + 1] == '.': 125 | result.parts.add IcppPart(kind: ipkNextDotArg) 126 | 127 | inc i 128 | 129 | # elif i + 1 < pat.len and pat[i + 1] == '[': 130 | # discard 131 | 132 | else: 133 | result.parts.add IcppPart(kind: ipkNextArg) 134 | 135 | inc j 136 | inc i 137 | of '\'': 138 | let begin = i 139 | var 140 | stars: int 141 | argIdx: int 142 | isPattern = false 143 | 144 | inc i 145 | 146 | while pat[i] == '*': 147 | inc stars 148 | inc i 149 | 150 | if pat[i] in Digits: 151 | argIdx = pat[i].ord - '0'.ord 152 | inc i 153 | isPattern = true 154 | 155 | else: 156 | i = begin 157 | 158 | 159 | if isPattern: 160 | if argIdx == 0: 161 | result.parts.add IcppPart( 162 | kind: ipkResultType, argIdx: -1, baseGet: stars) 163 | 164 | else: 165 | result.parts.add IcppPart( 166 | kind: ipkResultType, argIdx: argIdx - 1, baseGet: stars) 167 | 168 | else: 169 | pushText("'") 170 | inc i 171 | 172 | else: 173 | let start = i 174 | while i < pat.len: 175 | if pat[i] notin {'@', '#', '\''}: inc(i) 176 | else: 177 | break 178 | 179 | if i - 1 >= start: 180 | pushText(pat[start .. i - 1]) 181 | -------------------------------------------------------------------------------- /old/src/hcparse/read_boost_wave/.fdignore: -------------------------------------------------------------------------------- 1 | boost_wave_wrap*.nim 2 | 3 | -------------------------------------------------------------------------------- /old/src/hcparse/read_boost_wave/.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | 41 | # xemacs temporary files 42 | *.flc 43 | 44 | # Vim temporary files 45 | .*.swp 46 | 47 | # Visual Studio generated files 48 | *.ib_pdb_index 49 | *.idb 50 | *.ilk 51 | *.pdb 52 | *.sln 53 | *.suo 54 | *.vcproj 55 | *vcproj.*.*.user 56 | *.ncb 57 | *.sdf 58 | *.opensdf 59 | *.vcxproj 60 | *vcxproj.* 61 | 62 | # MinGW generated files 63 | *.Debug 64 | *.Release 65 | 66 | # Python byte code 67 | *.pyc 68 | 69 | # Binaries 70 | # -------- 71 | *.dll 72 | *.exe 73 | 74 | CMakeLists.txt.user 75 | build* 76 | 77 | 78 | # Created by https://www.toptal.com/developers/gitignore/api/conan 79 | # Edit at https://www.toptal.com/developers/gitignore?templates=conan 80 | 81 | ### Conan ### 82 | # Conan build information 83 | conan.lock 84 | conanbuildinfo.* 85 | conaninfo.txt 86 | graph_info.json 87 | 88 | # End of https://www.toptal.com/developers/gitignore/api/conan 89 | 90 | **/Find*.cmake 91 | conan_paths.* 92 | activate_run.ps1 93 | activate_run.sh 94 | deactivate_run.ps1 95 | deactivate_run.sh 96 | environment_run.ps1.env 97 | environment_run.sh.env 98 | -------------------------------------------------------------------------------- /old/src/hcparse/read_boost_wave/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | set(QT_CREATOR_SKIP_CONAN_SETUP ON) 4 | set(CMAKE_VERBOSE_MAKEFILE ON) 5 | 6 | project(wave CXX C) 7 | 8 | project(boost_wave LANGUAGES CXX) 9 | 10 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 11 | set(CMAKE_CXX_STANDARD 17) 12 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 13 | 14 | add_library(boost_cwave SHARED 15 | boost_wave_global.hpp 16 | boost_wave.cpp 17 | boost_wave.hpp 18 | wave_c_api.h 19 | ) 20 | 21 | add_executable(boost_wave_test 22 | boost_wave_test.cpp 23 | boost_wave.cpp 24 | boost_wave.hpp 25 | scratch.cpp 26 | ) 27 | 28 | include(${CMAKE_CURRENT_SOURCE_DIR}/conanbuildinfo.cmake) 29 | conan_basic_setup(TARGETS) 30 | include(${CMAKE_CURRENT_SOURCE_DIR}/conan_paths.cmake) 31 | 32 | find_package(Boost COMPONENTS system filesystem thread wave REQUIRED) 33 | 34 | target_link_libraries(boost_cwave 35 | Boost::system 36 | Boost::filesystem 37 | Boost::wave 38 | Boost::thread 39 | ) 40 | 41 | #target_compile_definitions(boost_cwave PUBLIC 42 | # BOOST_ALL_NO_LIB 43 | # BOOST_CHRONO_DYN_LINK 44 | # BOOST_FILESYSTEM_DYN_LINK 45 | # BOOST_SYSTEM_DYN_LINK 46 | # BOOST_THREAD_DYN_LINK 47 | # BOOST_WAVE_DYN_LINK 48 | # BOOST_WAVE_LIBRARY 49 | #) 50 | 51 | target_link_libraries(boost_wave_test 52 | Boost::system 53 | Boost::filesystem 54 | Boost::wave 55 | Boost::thread 56 | ) 57 | 58 | #target_compile_definitions(boost_wave_test PUBLIC 59 | # BOOST_ALL_NO_LIB 60 | # BOOST_CHRONO_DYN_LINK 61 | # BOOST_FILESYSTEM_DYN_LINK 62 | # BOOST_SYSTEM_DYN_LINK 63 | # BOOST_THREAD_DYN_LINK 64 | # BOOST_WAVE_DYN_LINK 65 | # BOOST_WAVE_LIBRARY 66 | #) 67 | 68 | target_compile_definitions(boost_cwave PRIVATE BOOST_WAVE_LIBRARY) 69 | 70 | set_target_properties(boost_cwave 71 | PROPERTIES 72 | LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../../lib" 73 | ) 74 | -------------------------------------------------------------------------------- /old/src/hcparse/read_boost_wave/boost_wave_global.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_WAVE_GLOBAL_HPP 2 | #define BOOST_WAVE_GLOBAL_HPP 3 | 4 | #if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) 5 | # define Q_DECL_EXPORT __declspec(dllexport) 6 | # define Q_DECL_IMPORT __declspec(dllimport) 7 | #else 8 | # define Q_DECL_EXPORT __attribute__((visibility("default"))) 9 | # define Q_DECL_IMPORT __attribute__((visibility("default"))) 10 | #endif 11 | 12 | #if defined(BOOST_WAVE_LIBRARY) 13 | # define BOOST_WAVE_EXPORT Q_DECL_EXPORT 14 | #else 15 | # define BOOST_WAVE_EXPORT Q_DECL_IMPORT 16 | #endif 17 | 18 | #endif // BOOST_WAVE_GLOBAL_HPP 19 | -------------------------------------------------------------------------------- /old/src/hcparse/read_boost_wave/boost_wave_test.cpp: -------------------------------------------------------------------------------- 1 | #include "boost_wave.hpp" 2 | 3 | EntryHandling found_warning_directive_impl( 4 | const WaveContextImplHandle* ctx, 5 | const WaveTokenListHandle* message, 6 | void* env) { 7 | std::cout << "Found warning directive with message [[" 8 | << util::impl::as_string(*toCxx(message)) << "]]\n"; 9 | return EntryHandlingSkip; 10 | } 11 | 12 | 13 | int main() { 14 | const char* text = "test()\n"; 15 | WaveContextHandle* context = wave_newWaveContext(text, "file"); 16 | 17 | // wave_setFoundWarningDirective(context, 18 | // &found_warning_directive_impl, NULL); 19 | 20 | 21 | WaveIteratorHandle* begin = wave_beginIterator(context); 22 | WaveIteratorHandle* end = wave_endIterator(context); 23 | 24 | while (!wave_contextHasErrors(context) 25 | && wave_neqIterator(begin, end)) { 26 | WaveTokenHandle* tok = wave_iterGetTok(begin); 27 | std::cout << "token " << wave_tokGetValue(tok) << "\n"; 28 | wave_advanceIterator(begin); 29 | wave_deleteTok(tok); 30 | } 31 | 32 | if (wave_contextHasErrors(context)) { 33 | std::cout << "Error encountered during parsing\n"; 34 | } 35 | 36 | if (wave_contextHasWarnings(context)) { 37 | std::cout << "Warning encountered during parsing\n"; 38 | auto warn = wave_contextPopDiagnostics(context); 39 | std::cout << "> " << warn.errorText << " in " << warn.filename 40 | << "\n"; 41 | } 42 | 43 | std::cout << "Done\n"; 44 | } 45 | -------------------------------------------------------------------------------- /old/src/hcparse/read_boost_wave/boost_wave_tokens.nim: -------------------------------------------------------------------------------- 1 | import std/bitops 2 | 3 | func `or`[A, B](a: A, b: B): int = a.int or b.int 4 | func `and`[A, B](a: A, b: B): int = a.int and b.int 5 | 6 | template fromId(id, cat: untyped): untyped = bitor(id.int, cat.int) 7 | # template fromTok(tok: ) 8 | # template fromId(id, cat: untyped): untyped = id or cat 9 | 10 | # #define ID_FROM_TOKEN(tok) ((tok) & ~TokenTypeMask) 11 | # #define BASEID_FROM_TOKEN(tok) ((tok) & ~ExtTokenTypeMask) 12 | 13 | 14 | type 15 | TokenCategory = enum 16 | PPTokenFlag = 0x00040000 17 | TokenValueMask = 0x0007FFFF 18 | AltTokenType = 0x00080000 19 | TriGraphTokenType = 0x00100000 20 | AltExtTokenType = 0x00280000 21 | ExtTokenOnlyMask = 0x00780000 22 | 23 | 24 | IdentifierTokenType = 0x08040000 25 | ParameterTokenType = 0x08840000 26 | ExtParameterTokenType = 0x088C0000 27 | OptParameterTokenType = 0x08940000 28 | KeywordTokenType = 0x10040000 29 | OperatorTokenType = 0x18040000 30 | LiteralTokenType = 0x20040000 31 | IntegerLiteralTokenType = 0x20840000 32 | FloatingLiteralTokenType = 0x21040000 33 | StringLiteralTokenType = 0x21840000 34 | CharacterLiteralTokenType = 0x22040000 35 | BoolLiteralTokenType = 0x22840000 36 | PPTokenType = 0x28040000 37 | PPConditionalTokenType = 0x28440000 38 | 39 | UnknownTokenType = 0x50000000 40 | EOLTokenType = 0x58000000 41 | EOFTokenType = 0x60000000 42 | WhiteSpaceTokenType = 0x68000000 43 | InternalTokenType = 0x70040000 44 | 45 | TokenTypeMask = 0x7F800000 46 | 47 | 48 | MainTokenMask = 0x7F87FFFF 49 | ExtTokenTypeMask = 0x7FF80000 50 | 51 | import std/macros 52 | 53 | type 54 | WaveTokId* = enum 55 | tokId_UNKNOWN 56 | tokId_FIRST_TOKEN 57 | tokId_AND 58 | tokId_AND_ALT 59 | tokId_ANDAND 60 | tokId_ANDAND_ALT 61 | tokId_ASSIGN 62 | tokId_ANDASSIGN 63 | tokId_ANDASSIGN_ALT 64 | tokId_OR 65 | tokId_OR_ALT 66 | tokId_OR_TRIGRAPH 67 | tokId_ORASSIGN 68 | tokId_ORASSIGN_ALT 69 | tokId_ORASSIGN_TRIGRAPH 70 | tokId_XOR 71 | tokId_XOR_ALT 72 | tokId_XOR_TRIGRAPH 73 | tokId_XORASSIGN 74 | tokId_XORASSIGN_ALT 75 | tokId_XORASSIGN_TRIGRAPH 76 | tokId_COMMA 77 | tokId_COLON 78 | tokId_DIVIDE 79 | tokId_DIVIDEASSIGN 80 | tokId_DOT 81 | tokId_DOTSTAR 82 | tokId_ELLIPSIS 83 | tokId_EQUAL 84 | tokId_GREATER 85 | tokId_GREATEREQUAL 86 | tokId_LEFTBRACE 87 | tokId_LEFTBRACE_ALT 88 | tokId_LEFTBRACE_TRIGRAPH 89 | tokId_LESS 90 | tokId_LESSEQUAL 91 | tokId_LEFTPAREN 92 | tokId_LEFTBRACKET 93 | tokId_LEFTBRACKET_ALT 94 | tokId_LEFTBRACKET_TRIGRAPH 95 | tokId_MINUS 96 | tokId_MINUSASSIGN 97 | tokId_MINUSMINUS 98 | tokId_PERCENT 99 | tokId_PERCENTASSIGN 100 | tokId_NOT 101 | tokId_NOT_ALT 102 | tokId_NOTEQUAL 103 | tokId_NOTEQUAL_ALT 104 | tokId_OROR 105 | tokId_OROR_ALT 106 | tokId_OROR_TRIGRAPH 107 | tokId_PLUS 108 | tokId_PLUSASSIGN 109 | tokId_PLUSPLUS 110 | tokId_ARROW 111 | tokId_ARROWSTAR 112 | tokId_QUESTION_MARK 113 | tokId_RIGHTBRACE 114 | tokId_RIGHTBRACE_ALT 115 | tokId_RIGHTBRACE_TRIGRAPH 116 | tokId_RIGHTPAREN 117 | tokId_RIGHTBRACKET 118 | tokId_RIGHTBRACKET_ALT 119 | tokId_RIGHTBRACKET_TRIGRAPH 120 | tokId_COLON_COLON 121 | tokId_SEMICOLON 122 | tokId_SHIFTLEFT 123 | tokId_SHIFTLEFTASSIGN 124 | tokId_SHIFTRIGHT 125 | tokId_SHIFTRIGHTASSIGN 126 | tokId_STAR 127 | tokId_COMPL 128 | tokId_COMPL_ALT 129 | tokId_COMPL_TRIGRAPH 130 | tokId_STARASSIGN 131 | tokId_ASM 132 | tokId_AUTO 133 | tokId_BOOL 134 | tokId_FALSE 135 | tokId_TRUE 136 | tokId_BREAK 137 | tokId_CASE 138 | tokId_CATCH 139 | tokId_CHAR 140 | tokId_CLASS 141 | tokId_CONST 142 | tokId_CONSTCAST 143 | tokId_CONTINUE 144 | tokId_DEFAULT 145 | tokId_DELETE 146 | tokId_DO 147 | tokId_DOUBLE 148 | tokId_DYNAMICCAST 149 | tokId_ELSE 150 | tokId_ENUM 151 | tokId_EXPLICIT 152 | tokId_EXPORT 153 | tokId_EXTERN 154 | tokId_FLOAT 155 | tokId_FOR 156 | tokId_FRIEND 157 | tokId_GOTO 158 | tokId_IF 159 | tokId_INLINE 160 | tokId_INT 161 | tokId_LONG 162 | tokId_MUTABLE 163 | tokId_NAMESPACE 164 | tokId_NEW 165 | tokId_OPERATOR 166 | tokId_PRIVATE 167 | tokId_PROTECTED 168 | tokId_PUBLIC 169 | tokId_REGISTER 170 | tokId_REINTERPRETCAST 171 | tokId_RETURN 172 | tokId_SHORT 173 | tokId_SIGNED 174 | tokId_SIZEOF 175 | tokId_STATIC 176 | tokId_STATICCAST 177 | tokId_STRUCT 178 | tokId_SWITCH 179 | tokId_TEMPLATE 180 | tokId_THIS 181 | tokId_THROW 182 | tokId_TRY 183 | tokId_TYPEDEF 184 | tokId_TYPEID 185 | tokId_TYPENAME 186 | tokId_UNION 187 | tokId_UNSIGNED 188 | tokId_USING 189 | tokId_VIRTUAL 190 | tokId_VOID 191 | tokId_VOLATILE 192 | tokId_WCHART 193 | tokId_WHILE 194 | tokId_PP_DEFINE 195 | tokId_PP_IF 196 | tokId_PP_IFDEF 197 | tokId_PP_IFNDEF 198 | tokId_PP_ELSE 199 | tokId_PP_ELIF 200 | tokId_PP_ENDIF 201 | tokId_PP_ERROR 202 | tokId_PP_LINE 203 | tokId_PP_PRAGMA 204 | tokId_PP_UNDEF 205 | tokId_PP_WARNING 206 | tokId_IDENTIFIER 207 | tokId_OCTALINT 208 | tokId_DECIMALINT 209 | tokId_HEXAINT 210 | tokId_INTLIT 211 | tokId_LONGINTLIT 212 | tokId_FLOATLIT 213 | tokId_FIXEDPOINTLIT 214 | tokId_CCOMMENT 215 | tokId_CPPCOMMENT 216 | tokId_CHARLIT 217 | tokId_STRINGLIT 218 | tokId_CONTLINE 219 | tokId_SPACE 220 | tokId_SPACE2 221 | tokId_NEWLINE 222 | tokId_GENERATEDNEWLINE 223 | tokId_POUND_POUND 224 | tokId_POUND_POUND_ALT 225 | tokId_POUND_POUND_TRIGRAPH 226 | tokId_POUND 227 | tokId_POUND_ALT 228 | tokId_POUND_TRIGRAPH 229 | tokId_ANY 230 | tokId_ANY_TRIGRAPH 231 | tokId_PP_INCLUDE 232 | tokId_PP_QHEADER 233 | tokId_PP_HHEADER 234 | tokId_PP_INCLUDE_NEXT 235 | tokId_PP_QHEADER_NEXT 236 | tokId_PP_HHEADER_NEXT 237 | tokId_EOF 238 | tokId_EOI 239 | tokId_PP_NUMBER 240 | tokId_MSEXT_INT8 241 | tokId_MSEXT_INT16 242 | tokId_MSEXT_INT32 243 | tokId_MSEXT_INT64 244 | tokId_MSEXT_BASED 245 | tokId_MSEXT_DECLSPEC 246 | tokId_MSEXT_CDECL 247 | tokId_MSEXT_FASTCALL 248 | tokId_MSEXT_STDCALL 249 | tokId_MSEXT_TRY 250 | tokId_MSEXT_EXCEPT 251 | tokId_MSEXT_FINALLY 252 | tokId_MSEXT_LEAVE 253 | tokId_MSEXT_INLINE 254 | tokId_MSEXT_ASM 255 | 256 | tokId_MSEXT_PP_REGION 257 | tokId_MSEXT_PP_ENDREGION 258 | tokId_IMPORT 259 | tokId_ALIGNAS 260 | tokId_ALIGNOF 261 | tokId_CHAR16_T 262 | tokId_CHAR32_T 263 | tokId_CONSTEXPR 264 | tokId_DECLTYPE 265 | tokId_NOEXCEPT 266 | tokId_NULLPTR 267 | tokId_STATICASSERT 268 | tokId_THREADLOCAL 269 | tokId_RAWSTRINGLIT 270 | tokId_CHAR8_T 271 | tokId_CONCEPT 272 | tokId_CONSTEVAL 273 | tokId_CONSTINIT 274 | tokId_CO_AWAIT 275 | tokId_CO_RETURN 276 | tokId_CO_YIELD 277 | tokId_REQUIRES 278 | tokId_SPACESHIP 279 | 280 | tokId_LAST_TOKEN_ID 281 | tokId_LAST_TOKEN 282 | 283 | tokId_UNKNOWN_UNIVERSALCHAR 284 | tokId_NONREPLACABLE_IDENTIFIER 285 | tokId_PLACEHOLDER 286 | tokId_PLACEMARKER 287 | tokId_PARAMETERBASE 288 | tokId_EXTPARAMETERBASE 289 | tokId_OPTPARAMETERBASE 290 | 291 | # # T_LAST_TOKEN_ID = 1879310739 + 1 292 | 293 | # T_LAST_TOKEN = (((1879310739 + 1) and not PPTokenFlag.uint) and not TokenTypeMask.uint) 294 | # T_UNKNOWN_UNIVERSALCHAR = (('\\'.int) or (UnknownTokenType)) 295 | # T_NONREPLACABLE_IDENTIFIER = ((T_LAST_TOKEN + 1) or (IdentifierTokenType)) 296 | # T_PLACEHOLDER = ((T_LAST_TOKEN + 2) or (WhiteSpaceTokenType)) 297 | # T_PLACEMARKER = ((T_LAST_TOKEN + 3) or (InternalTokenType)) 298 | # T_PARAMETERBASE = ((T_LAST_TOKEN + 4) or (ParameterTokenType)) 299 | # T_EXTPARAMETERBASE = ((T_LAST_TOKEN + 4) or (ExtParameterTokenType)) 300 | # T_OPTPARAMETERBASE = ((T_LAST_TOKEN + 4) or (OptParameterTokenType)) 301 | -------------------------------------------------------------------------------- /old/src/hcparse/read_boost_wave/conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | boost/1.76.0 3 | 4 | [options] 5 | boost:shared=True 6 | 7 | [generators] 8 | cmake_find_package 9 | cmake_paths 10 | cmake 11 | virtualrunenv 12 | json 13 | -------------------------------------------------------------------------------- /old/src/hcparse/read_boost_wave/hc_wavereader.nim: -------------------------------------------------------------------------------- 1 | import ./boost_wave 2 | import hmisc/other/oswrap 3 | import hmisc/core/[all] 4 | import std/[strutils, options, tables, sets] 5 | 6 | import ../read_libclang/hc_types 7 | 8 | export boost_wave 9 | 10 | type 11 | WaveReader* = object 12 | ctx*: WaveContext 13 | 14 | WaveCache* = ref object 15 | defines*: Table[AbsFile, seq[ 16 | tuple[name: string, args, body: seq[string]]]] 17 | 18 | 19 | 20 | proc newWaveReader*( 21 | file: AbsFile, 22 | cache: WaveCache, 23 | conf: ParseConf, 24 | code: Option[string] = none string 25 | ): WaveReader = 26 | let topFile = file 27 | 28 | var resCtx: WaveContext = newWaveContext( 29 | if code.isSome(): code.get() else: readFile(file), 30 | file.string, 31 | conf.userIncludes, 32 | conf.sysIncludes 33 | ) 34 | 35 | for (name, args, impl) in conf.macroDefs: 36 | resCtx.addMacroDefinition(name, args, impl) 37 | 38 | resCtx.onFoundIncludeDirective(): 39 | var lastVisited: string 40 | 41 | try: 42 | let inclf = unescapeInclude(impl) 43 | let file = resCtx.findIncludeFile(inclf) 44 | if file notin cache.defines: 45 | cache.defines[file] = @[] 46 | var subcontext = newWaveContext( 47 | readFile($file), $file, conf.userIncludes, conf.sysIncludes) 48 | 49 | var level = 0 50 | 51 | var stack: seq[string] 52 | 53 | subcontext.onOpenedIncludeFile(): 54 | stack.add $absFilename 55 | 56 | subcontext.onReturningFromIncludeFile(): 57 | discard stack.pop() 58 | 59 | subcontext.onFoundIncludeDirective(): 60 | let file = subcontext.findIncludeFile(unescapeInclude(impl)).string 61 | if ?stack and file == stack.last(): 62 | let now = subcontext.currentFile() 63 | let line: int = subcontext.currentLine() 64 | 65 | raise newEnvironmentAssertionError( 66 | "Subcontext included file ", file, 67 | " repeatedly included the same starting point (line ", line, 68 | "). Endless include loop was terminated. ", 69 | "This issue might've been caused my a malformed include header found (", 70 | mcode("#include "), 71 | " without guargs) or incorrect ", 72 | "starting define configuration that lead to an ifinite loop (guard). ", 73 | "Include found at ", 74 | now, ":", line, 75 | " while processing toplevel file ", 76 | mq(topFile) 77 | ) 78 | 79 | else: 80 | lastVisited = file 81 | 82 | return EntryHandlingProcess 83 | 84 | for (name, args, impl) in conf.macroDefs: 85 | subcontext.addMacroDefinition(name, args, impl) 86 | 87 | subcontext.skipAll() 88 | 89 | for def in macroNames(subcontext): 90 | let mdef = subcontext.getMacroDefinition($def) 91 | if not mdef.isPredefined: 92 | var args, body: seq[string] 93 | 94 | for arg in mdef.parameters: args.add $arg 95 | for arg in mdef.definition: body.add $arg 96 | 97 | cache.defines[file].add(($def, args, body)) 98 | 99 | for (name, args, body) in cache.defines[file]: 100 | # FIXME keep track of all defined macros to avoid illegal macro 101 | # redefinition excepsions that might potentially be reaised 102 | # here.? 103 | resCtx.addMacroDefinition(name, args, some body.join("")) 104 | 105 | except: 106 | raise 107 | 108 | return EntryHandlingSkip 109 | 110 | result.ctx = resCtx 111 | 112 | proc newWaveCache*(): WaveCache = new(result) 113 | 114 | proc getExpanded*(reader: var WaveReader): string = 115 | for tok in items(reader.ctx): 116 | result.add tok.strVal() 117 | -------------------------------------------------------------------------------- /old/src/hcparse/read_boost_wave/nim.cfg: -------------------------------------------------------------------------------- 1 | --nimcache:cache 2 | -d:debugDlOpen 3 | --debugger:native 4 | -------------------------------------------------------------------------------- /old/src/hcparse/read_boost_wave/scratch.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haxscramper/hcparse/1e1a68a49192c0a3731ae3279be56c2a24542bb0/old/src/hcparse/read_boost_wave/scratch.cpp -------------------------------------------------------------------------------- /old/src/hcparse/read_boost_wave/xmake.lua: -------------------------------------------------------------------------------- 1 | package("boost_wave_c") 2 | add_deps("cmake") 3 | 4 | on_install("linux", function (package) 5 | print("building package") 6 | import("package.tools.cmake").install(package, configs) 7 | end) 8 | 9 | -------------------------------------------------------------------------------- /old/src/hcparse/read_deps/conan.nim: -------------------------------------------------------------------------------- 1 | import 2 | pkg/[jsony] 3 | 4 | import 5 | std/[strformat] 6 | 7 | import 8 | hmisc/core/all, 9 | hmisc/other/[oswrap, hshell] 10 | 11 | import 12 | ../read_libclang/hc_types 13 | 14 | type 15 | ConanDep* = object 16 | version*: string 17 | name*: string 18 | rootpath*: string 19 | description*: string 20 | includePaths*: seq[string] 21 | libPaths*: seq[string] 22 | cxxflags*: seq[string] 23 | cflags*: seq[string] 24 | 25 | 26 | ConanBuildInfo* = object 27 | dependencies*: seq[ConanDep] 28 | 29 | proc findIncludePath*(info: ConanBuildInfo, lib: string): seq[AbsDir] = 30 | for dep in info.dependencies: 31 | if dep.name == lib: 32 | for path in dep.includePaths: 33 | result.add AbsDir(path) 34 | 35 | proc getBuildInfo*( 36 | name: string, 37 | version: tuple[major, minor, patch: int], 38 | tempDir: AbsDir 39 | ): ConanBuildInfo = 40 | 41 | assertExists(tempDir) 42 | 43 | writeFile(tempDir /. "conanfile.txt", &""" 44 | [requires] 45 | {name}/{version.major}.{version.minor}.{version.patch} 46 | 47 | [generators] 48 | json 49 | """) 50 | 51 | withDir tempDir: 52 | let cmd = shellCmd(conan, install, ".", "build" = "missing") 53 | let res = evalShell cmd 54 | 55 | result = readFile("conanbuildinfo.json").fromJson(ConanBuildInfo) 56 | 57 | proc add*(conf: var ParseConf, info: ConanBuildInfo) = 58 | for dep in info.dependencies: 59 | for path in dep.includePaths: 60 | conf.includePaths.add AbsDir(path) 61 | -------------------------------------------------------------------------------- /old/src/hcparse/read_doxygen/dox_codegen.nim: -------------------------------------------------------------------------------- 1 | import 2 | hnimast/codegen/xsd_to_nim, 3 | hmisc/other/[oswrap, hshell], 4 | hnimast, 5 | hmisc/core/all 6 | 7 | const dir = oswrap.currentSourceDir() 8 | 9 | proc doxygenXmlGenerate() = 10 | let compound = cwd() /. "dox_compound.nim" 11 | generateForXsd(cwd() /. "dox_compound.xsd"). 12 | writeXsdGenerator(compound) 13 | 14 | let index = cwd() /. "dox_index.nim" 15 | generateForXsd(cwd() /. "dox_index.xsd"). 16 | writeXsdGenerator(index) 17 | 18 | execShell shellCmd(nim, check, errormax = 2, $compound), limitErr = 30 19 | execShell shellCmd(nim, check, errormax = 2, $index), limitErr = 30 20 | 21 | echo "Doxygen generate done" 22 | 23 | execShell shellCmd(nim, r, "dox_xml.nim") 24 | 25 | when isMainModule: 26 | if paramCount() == 0: 27 | startHax() 28 | doxygenXmlGenerate() 29 | 30 | else: 31 | case paramStr(0): 32 | of "doxygen": doxygenXmlGenerate() 33 | -------------------------------------------------------------------------------- /old/src/hcparse/read_doxygen/dox_index.nim: -------------------------------------------------------------------------------- 1 | import std/[options] 2 | import hmisc/hasts/[xml_ast] 3 | export options, xml_ast 4 | 5 | import hmisc/algo/halgorithm 6 | 7 | type 8 | DoxygenType* = object 9 | version*: string 10 | compound*: seq[CompoundType] 11 | 12 | CompoundType* = object 13 | refid*: string 14 | kind*: CompoundKind 15 | name*: string 16 | member*: seq[MemberType] 17 | 18 | MemberType* = object 19 | refid*: string 20 | kind*: MemberKind 21 | name*: string 22 | 23 | CompoundKind* = enum 24 | ckClass, ## XSD enumeration: `class` 25 | ckStruct, ## XSD enumeration: `struct` 26 | ckUnion, ## XSD enumeration: `union` 27 | ckInterface, ## XSD enumeration: `interface` 28 | ckProtocol, ## XSD enumeration: `protocol` 29 | ckCategory, ## XSD enumeration: `category` 30 | ckException, ## XSD enumeration: `exception` 31 | ckFile, ## XSD enumeration: `file` 32 | ckNamespace, ## XSD enumeration: `namespace` 33 | ckGroup, ## XSD enumeration: `group` 34 | ckPage, ## XSD enumeration: `page` 35 | ckExample, ## XSD enumeration: `example` 36 | ckDir, ## XSD enumeration: `dir` 37 | ckType ## XSD enumeration: `type` 38 | MemberKind* = enum 39 | mkDefine, ## XSD enumeration: `define` 40 | mkProperty, ## XSD enumeration: `property` 41 | mkEvent, ## XSD enumeration: `event` 42 | mkVariable, ## XSD enumeration: `variable` 43 | mkTypedef, ## XSD enumeration: `typedef` 44 | mkEnum, ## XSD enumeration: `enum` 45 | mkEnumvalue, ## XSD enumeration: `enumvalue` 46 | mkFunction, ## XSD enumeration: `function` 47 | mkSignal, ## XSD enumeration: `signal` 48 | mkPrototype, ## XSD enumeration: `prototype` 49 | mkFriend, ## XSD enumeration: `friend` 50 | mkDcop, ## XSD enumeration: `dcop` 51 | mkSlot ## XSD enumeration: `slot` 52 | 53 | proc loadXml*(parser: var HXmlParser; target: var DoxygenType; tag: string; 54 | inMixed: bool = false) 55 | 56 | proc loadXml*(parser: var HXmlParser; target: var CompoundType; tag: string; 57 | inMixed: bool = false) 58 | 59 | proc loadXml*(parser: var HXmlParser; target: var MemberType; tag: string; 60 | inMixed: bool = false) 61 | 62 | proc loadXml*(parser: var HXmlParser; target: var CompoundKind; tag: string) 63 | 64 | proc loadXml*(parser: var HXmlParser; target: var MemberKind; tag: string) 65 | 66 | proc loadXml*(parser: var HXmlParser; target: var DoxygenType; tag: string; 67 | inMixed: bool = false) = 68 | ## 743:4:xml_to_types.nim 69 | next(parser) 70 | while true: 71 | case parser.kind 72 | of XmlEventKind.xmlAttribute: 73 | case parser.attrKey 74 | of "version": 75 | loadXml(parser, target.version, "version") 76 | else: 77 | ## 553:4:xml_to_types.nim 78 | if not(startsWith(parser.attrKey(), ["xmlns:", "xsi:", "xml:"])): 79 | raiseUnexpectedAttribute(parser) 80 | else: 81 | parser.next() 82 | of {XmlEventKind.xmlElementStart, XmlEventKind.xmlElementOpen}: 83 | case parser.elementName() 84 | of "compound": 85 | ## 707:48:xml_to_types.nim 86 | loadXml(parser, target.compound, "compound") 87 | else: 88 | ## 712:4:xml_to_types.nim 89 | if inMixed: 90 | return 91 | else: 92 | raiseUnexpectedElement(parser, tag) 93 | of XmlEventKind.xmlElementClose: 94 | parser.next() 95 | of XmlEventKind.xmlElementEnd: 96 | if parser.elementName() == tag: 97 | parser.next() 98 | break 99 | else: 100 | raiseUnexpectedElement(parser, tag) 101 | of {XmlEventKind.xmlError, XmlEventKind.xmlEof, XmlEventKind.xmlCharData, 102 | XmlEventKind.xmlWhitespace, XmlEventKind.xmlComment, XmlEventKind.xmlPI, 103 | XmlEventKind.xmlCData, XmlEventKind.xmlEntity, XmlEventKind.xmlSpecial}: 104 | ## 736:6:xml_to_types.nim 105 | echo parser.displayAt() 106 | assert false 107 | 108 | 109 | proc loadXml*(parser: var HXmlParser; target: var CompoundType; tag: string; 110 | inMixed: bool = false) = 111 | ## 743:4:xml_to_types.nim 112 | next(parser) 113 | while true: 114 | case parser.kind 115 | of XmlEventKind.xmlAttribute: 116 | case parser.attrKey 117 | of "refid": 118 | loadXml(parser, target.refid, "refid") 119 | of "kind": 120 | loadXml(parser, target.kind, "kind") 121 | else: 122 | ## 553:4:xml_to_types.nim 123 | if not(startsWith(parser.attrKey(), ["xmlns:", "xsi:", "xml:"])): 124 | raiseUnexpectedAttribute(parser) 125 | else: 126 | parser.next() 127 | of {XmlEventKind.xmlElementStart, XmlEventKind.xmlElementOpen}: 128 | case parser.elementName() 129 | of "name": 130 | ## 707:48:xml_to_types.nim 131 | loadXml(parser, target.name, "name") 132 | of "member": 133 | ## 707:48:xml_to_types.nim 134 | loadXml(parser, target.member, "member") 135 | else: 136 | ## 712:4:xml_to_types.nim 137 | if inMixed: 138 | return 139 | else: 140 | raiseUnexpectedElement(parser, tag) 141 | of XmlEventKind.xmlElementClose: 142 | parser.next() 143 | of XmlEventKind.xmlElementEnd: 144 | if parser.elementName() == tag: 145 | parser.next() 146 | break 147 | else: 148 | raiseUnexpectedElement(parser, tag) 149 | of {XmlEventKind.xmlError, XmlEventKind.xmlEof, XmlEventKind.xmlCharData, 150 | XmlEventKind.xmlWhitespace, XmlEventKind.xmlComment, XmlEventKind.xmlPI, 151 | XmlEventKind.xmlCData, XmlEventKind.xmlEntity, XmlEventKind.xmlSpecial}: 152 | ## 736:6:xml_to_types.nim 153 | echo parser.displayAt() 154 | assert false 155 | 156 | 157 | proc loadXml*(parser: var HXmlParser; target: var MemberType; tag: string; 158 | inMixed: bool = false) = 159 | ## 743:4:xml_to_types.nim 160 | next(parser) 161 | while true: 162 | case parser.kind 163 | of XmlEventKind.xmlAttribute: 164 | case parser.attrKey 165 | of "refid": 166 | loadXml(parser, target.refid, "refid") 167 | of "kind": 168 | loadXml(parser, target.kind, "kind") 169 | else: 170 | ## 553:4:xml_to_types.nim 171 | if not(startsWith(parser.attrKey(), ["xmlns:", "xsi:", "xml:"])): 172 | raiseUnexpectedAttribute(parser) 173 | else: 174 | parser.next() 175 | of {XmlEventKind.xmlElementStart, XmlEventKind.xmlElementOpen}: 176 | case parser.elementName() 177 | of "name": 178 | ## 707:48:xml_to_types.nim 179 | loadXml(parser, target.name, "name") 180 | else: 181 | ## 712:4:xml_to_types.nim 182 | if inMixed: 183 | return 184 | else: 185 | raiseUnexpectedElement(parser, tag) 186 | of XmlEventKind.xmlElementClose: 187 | parser.next() 188 | of XmlEventKind.xmlElementEnd: 189 | if parser.elementName() == tag: 190 | parser.next() 191 | break 192 | else: 193 | raiseUnexpectedElement(parser, tag) 194 | of {XmlEventKind.xmlError, XmlEventKind.xmlEof, XmlEventKind.xmlCharData, 195 | XmlEventKind.xmlWhitespace, XmlEventKind.xmlComment, XmlEventKind.xmlPI, 196 | XmlEventKind.xmlCData, XmlEventKind.xmlEntity, XmlEventKind.xmlSpecial}: 197 | ## 736:6:xml_to_types.nim 198 | echo parser.displayAt() 199 | assert false 200 | 201 | 202 | proc loadXml*(parser: var HXmlParser; target: var CompoundKind; tag: string) = 203 | ## 776:4:xml_to_types.nim 204 | mixin loadXml 205 | case parser.strVal 206 | of "class": 207 | target = ckClass 208 | of "struct": 209 | target = ckStruct 210 | of "union": 211 | target = ckUnion 212 | of "interface": 213 | target = ckInterface 214 | of "protocol": 215 | target = ckProtocol 216 | of "category": 217 | target = ckCategory 218 | of "exception": 219 | target = ckException 220 | of "file": 221 | target = ckFile 222 | of "namespace": 223 | target = ckNamespace 224 | of "group": 225 | target = ckGroup 226 | of "page": 227 | target = ckPage 228 | of "example": 229 | target = ckExample 230 | of "dir": 231 | target = ckDir 232 | of "type": 233 | target = ckType 234 | parser.next() 235 | 236 | 237 | proc loadXml*(parser: var HXmlParser; target: var MemberKind; tag: string) = 238 | ## 776:4:xml_to_types.nim 239 | mixin loadXml 240 | case parser.strVal 241 | of "define": 242 | target = mkDefine 243 | of "property": 244 | target = mkProperty 245 | of "event": 246 | target = mkEvent 247 | of "variable": 248 | target = mkVariable 249 | of "typedef": 250 | target = mkTypedef 251 | of "enum": 252 | target = mkEnum 253 | of "enumvalue": 254 | target = mkEnumvalue 255 | of "function": 256 | target = mkFunction 257 | of "signal": 258 | target = mkSignal 259 | of "prototype": 260 | target = mkPrototype 261 | of "friend": 262 | target = mkFriend 263 | of "dcop": 264 | target = mkDcop 265 | of "slot": 266 | target = mkSlot 267 | parser.next() 268 | -------------------------------------------------------------------------------- /old/src/hcparse/read_doxygen/dox_index.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /old/src/hcparse/read_libclang/cxcommon.nim: -------------------------------------------------------------------------------- 1 | import std/[strutils, sequtils, parseutils] 2 | import hmisc/other/oswrap 3 | import hmisc/algo/hstring_algo 4 | import hmisc/core/all 5 | 6 | func toCamelCase*(str: string): string = 7 | var buf = str.split("_"). 8 | filterIt(it.len > 0). 9 | mapIt(it.capitalizeAscii()) 10 | 11 | if buf.len > 0 and buf[0].len > 0: 12 | buf[0][0] = buf[0][0].toLowerAscii() 13 | 14 | return buf.join("") 15 | 16 | proc fixIdentName*(str: string): string = 17 | var str = str 18 | str = str[str.skipWhile({'_'}) .. ^1] 19 | str = str.replace("::", "_") 20 | 21 | case str: 22 | of "set": "cxSet" 23 | of "type": "cxType" 24 | of "range": "cxRange" 25 | of "string": "cxString" 26 | of "end": "`end`" 27 | of "is": "cxIs" 28 | of "in": "cxIn" 29 | of "include": "cxInclude" 30 | of "proc": "cxProc" 31 | of "method": "cxMethod" 32 | of "block": "cxBlock" 33 | elif str.normalize() in ["cstringarray"]: 34 | str 35 | 36 | else: 37 | str.toCamelCase() 38 | 39 | func toPascalCase*(str: string): string = 40 | str.split("_"). 41 | filterIt(it.len > 0). 42 | mapIt(it.capitalizeAscii()). 43 | join("") 44 | 45 | proc fixStdTypeName*(head: string, idx: int): string = 46 | if head.len == 0: 47 | result = "T" & $idx 48 | else: 49 | let split = head.split("::") 50 | for name in split[0 .. ^1]: 51 | result &= name.toPascalCase() 52 | 53 | func toIncludes*(files: seq[AbsDir]): seq[string] = 54 | for file in files: 55 | result.add file.getStr().addPrefix("-I") 56 | 57 | func validCxxIdentifier*(str: string): bool = 58 | if str[0] notin IdentStartChars: 59 | return false 60 | 61 | for ch in str: 62 | if ch notin IdentChars: 63 | return false 64 | 65 | return true 66 | 67 | proc fixFileName*(name: string): string = 68 | name.multiReplace({"-": "_", "+": "p"}). 69 | RelFile().withoutExt().getStr().toSnakeCase() 70 | 71 | proc toNimFile*(file: RelFile): RelFile = 72 | var buf: seq[string] 73 | for pathPart in file.getStr().split("/"): 74 | buf.add fixFileName(pathPart) 75 | 76 | result = RelFile(buf.join("/")).withExt("nim") 77 | 78 | 79 | func stripComment*(text: string): string = 80 | const starts = ["/*!", "/**<", "/**", "/*", "//<", "///", "//", "*"] 81 | const ends = ["*/", "*"] 82 | var idx = 0 83 | for line in text.splitLines(): 84 | var pos = line.skipWhile({' '}) 85 | for start in starts: 86 | if pos + start.len < line.len and 87 | line[pos .. pos + start.high] == start: 88 | pos = clamp(pos + start.len, 0, high(line)) 89 | break 90 | 91 | var final = line.high 92 | for endc in ends: 93 | if ?line and line[ 94 | clamp(final - endc.high, 0, final) .. final] == endc: 95 | final = clamp(final - endc.len, pos, high(line)) 96 | break 97 | 98 | if idx != 0: 99 | result.add "\n" 100 | 101 | else: 102 | while pos < line.len and line[pos] in {' '}: 103 | inc pos 104 | 105 | inc idx 106 | if 0 < line.len: 107 | if line[pos .. final] in ["*", "/"]: 108 | result.add "" 109 | 110 | else: 111 | result.add line[pos .. final] 112 | 113 | -------------------------------------------------------------------------------- /old/src/hcparse/read_libclang/cxvisitors.nim: -------------------------------------------------------------------------------- 1 | import libclang_wrap 2 | import std/[macros, sugar, sequtils] 3 | import hmisc/core/[all, code_errors] 4 | import hnimast 5 | 6 | #*************************************************************************# 7 | #************************** Visitor wrappers ***************************# 8 | #*************************************************************************# 9 | 10 | proc toClientData*[T](val: var T): CXClientData = 11 | CXClientData(addr val) 12 | 13 | type CXVisitor = proc( 14 | cursor, parent: CXCursor, 15 | clientData: pointer): CXChildVisitResult {.cdecl.} 16 | 17 | proc toCursorVisitor*(impl: CXVisitor): CXCursorVisitor = 18 | CXCursorVisitor(impl) 19 | 20 | proc visitChildren*[T]( 21 | cursor: CXCursor, callback: tuple[data: T, impl: CXVisitor]) = 22 | ## Overload for child visit used by `makeVisitor` macro 23 | var data = callback.data 24 | discard cursor.visitChildren( 25 | toCursorVisitor(callback.impl), 26 | toClientData(data)) 27 | 28 | func makeVisitorImpl*( 29 | varnames: seq[NimNode], 30 | procArgs: openarray[(string, NType[NimNode])], 31 | returnType: NType[NimNode], 32 | body: NimNode 33 | ): NimNode = 34 | 35 | var immutableCopies = newStmtList() 36 | let tupleData = nnkPar.newTree: collect(newSeq): 37 | for capture in varnames: 38 | capture.assertNodeKind({nnkIdent}) 39 | immutableCopies.add quote do: 40 | when not isMutable(`capture`): 41 | var `capture` = `capture` 42 | 43 | newColonExpr(capture, newCall("addr", capture)) 44 | 45 | let byaddrid = ident "byaddr" 46 | let dataUnpack = newStmtList: collect(newSeq): 47 | for capture in varnames: 48 | quote do: 49 | var `capture` {.`byaddrid`.} = data[].`capture`[] 50 | 51 | let 52 | # cursorId = ident "cursor" 53 | # parentId = ident "parent" 54 | dataId = genSym(nskType, "Data") 55 | 56 | 57 | var procDecl = newNProcDecl( 58 | name = "visitor", 59 | args = procArgs, 60 | returnType = some(returnType), 61 | exported = false, 62 | pragma = newNPragma("cdecl"), 63 | impl = ( 64 | quote do: 65 | let data {.inject.} = cast[ptr[`dataId`]](clientData) 66 | `dataUnpack` 67 | `body` 68 | ) 69 | ).toNNode() 70 | 71 | 72 | result = quote do: 73 | block: 74 | `immutableCopies` 75 | var data {.inject.} = `tupleData` 76 | type `dataId` = typeof(data) 77 | `procDecl` 78 | # proc visitor(`cursorId`, `parentId`: CXCursor, 79 | # clientData: pointer): CXChildVisitResult {.cdecl.} = 80 | 81 | (data, visitor) 82 | 83 | 84 | macro makeVisitor*(captureVars, body: untyped): untyped = 85 | ## Create `{.cdecl.}` callback for child visit. Macro head is a 86 | ## `[var1, var2, ...]` list - all variables that are available in 87 | ## the visitor body must be listed explicitly. 88 | ## 89 | ## .. code-block:: Nim 90 | ## 91 | ## var buf: seq[string] 92 | ## makeVisitor [unit, functionNames]: 93 | ## if cursor.cxKind == CXCursor_FunctionDecl: 94 | ## buf.add $cursor 95 | captureVars.assertNodeKind({nnkBracket}) 96 | result = makeVisitorImpl( 97 | toSeq(captureVars), 98 | procArgs = { 99 | "cursor" : newNType("CXCursor"), 100 | "parent" : newNType("CXCursor"), 101 | "clientData" : newNType("pointer"), 102 | }, 103 | returnType = newNType("CXChildVisitResult"), 104 | body 105 | ) 106 | 107 | # echo result.repr 108 | 109 | macro makeDeclarationIndexer*(captureVars, body: untyped): untyped = 110 | captureVars.assertNodeKind({nnkBracket}) 111 | result = makeVisitorImpl( 112 | toSeq(captureVars), 113 | procArgs = { 114 | "clientData" : newNType("CXClientData"), 115 | "idxDeclInfo" : newNType("ptr", @["CXIdxDeclInfo"]), 116 | }, 117 | returnType = newNType("void"), 118 | body 119 | ) 120 | -------------------------------------------------------------------------------- /old/src/hcparse/read_libclang/hc_depresolve.nim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haxscramper/hcparse/1e1a68a49192c0a3731ae3279be56c2a24542bb0/old/src/hcparse/read_libclang/hc_depresolve.nim -------------------------------------------------------------------------------- /old/src/hcparse/read_libclang/hc_genhelper.nim: -------------------------------------------------------------------------------- 1 | when false: 2 | ## The API is exactly as I want it, but due to IR breakages I temporarily 3 | ## commented things out, will fix later. 4 | type 5 | CErrorCodeKind = enum 6 | eckBadInteger 7 | eckErrorEnum 8 | 9 | SetLit = range[0 .. 65535] 10 | 11 | CErrorCode = object 12 | message*: string 13 | printArgs*: set[SetLit] 14 | case kind*: CErrorCodeKind 15 | of eckErrorEnum: 16 | enumIdent*: CScopedIdent 17 | 18 | of eckBadInteger: 19 | validRange*: Slice[cint] 20 | 21 | func negativeError*(message: string, printIdx: set[SetLit] = {}): CErrorCode = 22 | CErrorCode( 23 | message: message, 24 | kind: eckBadInteger, 25 | validRange: (cint(0) .. high(cint)), 26 | printArgs: printIdx 27 | ) 28 | 29 | func errorEnum*(path: CScopedIdent): CErrorCode = 30 | CErrorCode(kind: eckErrorEnum, enumIdent: path) 31 | 32 | 33 | proc errorCodesToException*( 34 | genProc: var GenProc, conf: WrapConf, cache: var WrapCache, 35 | errorMap: seq[(CSCopedIdent, CErrorCode)] 36 | ): seq[WrappedEntry] = 37 | 38 | for (ident, code) in errorMap: 39 | if sameNoGeneric(genProc.cdecl.ident, ident): 40 | var gen2 = deepCopy(genProc) 41 | genProc.name &= "Raw" 42 | gen2.noPragmas = gpcNoPragma 43 | 44 | var call = newPCall(genProc.name) 45 | for arg in genProc.arguments: 46 | call.add newPIdent(arg.name) 47 | 48 | let validRange = nnkInfix.newPTree( 49 | newPIdent(".."), 50 | newPCall("cint", newPLit(code.validRange.a)), 51 | newPCall("cint", newPLit(code.validRange.b)) 52 | ) 53 | 54 | case code.kind: 55 | of eckBadInteger: 56 | var msg = &"Return value of the {genProc.cdecl.cursor}" 57 | msg &= " is not in valid range - expected [" 58 | msg &= tern(code.validRange.a == low(cint), "low(cint)", $code.validRange.a) 59 | msg &= " .. " 60 | msg &= tern(code.validRange.b == high(cint), "high(cint)", $code.validRange.b) 61 | msg &= "], but got " 62 | 63 | var msg2 = ". " 64 | if code.message.len > 0: 65 | msg2 &= code.message & ". " 66 | 67 | var argList = newPStmtList() 68 | if code.printArgs.len > 0: 69 | msg2 &= tern(code.printArgs.len > 0, "Arguments were '", "Argument was '") 70 | 71 | var cnt = 0 72 | for idx, arg in gen2.arguments: 73 | if SetLit(idx) in code.printArgs: 74 | if cnt > 0: 75 | argList.add pquote(errMsg &= "', '") 76 | 77 | argList.add pquote(errMsg &= $(`newPIdent(arg.name)`)) 78 | inc cnt 79 | 80 | if cnt > 0: 81 | argList.add pquote(errMsg &= "'.") 82 | 83 | gen2.impl = some pquote do: 84 | result = `call` 85 | if result notin `validRange`: 86 | var errMsg = `msg` & $result & `msg2` 87 | `argList` 88 | raise newException(ValueError, errMsg) 89 | 90 | else: 91 | raiseImplementError("") 92 | 93 | return @[newWrappedEntry( 94 | gen2.toNNode(conf, cache).toNimDecl(), wepInProcs, currLInfo(), 95 | genProc.cdecl 96 | )] 97 | -------------------------------------------------------------------------------- /old/src/hcparse/read_libclang/header.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | class C; 7 | 8 | int get_number(int val) { 9 | return val + 1; 10 | } 11 | 12 | void func_pointer_test() { 13 | int (*func)(int) = &get_number; 14 | std::cout << " [ " << func(0) << " ] \n"; 15 | } 16 | 17 | class K 18 | { 19 | public: 20 | int get_number(int val) { 21 | return this->increment + val; 22 | } 23 | int increment = 0; 24 | }; 25 | 26 | void method_pointer_test() { 27 | K val; 28 | K* ptr = &val; 29 | val.increment = 10; 30 | 31 | int (K::*method_pointer)(int) = &K::get_number; 32 | 33 | 34 | std::cout << " [ " << (ptr->*method_pointer)(0) << " ] \n"; 35 | std::cout << " [ " << (val.*method_pointer)(0) << " ] \n"; 36 | } 37 | 38 | void void_ptr_test() { 39 | int var = 10; 40 | 41 | void* void_ptr = &var; 42 | int* int_ptr = &var; 43 | 44 | if (*static_cast(void_ptr) == var) { 45 | std::cout << void_ptr << "\n"; 46 | std::cout << int_ptr << "\n"; 47 | } 48 | } 49 | 50 | 51 | template 52 | T& scastp(void* arg) { 53 | return *static_cast(arg); 54 | } 55 | 56 | using signal_msg = void*; 57 | 58 | using slot_func = void (C::*)(signal_msg); 59 | using signal_func = void (C::*)(signal_msg); 60 | 61 | template 62 | slot_func slot_cast(void (D::*func)(signal_msg)) { 63 | return static_cast(func); 64 | } 65 | 66 | template 67 | signal_func signal_cast(void (D::*func)(signal_msg)) { 68 | return static_cast(func); 69 | } 70 | 71 | 72 | struct signal_compare { 73 | bool operator()(const signal_func& lhs, const signal_func& rhs) { 74 | return std::memcmp(&lhs, &rhs, sizeof(lhs)) < 0; 75 | } 76 | }; 77 | 78 | using signal_map = std::multimap< 79 | signal_func, // 80 | std::pair, // 81 | signal_compare>; 82 | 83 | using signal_iter = signal_map::iterator; 84 | 85 | 86 | class C 87 | { 88 | public: 89 | void set_connection(signal_func signal, C* target, slot_func slot) { 90 | connects.insert({signal, {target, slot}}); 91 | } 92 | 93 | void emit_signal(signal_func signal, signal_msg data) { 94 | std::pair 95 | equal_range = connects.equal_range(signal); 96 | 97 | for (signal_iter slot = equal_range.first; 98 | slot != equal_range.second; 99 | ++slot) { 100 | 101 | C* target = slot->second.first; 102 | signal_func signal = slot->second.second; 103 | 104 | (target->*signal)(data); 105 | } 106 | } 107 | 108 | 109 | public: 110 | void signal_1(signal_msg arg) { 111 | std::cout << "Executed signal 1\n"; 112 | emit_signal(&C::signal_1, arg); 113 | } 114 | 115 | void signal_2(signal_msg arg) { 116 | std::cout << "Executed signal 2\n"; 117 | emit_signal(&C::signal_2, arg); 118 | } 119 | 120 | public: 121 | void slot_1(signal_msg _arg) { 122 | std::string& arg = scastp(_arg); 123 | std::cout << "Called slot 1: " << arg; 124 | } 125 | 126 | void slot_2(signal_msg arg) { 127 | std::cout << "Called slot 2: " << scastp(arg); 128 | } 129 | 130 | private: 131 | signal_map connects; 132 | }; 133 | 134 | 135 | #define connect(emitter, signal, target, slot) \ 136 | (emitter)->set_connection( \ 137 | static_cast(signal), \ 138 | target, \ 139 | static_cast(slot)) 140 | 141 | /** 142 | * A parsed comment. 143 | */ 144 | void signal_slots_test() { 145 | std::cout << "test 2\n\n\n"; 146 | 147 | C emitter; 148 | C reciever; 149 | 150 | std::string arg = "argument string\n"; 151 | 152 | connect(&emitter, &C::signal_2, &reciever, &C::slot_2); 153 | 154 | std::cout << "testing signal 2\n"; 155 | emitter.signal_2(&arg); 156 | 157 | std::cout << "testing signal 1\n"; 158 | emitter.signal_1(&arg); 159 | } 160 | 161 | 162 | int main() { 163 | func_pointer_test(); 164 | method_pointer_test(); 165 | 166 | void_ptr_test(); 167 | 168 | signal_slots_test(); 169 | } 170 | -------------------------------------------------------------------------------- /old/src/hcparse/read_libclang/libclang_extensions.cpp: -------------------------------------------------------------------------------- 1 | // #include 2 | #include "cxcursor.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | using namespace clang; 20 | using namespace clang::cxcursor; 21 | // using namespace clang::cxtu; 22 | // using namespace clang::cxindex; 23 | 24 | static const IdentifierInfo* getMacroIdentifier(CXCursor C) { 25 | if (C.kind == CXCursor_MacroDefinition) { 26 | if (const MacroDefinitionRecord* MDR = getCursorMacroDefinition( 27 | C)) { 28 | return MDR->getName(); 29 | } 30 | } else if (C.kind == CXCursor_MacroExpansion) { 31 | MacroExpansionCursor ME = getCursorMacroExpansion(C); 32 | return ME.getName(); 33 | } 34 | return nullptr; 35 | } 36 | 37 | 38 | int clang_Cursor_getParamNum(CXCursor C) { 39 | const IdentifierInfo* II = getMacroIdentifier(C); 40 | if (!II) { 41 | return -1; 42 | } 43 | ASTUnit* ASTU = getCursorASTUnit(C); 44 | Preprocessor& PP = ASTU->getPreprocessor(); 45 | if (const MacroInfo* MI = PP.getMacroInfo(II)) { 46 | return MI->getParameterNum(II); 47 | } 48 | return -1; 49 | } 50 | 51 | int main() { 52 | } 53 | 54 | // static inline QualType GetQualType(CXType CT) { 55 | // return QualType::getFromOpaquePtr(CT.data[0]); 56 | // } 57 | 58 | // CXType clang_DependentVectorType_GetSizeExpr(CXType CT) { 59 | // Expr* EC; 60 | // QualType T = GetQualType(CT); 61 | // const Type* TP = T.getTypePtrOrNull(); 62 | // if (TP) { 63 | // switch (TP->getTypeClass()) { 64 | // case Type::DependentSizedArray: 65 | // EC = cast(TP)->getSizeExpr(); 66 | // break; 67 | // default: break; 68 | // } 69 | // } 70 | // return cxcursor::MakeCXCursor( 71 | // EC, getCursorDecl(c), cxcursor::getCursorTU(EC)); 72 | // } 73 | -------------------------------------------------------------------------------- /old/src/hcparse/read_libclang/libclang_extensions.nim: -------------------------------------------------------------------------------- 1 | {.compile: "libclang_extensions.cpp".} 2 | 3 | -------------------------------------------------------------------------------- /old/src/hcparse/read_libclang/readme.org: -------------------------------------------------------------------------------- 1 | *raw* bindings for libclang - no functions were renamed, no 2 | preprocessing, nothing. Directly corresponds to code in 3 | ~/usr/include/clang-c/*~ (clang ~v10.0.1~) 4 | -------------------------------------------------------------------------------- /old/src/nim.cfg: -------------------------------------------------------------------------------- 1 | --warning[UnusedImport]:off 2 | --warning[User]:off 3 | --warning[UnsafeSetLen]:off 4 | -------------------------------------------------------------------------------- /old/src/test.cpp: -------------------------------------------------------------------------------- 1 | #define ABCD 2 2 | 3 | #pragma STDC FENV_ACCESS 4 | #define EE(X) #X## #X 5 | 6 | #ifdef ABCD 7 | struct A {}; 8 | #else 9 | struct B {}; 10 | #endif 11 | 12 | #ifndef ABCD 13 | A ee() { 14 | } 15 | #elif ABCD == 2 16 | A* ee2() { 17 | } 18 | #else 19 | A ee3() { 20 | } 21 | #endif 22 | 23 | #if !defined(DCBA) && (ABCD < 2 * 4 - 3) 24 | A* ee4() { 25 | } 26 | #endif 27 | 28 | 29 | int main() { 30 | } 31 | -------------------------------------------------------------------------------- /old/tests/.gdbinit: -------------------------------------------------------------------------------- 1 | set print address off 2 | set print frame-arguments presence 3 | watch framePtr__HRfVMH3jYeBJz6Q6X9b6Ptw->calldepth < -2000 4 | run 5 | bt 6 | -------------------------------------------------------------------------------- /old/tests/.gitignore: -------------------------------------------------------------------------------- 1 | resnim.nim 2 | -------------------------------------------------------------------------------- /old/tests/__tQWindow.nim: -------------------------------------------------------------------------------- 1 | import 2 | hnimast/interop/wrap_macros, 3 | hmisc/core/all, 4 | hmisc/other/oswrap 5 | 6 | static: 7 | startHaxComp() 8 | 9 | {.passc: "-fPIC".} 10 | {.passc: "-I/usr/include/qt".} 11 | {.passc: "-I/usr/include/qt/QtGui".} 12 | {.passc: "-I/usr/include/qt/QtWidgets".} 13 | 14 | {.passl: "-lQt5Gui".} 15 | {.passl: "-lQt5Core".} 16 | {.passl: "-lQt5Widgets".} 17 | 18 | wrapheader "": 19 | class QWidget 20 | 21 | wrapheader "": 22 | class QTextEdit of QWidget: 23 | proc newQTextEdit(parent: ptr QWidget): ptr QTextEdit {.constructor.} 24 | 25 | wrapheader "": 26 | class QMainWindow of QWidget: 27 | proc newQMainWindow(): ptr QMainWindow {.constructor.} 28 | proc show() 29 | proc setFixedSize(w: int, h: int) 30 | proc setCentralWidget(widget: ptr QWidget) 31 | 32 | wrapheader "": 33 | class QApplication: 34 | proc newQApplication(argc: cint, argv: cstringArray): 35 | ptr QApplication {.constructor.} 36 | 37 | proc exec() 38 | 39 | static: startHaxComp() 40 | 41 | cgen "${cacheDir}/${file}": 42 | include "" 43 | 44 | class DerivedEditor of QTextEdit: 45 | proc textChangedSlot() {.slot.} = 46 | echo "Signal derived changed" 47 | 48 | proc new(parent: ptr QWidget): ptr DerivedEditor 49 | {.constructor(QTextEdit(parent)).} 50 | 51 | template connect*[A, B]( 52 | a: ptr A, signal: untyped{nkIdent}, 53 | b: ptr B, slot: untyped{nkIdent} 54 | ): untyped = 55 | 56 | const 57 | signalPtr = "&" & $typeof(a[]) & "::" & astToStr(signal) 58 | slotPtr = "&" & $typeof(b[]) & "::" & astToStr(slot) 59 | 60 | block: 61 | let 62 | inA {.inject.} = a 63 | inB {.inject.} = b 64 | 65 | // "Emit QObject connect start" 66 | {.emit: "QObject::connect(`inA`, " & signalPtr & ", `inB`, " & slotPtr & ");".} 67 | // "End connect" 68 | 69 | 70 | 71 | import hmisc/shellexec/xephyr 72 | 73 | proc main() = 74 | withXephyr(): 75 | var 76 | argc: cint = 0 77 | argv: cstringarray 78 | 79 | // "QApplication" 80 | var app: ptr QApplication = newQApplication(argc, argv) 81 | 82 | // "QMainWindow" 83 | var window: ptr QMainWindow = newQMainWindow() 84 | 85 | // "Derived editor" 86 | var edit: ptr DerivedEditor = newDerivedEditor(nil) 87 | 88 | window[].setFixedSize(320, 320) 89 | window[].show() 90 | window[].setCentralWidget(edit) 91 | 92 | connect(edit, textChanged, edit, textChangedSlot) 93 | app[].exec() 94 | 95 | if not defined(haxTestall): 96 | main() 97 | -------------------------------------------------------------------------------- /old/tests/ccode.yaml: -------------------------------------------------------------------------------- 1 | - 2 | name: "Structure import" 3 | comment: |- 4 | Import struct from header file and wrap field 5 | 6 | cfiles: 7 | - filename: "cppfile.hpp" 8 | contents: | 9 | struct Test { int val; }; 10 | nimfiles: 11 | - filename: "importer.nim" 12 | contents: | 13 | import cppfile 14 | var test: Test 15 | test.val = 12 16 | - 17 | name: "Single method" 18 | comment: |- 19 | Wrap class method 20 | 21 | cfiles: 22 | - filename: "cppfile.hpp" 23 | contents: | 24 | class Q { 25 | public: 26 | int a; 27 | void hhh() { a += 2; }; 28 | int qq() { return 1; }; 29 | }; 30 | nimfiles: 31 | - filename: "importer.nim" 32 | contents: | 33 | import cppfile 34 | var q: Q 35 | q.hhh() 36 | echo q.qq() 37 | stdout: |- 38 | 1 39 | - 40 | name: "Includes" 41 | cfiles: 42 | - filename: "cppfile.hpp" 43 | contents: | 44 | #include 45 | int function() { return 12; } 46 | 47 | nimfiles: 48 | - filename: "importer.nim" 49 | contents: | 50 | import cppfile 51 | echo function() 52 | stdout: |- 53 | 1 54 | - 55 | name: "Namespaces & includes" 56 | cfiles: 57 | - filename: "cppfile.hpp" 58 | contents: | 59 | #include 60 | 61 | namespace Q { 62 | class Z { 63 | public: 64 | void hello() const { 65 | std::cout << "Hello from C++ code"; 66 | }; 67 | }; 68 | } 69 | 70 | nimfiles: 71 | - filename: "importer.nim" 72 | contents: | 73 | import cppfile 74 | let z = QZ() # Imported from namespace `Q::Z` 75 | z.hello() 76 | 77 | stdout: |- 78 | Hello from C++ code 79 | 80 | - 81 | name: "Porting operators" 82 | cfiles: 83 | - filename: "cppfile.hpp" 84 | contents: | 85 | #include 86 | 87 | class Z { 88 | public: 89 | int a; 90 | void operator+=(const Z& rhs) { a += rhs.a; } 91 | }; 92 | nimfiles: 93 | - filename: "importer.nim" 94 | contents: | 95 | import cppfile 96 | var z = Z(a: cint 12) 97 | z += Z(a: cint 22) 98 | echo z.a 99 | stdout: |- 100 | 34 101 | - 102 | name: "Template class wrap" 103 | cfiles: 104 | - filename: "cppfile.hpp" 105 | contents: | 106 | #include 107 | #include 108 | 109 | template 110 | class Z { 111 | public: 112 | void getParam() const { 113 | std::cout << "Template parameter name [" << 114 | typeid(T).name() << "] \n"; 115 | } 116 | }; 117 | 118 | nimfiles: 119 | - filename: "importer.nim" 120 | contents: | 121 | import cppfile 122 | let z = Z[tuple[a: int, b: float]]() 123 | z.getParam() 124 | - 125 | name: "Imported class" 126 | comment: | 127 | Main file that we are interseted in wrapping Public API uses type 128 | `D` that was imported from another header. In order to compile 129 | wraper we must know how this type is defined (where it is imported 130 | from etc.) or treat it as opaque handle - e.g provide no 131 | implementation except for `type D {.importcpp: "someheader".} = 132 | object` 133 | cfiles: 134 | - filename: "cppmain.hpp" 135 | contents: | 136 | #include "dependency.hpp" 137 | class Q { public: D dep; }; 138 | - filename: "dependency.hpp" 139 | contents: | 140 | class D { public: int d; }; 141 | nimfiles: 142 | - filename: "importer.nim" 143 | contents: | 144 | import cppmain 145 | var q: Q 146 | echo typeof q.dep 147 | 148 | assert not compiles((var tmp: D)) 149 | import dependency 150 | assert compiles((var tmp: D)) 151 | - 152 | name: "Multiple dependencies" 153 | cfiles: 154 | - filename: "cppmain.hpp" 155 | contents: | 156 | #pragma once 157 | // Internal implementation dependency 158 | #include "header0.hpp" 159 | 160 | // External API dendendencies 161 | #include "header1.hpp" 162 | #include "header2.hpp" 163 | 164 | class Q { D0 dep0; public: D1 dep1; D2 dep2; }; 165 | - filename: "header0.hpp" 166 | contents: | 167 | #pragma once 168 | class D0 { public: int i; }; 169 | - filename: "header1.hpp" 170 | contents: | 171 | #pragma once 172 | class D1 { public: int i; }; 173 | - filename: "header2.hpp" 174 | contents: | 175 | #pragma once 176 | class D2 { public: int i; }; 177 | nimfiles: 178 | - 179 | filename: "importer.nim" 180 | contents: | 181 | import cppmain 182 | var q: Q 183 | echo typeof q.dep1.i 184 | echo q.dep2.i 185 | - 186 | name: "Multifile" 187 | cfiles: 188 | - 189 | filename: "public0.hpp" 190 | contents: | 191 | // Contents of this file can be see from at least two 192 | // elements in public API. You can use `Public0` by including 193 | // either "public0" or "public1" (although second one is not 194 | // advised to, since it is not clear where type comes from) 195 | #pragma once 196 | struct Public0 {}; 197 | - 198 | filename: "public1.hpp" 199 | contents: | 200 | #pragma once 201 | #include "public0.hpp" 202 | struct Public1 {}; 203 | nimfiles: 204 | - 205 | filename: "alluser.nim" 206 | contents: | 207 | # Since original API is split into two files two nim wrappers will be 208 | # created. 209 | import public0 210 | import public1 211 | 212 | var pub0: Public0 213 | var pub1: Public1 214 | 215 | - 216 | filename: "public0_user.nim" 217 | contents: | 218 | import public0 219 | var pub0: Public0 220 | 221 | - 222 | filename: "public1_user.nim" 223 | contents: | 224 | import public1 225 | var pub1: Public1 226 | 227 | - 228 | name: "Single internal" 229 | comment: | 230 | Internal class reused in two API units 231 | cfiles: 232 | - 233 | filename: "internal.hpp" 234 | internal: true 235 | contents: | 236 | #pragma once 237 | struct Intern {}; 238 | - filename: "user-a.hpp" 239 | contents: | 240 | #pragma once 241 | #include "internal.hpp" 242 | Intern getVal1() {} 243 | nimfiles: 244 | - filename: "userA.nim" 245 | contents: | 246 | import user_a, std/os 247 | let val: Intern = getVal1() 248 | assert not fileExists("internla.nim") 249 | - 250 | name: "Internal reuse" 251 | comment: | 252 | Internal class reused in two API units 253 | cfiles: 254 | - 255 | filename: "internal.hpp" 256 | internal: true 257 | contents: | 258 | #pragma once 259 | struct Intern {}; 260 | - filename: "user-a.hpp" 261 | contents: | 262 | #pragma once 263 | #include "internal.hpp" 264 | Intern getVal1() {} 265 | - filename: "user-b.hpp" 266 | contents: | 267 | #pragma once 268 | #include "internal.hpp" 269 | Intern getVal2() {} 270 | nimfiles: 271 | - 272 | filename: "internUser.nim" 273 | contents: | 274 | import internal 275 | var test: Intern 276 | - filename: "userA.nim" 277 | contents: | 278 | import user_a 279 | let val: Intern = getVal1() 280 | - filename: "userB.nim" 281 | contents: | 282 | import user_b 283 | let val: Intern = getVal2() 284 | - 285 | name: "Forward typedef" 286 | forceFirst: 10 287 | comment: | 288 | Forward declaration of the typedef, for API unit split across 289 | multiple files (aka `std::string`-like). First forwar declare 290 | template class and create typedefs, then actually define class. 291 | C++ is such a nice language, right? And this is how stdlib shipped 292 | with GCC is written. Fucking piece of trash 293 | cfiles: 294 | - 295 | filename: "typedefs.hpp" 296 | internal: true 297 | contents: | 298 | #pragma once 299 | template struct Temp; 300 | using Using = Temp; 301 | - filename: "definition.hpp" 302 | internal: true 303 | contents: | 304 | # pragma once 305 | template struct Temp { T fld; }; 306 | - filename: "mainapi.hpp" 307 | contents: | 308 | # pragma once 309 | #include "definition.hpp" 310 | #include "typedefs.hpp" 311 | nimfiles: 312 | - 313 | filename: "apiuser.nim" 314 | contents: | 315 | import mainapi 316 | var us: Using 317 | var tm: Temp[string] 318 | -------------------------------------------------------------------------------- /old/tests/files/libgit_test/stdcopy.h: -------------------------------------------------------------------------------- 1 | 0xff00000000000000ull 2 | -------------------------------------------------------------------------------- /old/tests/files/libgit_test/types.h: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | -------------------------------------------------------------------------------- /old/tests/files/wavereader_main.h: -------------------------------------------------------------------------------- 1 | #include "wavereader_subcontext.h" 2 | subcontext_object_like 3 | -------------------------------------------------------------------------------- /old/tests/files/wavereader_subcontext.h: -------------------------------------------------------------------------------- 1 | #define subcontext_object_like 2 | #define function_like(arg) #arg 3 | -------------------------------------------------------------------------------- /old/tests/header.hpp: -------------------------------------------------------------------------------- 1 | enum E 2 | { 3 | V1 = 12, 4 | V2 = 12 5 | }; 6 | -------------------------------------------------------------------------------- /old/tests/incpp.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define A int 7 | #define B(arg) #arg 8 | #define C(arg, arg2) #arg## #arg2 9 | #define D(arg) "hhhh"## #arg 10 | 11 | #ifdef HELLO 12 | # define world 12 13 | #else 14 | # define world 0 15 | #endif 16 | 17 | 18 | using const_int = const int; 19 | 20 | template 21 | class Base 22 | { 23 | public: 24 | int fld; 25 | const_int fld2; 26 | void hell() {} 27 | }; 28 | 29 | template 30 | class Base2 31 | { 32 | public: 33 | void fuck() {} 34 | }; 35 | 36 | template 37 | class A 38 | : Base 39 | , Base2 40 | { 41 | public: 42 | int b; 43 | std::vector ss; 44 | 45 | A() {} 46 | ~A() {} 47 | A(int a) {} 48 | 49 | // template 50 | // struct MoreGeneric { 51 | // TNested field; 52 | // }; 53 | 54 | void operator<<(T arg) {} 55 | 56 | #if false 57 | void operator*(int v) {} 58 | void operator/(int v) {} 59 | void operator%(int v) {} 60 | void operator^(int v) {} 61 | void operator&(int v) {} 62 | void operator|(int v) {} 63 | void operator~() {} 64 | void operator!() {} 65 | void operator=(int v) {} 66 | void operator<(int v) {} 67 | void operator>(int v) {} 68 | void operator+=(int v) {} 69 | void operator-=(int v) {} 70 | void operator*=(int v) {} 71 | void operator/=(int v) {} 72 | void operator%=(int v) {} 73 | void operator^=(int v) {} 74 | void operator&=(int v) {} 75 | void operator|=(int v) {} 76 | void operator<<(int a) {} 77 | void operator>>(int a) {} 78 | void operator>>=(int a) {} 79 | void operator<<=(int a) {} 80 | void operator==(int a) {} 81 | void operator!=(int a) {} 82 | void operator<=(int a) {} 83 | void operator>=(int b) {} 84 | void operator&&(int b) {} 85 | void operator||(int b) {} 86 | void operator++(int b) {} 87 | void operator--(int b) {} 88 | void operator,(int b) {} 89 | void operator->*(int c) {} 90 | void operator->() {} 91 | void operator()(int b) {} 92 | void operator[](int b) {} 93 | 94 | #endif 95 | }; 96 | 97 | 98 | char operator/(std::vector c, int v) {} 99 | char operator%(std::vector c, int v) {} 100 | 101 | typedef int(GetSyncData)(double, double*, double, int, int, int, void*); 102 | 103 | struct S {}; 104 | 105 | S operator""_S(const char* s, unsigned long len) { return S(); } 106 | void operator"" _km(long double); // OK, will be called for 1.0_km 107 | int operator"" _i18n(const char*, unsigned long); // OK 108 | 109 | float operator""_e(const char*); // OK 110 | 111 | 112 | namespace cxx { 113 | struct B; 114 | 115 | inline namespace __impl12 { 116 | struct S { 117 | enum class C 118 | { 119 | Hello = 33, 120 | World = 12, 121 | Nice = 13, 122 | HHHZ, 123 | ZZZZ = 13 124 | }; 125 | B* s; 126 | }; 127 | } // namespace __impl12 128 | 129 | void operator*(S a, S b) {} 130 | 131 | struct B { 132 | void hello() {} 133 | static void explode(B b, S s) {} 134 | B() {} 135 | }; 136 | 137 | } // namespace cxx 138 | 139 | void usesEnum(cxx::S::C en, cxx::S other) {} 140 | 141 | struct CppBase { 142 | CppBase(const char* args) { 143 | printf("Non-default constructor -%s\n", args); 144 | } 145 | 146 | virtual void baseMethod(int arg) { 147 | printf("arg from nim - %d -\n", arg); 148 | } 149 | 150 | virtual void baseMethod2() { printf("baseMethod2()\n"); } 151 | }; 152 | 153 | // TODO default initalization of template 154 | 155 | #include 156 | 157 | 158 | struct H { 159 | int field; 160 | H(int arg); 161 | H(std::initializer_list ilist); 162 | }; 163 | 164 | struct Aggr { 165 | int field1; 166 | char field2; 167 | }; 168 | 169 | struct Aggr2 { 170 | Aggr aggr; 171 | float field3; 172 | }; 173 | 174 | void test0(H nice); 175 | void test1(H nice = 12); 176 | void test2(H nice = {1, 2, 3}); 177 | void test3(Aggr aggr = {1, 'c'}); 178 | void test4(Aggr2 aggr = {{1, 'c'}, 1.2}); 179 | void test5(Aggr2 aggr = {Aggr({1, 'c'}), 1.2}); 180 | 181 | #if false 182 | 183 | template 184 | struct Templated { 185 | T arg1; 186 | T arg2; 187 | }; 188 | 189 | template 190 | void test6(Templated = {12, 12}) {} 191 | 192 | #endif 193 | 194 | #include 195 | 196 | template 197 | struct HashIterator 198 | { 199 | typedef T* pointer; 200 | typedef T& reference; 201 | typedef T valueType; 202 | 203 | reference operator()(const T){} 204 | reference operator++(); 205 | 206 | bool operator!=(const T& other) {} 207 | bool operator==(const T& other) {} 208 | }; 209 | 210 | template 211 | class HashImpl { 212 | typedef HashIterator iterator; 213 | 214 | public: 215 | iterator begin() {} 216 | iterator end() {} 217 | }; 218 | 219 | template 220 | class Set { 221 | HashImpl table; 222 | 223 | public: 224 | Set(std::initializer_list ilist) {} 225 | }; 226 | -------------------------------------------------------------------------------- /old/tests/nim.cfg: -------------------------------------------------------------------------------- 1 | --path="$config/../src" 2 | 3 | --warning[ProveInit]:off 4 | #--warning[UnusedImport]:off 5 | --warning[UnsafeSetLen]:off 6 | --warning[UnreachableCode]:off 7 | #--showAllMismatches:on 8 | -d:ssl 9 | #--debugger:native 10 | --passc:"-g" 11 | --linetrace:on 12 | #--stacktrace:off 13 | --cc:gcc 14 | #--hint[XDeclaredButNotUsed]:on 15 | #--hints:on -------------------------------------------------------------------------------- /old/tests/runall.nim: -------------------------------------------------------------------------------- 1 | import hmisc/preludes/project_tasks 2 | -------------------------------------------------------------------------------- /old/tests/sfinae_header.hpp: -------------------------------------------------------------------------------- 1 | #define WIP 0 2 | 3 | template 4 | struct test {}; 5 | 6 | template 7 | struct integral_constant { 8 | #if WIP 9 | static const Tp value = v; 10 | typedef Tp value_type; 11 | typedef integral_constant type; 12 | #endif 13 | typedef test> test_t; 14 | }; 15 | 16 | #if WIP 17 | 18 | template 19 | struct enable_if {}; 20 | 21 | template 22 | struct enable_if { 23 | typedef T type; 24 | }; 25 | 26 | typedef integral_constant true_type; 27 | typedef integral_constant false_type; 28 | 29 | // clang-format off 30 | template struct remove_const { typedef Tp type; }; 31 | template struct remove_const { typedef Tp type; }; 32 | template struct remove_volatile { typedef Tp type; }; 33 | template struct remove_volatile { typedef Tp type; }; 34 | // clang-format on 35 | 36 | template 37 | struct remove_cv { 38 | typedef typename remove_const::type>::type 39 | type; 40 | }; 41 | 42 | template 43 | struct is_integral_helper : public false_type {}; 44 | 45 | template <> 46 | struct is_integral_helper : public integral_constant {}; 47 | 48 | 49 | template 50 | struct is_integral 51 | : public integral_constant< 52 | bool, 53 | (is_integral_helper::type>::value)> {}; 54 | 55 | 56 | template < 57 | class T, 58 | typename enable_if::value, bool>::type* = nullptr> 59 | int sfinae_overload(T t) { 60 | } 61 | 62 | 63 | template 64 | float sfinae_overload(T t) { 65 | } 66 | 67 | 68 | // template < 69 | // class T, 70 | // typename enable_if< 71 | // is_floating_point::value, bool 72 | // >::type* = nullptr 73 | // > 74 | // sfinaeOverload() { 75 | // std::cout << "Calling floating point type function\n"; 76 | // } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /old/tests/tBoostWaveExecute.nim: -------------------------------------------------------------------------------- 1 | import hcparse/read_boost_wave/boost_wave 2 | import hmisc/core/all 3 | import std/[strformat, sequtils, strutils] 4 | import hmisc/types/colorstring 5 | import hmisc/algo/[clformat, hstring_algo] 6 | import hmisc/preludes/unittest 7 | 8 | suite "Test expansion hooks": 9 | test "Allhooks": 10 | var ctx = newWaveContext( 11 | lit3""" 12 | #define concat(a, b) a ## b 13 | #warning "123" 14 | #if 1 15 | call1(); 16 | #else 17 | call2(); 18 | #endif 19 | #include 20 | 21 | #define ABC (X+Y) 22 | #define X 100 23 | #define Y 50 24 | #define MUL(x,y) ((x)*(y)) 25 | ABC 26 | MUL(MUL(1,2),3) 27 | 28 | """) 29 | 30 | var indent = 16 31 | ctx.onFoundWarningDirective(): 32 | echo toYellow("warning" |<< indent), wrap($message, CharBrace.doubleCurly) 33 | return EntryHandlingSkip 34 | 35 | ctx.onEvaluatedConditionalExpression(): 36 | echo hshow(directive.kind) |<< indent, toCyan($directive & " " & $expression), 37 | " = ", expressionValue 38 | 39 | ctx.onFoundIncludeDirective(): 40 | echo toBlue("#include" |<< indent), $impl 41 | return EntryHandlingSkip 42 | 43 | ctx.onSkippedToken(): 44 | stdout.write hshow(token.kind) |<< indent, " skip " 45 | if token.kind in {tokIdNewline}: 46 | echo wrap("\\n", CharBrace.doubleSquare) 47 | 48 | else: 49 | echo wrap($token, CharBrace.doubleSquare) 50 | 51 | ctx.onDefinedMacro(): 52 | echo toGreen("#define" |<< indent), name 53 | for item in items(parameters): 54 | echo " " |<< indent, hshow(item.kind) |<< 16, wrap($item, CharBrace.doubleAngle) 55 | 56 | echo toGreen("as") |>> indent 57 | for item in items(definition): 58 | echo " " |<< indent, hshow(item.kind) |<< 16, wrap($item, CharBrace.doubleAngle) 59 | 60 | ctx.onExpandingFunctionLikeMacro(): 61 | echo " " |<< indent, "expanding function-like macro", $macrodef 62 | inc indent, 2 63 | 64 | ctx.onExpandingObjectLikeMacro(): 65 | echo " " |<< indent, "expanding object-like macro ", $argmacro 66 | inc indent, 2 67 | 68 | ctx.onExpandedMacro(): 69 | echo " " |<< indent, 70 | "expanded macro to", 71 | clformat.joinc(mapIt(result, clt($it)), " ") 72 | 73 | dec indent, 2 74 | 75 | ctx.onRescannedMacro(): 76 | echo " " |<< indent, 77 | "rescanned macro to", 78 | clformat.joinc(mapIt(result, clt($it)), " ") 79 | 80 | dec indent, 2 81 | 82 | ctx.onEmitLineDirective(): 83 | return true 84 | 85 | for tok in items(ctx, false): 86 | echo hshow(tok.kind()) |<< indent, " real ", hshow(tok.getValue()) 87 | 88 | suite "Iterate over tokens": 89 | var ctx = newWaveContext(""" 90 | #if 1 91 | test1 92 | #else 93 | test2 94 | #endif 95 | """) 96 | 97 | var toks: seq[(WaveTokId, string)] 98 | 99 | var hookOverrideTriggered = false 100 | 101 | ctx.onEvaluatedConditionalExpression(): 102 | hookOverrideTriggered = true 103 | 104 | ctx.allTokens() do (skipped: bool, tok: ptr WaveTokenHandle): 105 | toks.add((tok.kind, $tok)) 106 | 107 | assert hookOverrideTriggered 108 | pprint toks 109 | 110 | suite "Get expanded text": 111 | test "Simple token": 112 | var ctx = newWaveContext("test()") 113 | check ctx.getExpanded().strip() == "test()" 114 | 115 | test "Get expanded with macros": 116 | var ctx = newWaveContext(""" 117 | #if defined(_MSC_VER) 118 | # define GIT_CALLBACK(name) (__cdecl *name) 119 | #else 120 | # define GIT_CALLBACK(name) (*name) 121 | #endif 122 | void GIT_CALLBACK(free)(git_writestream *stream); 123 | """) 124 | 125 | check ctx.getExpanded().strip() == "void (*free)(git_writestream *stream);" 126 | 127 | test "Get expanded with explicitly defined macros": 128 | var ctx = newWaveContext("GIT_CALLBACK(free)(git_writestream *stream);") 129 | check: 130 | ctx.addMacroDefinition("GIT_CALLBACK(name)=(*name)") 131 | ctx.getExpanded().strip() == "(*free)(git_writestream *stream);" 132 | 133 | test "Get expanded with explicitly defined macros via overload": 134 | var ctx = newWaveContext("GIT_CALLBACK(free)(git_writestream *stream);") 135 | ctx.addMacroDefinition("GIT_CALLBACK", @["name"], some "(*name)") 136 | check: 137 | ctx.getExpanded().strip() == "(*free)(git_writestream *stream);" 138 | 139 | test "Object macro definition": 140 | var ctx = newWaveContext("sys_macro") 141 | ctx.addMacroDefinition("sys_macro", @[], some "expanded") 142 | 143 | var expandedMacro = false 144 | ctx.onExpandingObjectLikeMacro(): 145 | expandedMacro = true 146 | 147 | return EntryHandlingProcess 148 | 149 | check: 150 | ctx.getExpanded().strip() == "expanded" 151 | expandedMacro == true 152 | 153 | suite "Language mode handling": 154 | test "No 'ull' literals": 155 | var context = newWaveContext("0xff00000000000000ull\n", languageMode = {}) 156 | context.skipAll() 157 | check context.hasWarnings() 158 | let diag = context.popDiag() 159 | check diag.code == wekLexerInvalidLongLongLiteral 160 | 161 | test "support 'ull' literals": 162 | var context = newWaveContext("0xff00000000000000ull\n") 163 | context.skipAll() 164 | check not context.hasWarnings() 165 | 166 | suite "Include directive handling": 167 | test "Raised exception for invalid include": 168 | 169 | expect WaveError as ewave: 170 | var ctx = newWaveContext("#include \"asdf.h\"") 171 | for tok in items(ctx): 172 | discard tok 173 | 174 | check ewave.diag.code == wekBadIncludeFile 175 | 176 | test "Ignore include": 177 | var ctx = newWaveContext("#include \"asdf.h\"\n") 178 | 179 | var trigger = "" 180 | 181 | ctx.onFoundIncludeDirective(): 182 | trigger = $impl 183 | return EntryHandlingSkip 184 | 185 | for tok in ctx: 186 | discard 187 | 188 | check trigger == "\"asdf.h\"" 189 | 190 | suite "Comment handling": 191 | test "Trailing comment": 192 | var ctx = newWaveContext("int var; /* Trailing */\n") 193 | check ctx.getExpanded().strip() == "int var; /* Trailing */" 194 | 195 | test "Trailing CPP comment": 196 | skip() 197 | 198 | let txt = "// some c++ comment\n" 199 | var ctx = newWaveContext(txt) 200 | check ctx.getExpanded() == txt 201 | 202 | test "Multiline comments": 203 | skip() 204 | let txt = """ 205 | /** 206 | * Submodule ignore values 207 | * 208 | */ 209 | typedef enum { 210 | GIT_SUBMODULE_IGNORE_UNSPECIFIED = -1, /**< use the submodule's configuration */ 211 | } git_submodule_ignore_t; 212 | """ 213 | var ctx = newWaveContext(txt) 214 | check ctx.getExpanded() == txt 215 | -------------------------------------------------------------------------------- /old/tests/tBoostWaveGenerate.nim: -------------------------------------------------------------------------------- 1 | import hmisc/preludes/unittest 2 | 3 | import 4 | compiler/ast/[ast, renderer], 5 | hcparse, 6 | hmisc/other/hpprint, 7 | hmisc/algo/[namegen, hstring_algo], 8 | hmisc/other/[oswrap, hshell], 9 | hmisc/core/all 10 | 11 | import std/[options, sets] 12 | 13 | let dir = AbsDir(relToSource"../src/hcparse/read_boost_wave") 14 | 15 | startHax() 16 | 17 | suite "Generate wave file": 18 | let bindDl = false 19 | test "Boost wave C API": 20 | let fixConf = baseFixConf.withIt do: 21 | it.libName = "wave" 22 | it.typeStore = newTypeStore() 23 | 24 | it.onFixName(): 25 | if cache.knownRename(name.nim): 26 | return cache.getRename(name.nim) 27 | 28 | if ?context[cancLibName] and name.context == cncProc: 29 | result = name.nim.dropNormPrefix(context[cancLibName].get().nim) 30 | 31 | else: 32 | result = name.nim 33 | 34 | result = fixContextedName(name, result) 35 | cache.newRename(name.nim, result) 36 | 37 | 38 | it.onGetBind(): 39 | if entry of cekProc: 40 | if bindDL: 41 | cxxDynlibVar("cwaveDl") 42 | 43 | else: 44 | cxxLinkBind() 45 | 46 | else: 47 | cxxHeader("wave_c_api.h") 48 | 49 | 50 | let res = dir /. "boost_wave_wrap_tmp.nim" 51 | 52 | var codegen = cCodegenConf.withIt do: 53 | it.nameStyle = idsCamel 54 | 55 | let lib = cxxLibImport("wave", @["wave_c_api.h"]) 56 | 57 | let ir = expandViaCc(dir /. "wave_c_api.h", baseCParseConf). 58 | wrapViaTs(fixConf, lib). 59 | postFixEntries(fixConf, lib) 60 | 61 | 62 | writeFile( 63 | res, 64 | if bindDl: 65 | lit3""" 66 | import std/os 67 | const boostWaveLibDir = currentSourcePath().splitFile().dir / "../../../lib" 68 | const cwaveDl* = boostWaveLibDir / "libboost_cwave.so" 69 | 70 | """ & ir.toString(codegen) 71 | 72 | else: 73 | "{.passc: \"-lboost_cwave\".}\n{.passl: \"-lboost_cwave\".}\n" & 74 | ir.toString(codegen) 75 | ) 76 | 77 | execShell shellCmd(nim, check, $res) 78 | 79 | suite "Run generated wave file": 80 | test "Compile and execute": 81 | execShell shellCmd(nim, r, $relToSource("tBoostWaveExecute.nim")) 82 | -------------------------------------------------------------------------------- /old/tests/tBoostWaveReader.nim: -------------------------------------------------------------------------------- 1 | import hcparse 2 | import hmisc/preludes/unittest 3 | import hmisc/other/oswrap 4 | 5 | suite "Basic reader": 6 | test "Include unistd": 7 | var cache = newWaveCache() 8 | var reader = newWaveReader( 9 | currentSourcePath().AbsFile(), 10 | cache, 11 | baseCParseConf, 12 | some "#include \n" 13 | ) 14 | 15 | for tok in items(reader.ctx): 16 | discard 17 | 18 | test "Parse relative source": 19 | var cache = newWaveCache() 20 | var reader = newWaveReader( 21 | AbsFile(relToSource"files/wavereader_main.h"), 22 | cache, 23 | baseCParseConf) 24 | 25 | echo reader.getExpanded() 26 | -------------------------------------------------------------------------------- /old/tests/tConvertBitsTs.nim: -------------------------------------------------------------------------------- 1 | import 2 | hmisc/preludes/unittest, 3 | hcparse/[hc_parsefront], 4 | hcparse/codegen/[hc_codegen], 5 | hcparse/processor/[wrap_store, hc_postprocess], 6 | compiler/ast/[ast, renderer], 7 | hnimast/[nim_decl, object_decl, obj_field_macros, hast_common, proc_decl] 8 | 9 | import std/[strutils] 10 | 11 | import pkg/[jsony, frosty], pkg/frosty/streams 12 | 13 | func getFields[N](o: ObjectDecl[N]): seq[ObjectField[N]] = getFlatFields(o) 14 | 15 | var fixConf = baseFixConf.withIt do: 16 | it.onFixName(): 17 | result = cache.fixContextedName(name) 18 | 19 | it.onGetBind(): 20 | return cxxHeader("?") 21 | 22 | it.typeStore = newTypeStore() 23 | 24 | proc lib(path: varargs[string]): CxxLibImport = 25 | cxxLibImport("test", @path) 26 | 27 | var baseConf = cxxCodegenConf.withIt do: 28 | it.nameStyle = idsCamel 29 | 30 | proc convStr(str: string, conf: CodegenConf = baseConf): string = 31 | let lib = lib(@["z"]) 32 | wrapViaTs(str, fixConf, lib). 33 | postFixEntries(fixConf, lib). 34 | toString(conf) 35 | 36 | proc convEntries(str: string, conf: CodegenConf = baseConf): seq[CxxEntry] = 37 | let lib = lib(@["z"]) 38 | wrapViaTs(str, fixConf, lib).postFixEntries(fixConf, lib) 39 | 40 | proc convDecls( 41 | str: string, conf: CodegenConf = baseConf): seq[NimDecl[PNode]] = 42 | let lib = lib(@["z"]) 43 | hc_codegen.toNNode[PNode]( 44 | wrapViaTs(str, fixConf, lib). 45 | postFixEntries(fixConf, lib), conf) 46 | 47 | proc convPPrint(str: string) = 48 | let lib = lib(@["z"]) 49 | pprint wrapViaTs(str, fixConf, lib). 50 | postFixEntries(fixConf, lib) 51 | 52 | suite "Convert type declarations": 53 | test "Regular struct": 54 | check convDecls("struct S {};")[0].getObject().getName() == "S" 55 | 56 | test "Struct with fields": 57 | let 58 | f1 = convDecls( 59 | "struct WithFields { int field; };")[0].getObject().getFields()[0] 60 | f2 = convDecls( 61 | "struct WithFields { int __field; };")[0].getObject().getFields()[0] 62 | 63 | check: 64 | not f1.hasPragma("importcpp") 65 | f1.name == "field" 66 | 67 | f2.hasPragma("importcpp") 68 | f2.name == "field" 69 | f2.getPragmaArgs("importcpp")[0].getStrVal() == "__field" 70 | 71 | test "Class with methods": 72 | let 73 | decls = convDecls("struct A { void get(); void set(int val); };") 74 | declA = decls[0].getObject() 75 | declGet = decls[1].getProc() 76 | declSet = decls[2].getProc() 77 | 78 | check: 79 | declA.getName() == "A" 80 | declGet.getName() == "get" 81 | declGet.argumentNames() == @["this"] 82 | declSet.argumentNames() == @["this", "val"] 83 | 84 | 85 | test "Class with documentation": 86 | let 87 | decls = convDecls("struct A { int field; /* doc comment */ };") 88 | declA = decls[0].getObject() 89 | 90 | check: 91 | declA.getName() == "A" 92 | declA.getFields()[0].getName() == "field" 93 | "doc comment" in declA.getFields()[0].docComment 94 | 95 | suite "Repeated names": 96 | test "Multiple structs": 97 | let decls = convDecls("struct _S {}; struct S{};")[0].getTypes() 98 | check: 99 | decls[0].getObject().getName() == "S" 100 | decls[1].getObject().getName() == "S1" 101 | 102 | suite "Procedures": 103 | test "Variadic proc": 104 | let pr = convDecls("void git_libgit2_opts(int option, ...);"). 105 | getFirst(nekProcDecl).getProc() 106 | 107 | check: 108 | pr.hasPragma("varargs") 109 | 110 | # suite "Enum": 111 | # test "enum": 112 | # echov convStr(""" 113 | # enum fullpow { q = 0, a = 1 << 0, b = 1 << 1 }; 114 | # """) 115 | 116 | suite "Qt elements": 117 | test "": 118 | echo convStr(""" 119 | 120 | class QObject { 121 | public: 122 | static QMetaObject::Connection connect( 123 | const QMetaMethod &method, 124 | Qt::ConnectionType type = Qt::AutoConnection); 125 | }; 126 | 127 | class QPaintDevice { 128 | public: int width() const { return metric(PdmWidth); } 129 | }; 130 | 131 | class QWidget : public QObject, public QPaintDevice { 132 | public: QRect frameGeometry() const; 133 | }; 134 | 135 | class QAbstractButton : public QWidget { 136 | public: explicit QAbstractButton(QWidget *parent = nullptr); 137 | };""") 138 | 139 | 140 | suite "Serialization": 141 | test "Functions": 142 | let entries = convEntries("int getIdx();") 143 | let test = freeze entries 144 | let unpacked = thaw[seq[CxxEntry]](test) 145 | 146 | echo unpacked.toString(cxxCodegenConf) 147 | 148 | test "Merger": 149 | var entries1 = thaw[seq[Cxxentry]]( 150 | freeze convEntries("enum Test { a };")) 151 | 152 | var entries2 = thaw[seq[Cxxentry]]( 153 | freeze convEntries("void setValue(Test arg);")) 154 | 155 | var store = newTypeStore() 156 | for entry in mitems(entries1): entry.reuseStore(store) 157 | for entry in mitems(entries2): entry.reuseStore(store) 158 | 159 | let entries = entries1 & entries2 160 | 161 | echo toString(entries, baseConf) 162 | 163 | suite "Convert edge cases": 164 | test "Rename mapped to the same nim ident": 165 | let s = convStr(""" 166 | typedef struct _Impl {} Impl; 167 | 168 | Impl get1(); 169 | _Impl get2(); 170 | """) 171 | 172 | echo s 173 | -------------------------------------------------------------------------------- /old/tests/tConvertLibs.nim: -------------------------------------------------------------------------------- 1 | import 2 | hcparse/[hc_parsefront, hc_impls], 3 | hcparse/processor/[hc_grouping], 4 | hcparse/codegen/[hc_codegen], 5 | hcparse/read_boost_wave/[hc_wavereader] 6 | 7 | 8 | import hnimast/hast_common 9 | import hmisc/algo/[ hparse_pegs, hstring_algo ] 10 | import hmisc/preludes/unittest 11 | import hmisc/other/oswrap 12 | 13 | import compiler/ast/ast 14 | 15 | import std/[strutils, sequtils] 16 | 17 | proc fixGit*(name: string, isType: bool): string = 18 | dropPrefix(name, "git_").snakeToCamelCase() 19 | 20 | suite "Bug hunting for git": 21 | let 22 | dir = getTestTempDir() 23 | sys = dir / "sys" 24 | user = dir / "user" 25 | file = user /. "user_main.h" 26 | 27 | mkWithDirStructure dir: 28 | dir sys: 29 | file "sys_file.h": "#define sys_macro expanded\n" 30 | 31 | dir user: 32 | file "user_main.h": 33 | lit3""" 34 | #include "user_sub.h" 35 | sys_macro 36 | """ 37 | file "user_sub.h": 38 | lit3""" 39 | #include 40 | """ 41 | 42 | test "Subcontext with failed include": 43 | var cache = newWaveCache() 44 | var reader = newWaveReader(file, cache, baseCParseConf) 45 | expect WaveError as we: 46 | discard reader.getExpanded() 47 | 48 | check: 49 | we.diag.code == wekBadIncludeFile 50 | we.diag.line == 1 51 | "Could not find include file" in we.msg 52 | 53 | test "Subcontext with correct include": 54 | var cache = newWaveCache() 55 | var conf = baseCParseConf 56 | conf.sysIncludes.add sys.string 57 | var reader = newWaveReader(file, cache, conf) 58 | check: 59 | reader.getExpanded().strip() == "expanded" 60 | 61 | 62 | 63 | 64 | 65 | suite "libgit": 66 | var enumMap: PegCallReplaceMap 67 | for prefix in @[ 68 | "OBJECT", 69 | "REFERENCE", 70 | "BRANCH", 71 | "FILEMODE", 72 | "SUBMODULE_UPDATE", 73 | "SUBMODULE_IGNORE", 74 | "SUBMODULE_RECURSE" 75 | ]: 76 | enumMap.add( 77 | sequence(term("GIT_" & prefix), *term('_'), capture(*anyChar())), 78 | toReplaceHandler("g" & abbrevSnake(prefix) & "${snakeToCamel}") 79 | ) 80 | 81 | 82 | var fixConf = baseFixConf 83 | 84 | fixConf.isIcpp = false 85 | fixConf.libName = "git" 86 | 87 | fixConf.onGetBind(): 88 | case entry.kind: 89 | of cekProc: result = cxxDynlibVar("libgitDl") 90 | else: result = cxxNoBind() 91 | 92 | fixConf.onFixName(): 93 | if cache.knownRename(name.nim): 94 | return cache.getRename(name.nim) 95 | 96 | result = keepNimIdentChars(name.nim) 97 | 98 | cache.newRename(name.nim, result) 99 | 100 | fixConf.typeStore = newTypeStore() 101 | 102 | let outDir = getTestTempDir() 103 | 104 | # test "Expand libgit": 105 | # # This is not a tests, this is a fucking joke, but I have no idea how 106 | # # to debug spontaneous nim closure failures when they are passed to the 107 | # # boost wave side, so for now I just repeatedly run the same test file 108 | # # until I get all entries wrapped correctly. 109 | 110 | # mkDir outDir 111 | # let lib = AbsDir"/usr/include/git2" 112 | # var cache = newWaveCache() 113 | # for file in walkDir(lib, AbsFile): 114 | # if file.name() notin [ 115 | # "stdint" # Use this header only with Microsoft Visual C++ compilers! 116 | # ]: 117 | # let resFile = (outDir /. file.name()) &. "h" 118 | 119 | # if not exists(resFile): 120 | # var reader = newWaveReader(file, cache, baseCParseConf) 121 | # resFile.writeFile(reader.getExpanded()) 122 | 123 | 124 | # test "libgit types": 125 | # var resultWrapped: seq[CxxFile] 126 | # block: 127 | # for file in walkDir(outDir, AbsFile, exts = @["h"]): 128 | # resultWrapped.add wrapViaTs(file, outDir, fixConf) 129 | 130 | # echo "Collected files" 131 | 132 | # for fix in regroupFiles(resultWrapped): 133 | # let res = outDir / fix.getFile().withExt("nim") 134 | # res.writeFile($toNNode[PNode](fix, cCodegenConf)) 135 | -------------------------------------------------------------------------------- /old/tests/tHcparseCli.nim: -------------------------------------------------------------------------------- 1 | import 2 | hmisc/preludes/unittest, 3 | hcparse/hcparse_cli 4 | 5 | suite "Setup project using conan": 6 | test "libgit2 wrappers": 7 | let dir = getTestTempDir(true) 8 | echov dir 9 | 10 | withDir dir: 11 | hcparseCli(@["init", "conan", "zlib", "1.2.11"]) 12 | -------------------------------------------------------------------------------- /old/tests/tLibclangBasic.nim: -------------------------------------------------------------------------------- 1 | import hmisc/preludes/unittest 2 | import 3 | hmisc/other/[ 4 | hpprint, 5 | hlogger 6 | ], 7 | 8 | hcparse/[ 9 | hc_parsefront, 10 | hc_impls 11 | ], 12 | 13 | hcparse/read_libclang/[ 14 | hc_types, 15 | hc_visitors, 16 | hc_clangreader, 17 | ], 18 | 19 | hcparse/processor/[hc_postprocess] 20 | 21 | proc convStr(file: AbsFile, s: string, print: bool = false): string = 22 | file.writeFile(s) 23 | var cache = newWrapCache() 24 | if print: 25 | let unit = parseFileViaClang(file) 26 | echo unit.getTranslationUnitCursor().treeRepr() 27 | 28 | var wrap = baseCppWrapConf.withDeepIt do: 29 | it.logger = newTermLogger() 30 | it.onIgnoreCursor(): 31 | return false 32 | 33 | 34 | let fix = baseFixConf.withIt do: 35 | it.typeStore = newTypeStore() 36 | it.onGetBind(): 37 | return cxxHeader("?") 38 | 39 | 40 | let api = parseFileViaClang(file). 41 | splitDeclarations(wrap, cache) 42 | 43 | let wrapped = api.wrapApiUnit(wrap, cache). 44 | postFixEntries(fix, cxxLibImport("h", @["h"])) 45 | 46 | return wrapped.toString(cxxCodegenConf) 47 | 48 | 49 | suite "Parse basic file": 50 | let dir = getTestTempDir() 51 | mkDir dir 52 | let file = dir /. "file.hpp" 53 | test "Dump tree repr": 54 | writeFile(file, """ 55 | struct Struct { 56 | int field; 57 | 58 | int get() const; 59 | 60 | public __attribute__((annotate("qt_signal"))): 61 | 62 | void set1(int arg); 63 | void set2(int arg); 64 | 65 | }; 66 | 67 | template 68 | class Templated { 69 | public: 70 | T get() const noexcept; 71 | void set(Z value); 72 | static void getQ(); 73 | }; 74 | 75 | // enum class Enum {en1, en2}; 76 | // Enum getEnum(Enum in); 77 | 78 | Templated operator%(int arg1, Struct arg2); 79 | 80 | int main() {} 81 | 82 | typedef struct LIBSSH2_USERAUTH_KBDINT_PROMPT 83 | { 84 | char *text; 85 | unsigned int length; 86 | unsigned char echo; 87 | } LIBSSH2_USERAUTH_KBDINT_PROMPT; 88 | 89 | typedef struct Q_LIBSSH2_POLLFD { 90 | unsigned char type; 91 | union { 92 | int socket_1; 93 | int socket_2; 94 | } fd; 95 | unsigned long events; 96 | } LIBSSH2_POLLFD; 97 | 98 | typedef unsigned long long libssh2_uint64_t; 99 | typedef long long libssh2_int64_t; 100 | typedef struct stat libssh2_struct_stat; 101 | typedef int libssh2_struct_stat_size; 102 | 103 | """) 104 | 105 | let unit = parseFileViaClang(file) 106 | echo unit.getTranslationUnitCursor().treeRepr() 107 | 108 | test "Visitors": 109 | var cache = newWrapCache() 110 | let api = parseFileViaClang(file). 111 | splitDeclarations(baseCppWrapConf, cache) 112 | 113 | var fix = baseFixConf.withIt do: 114 | it.typeStore = newTypeStore() 115 | 116 | fix.onGetBind(): 117 | return cxxHeader("?") 118 | 119 | var wrap = baseCppWrapConf.withDeepIt do: 120 | it.logger = newTermLogger() 121 | 122 | let wrapped = api.wrapApiUnit(wrap, cache). 123 | postFixEntries(fix, cxxLibImport("h", @["h"])) 124 | 125 | echo "Generated wrapped" 126 | echo wrapped.toString(cxxCodegenConf) 127 | 128 | suite "Convert edge cases": 129 | test "Rename mapped to the same nim ident": 130 | let file = getTestTempFile("c") 131 | let s = file.convStr(""" 132 | typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT 133 | { 134 | char *text; 135 | unsigned int length; 136 | unsigned char echo; 137 | } LIBSSH2_USERAUTH_KBDINT_PROMPT; 138 | 139 | typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE 140 | { 141 | char *text; 142 | unsigned int length; 143 | } LIBSSH2_USERAUTH_KBDINT_RESPONSE; 144 | 145 | /* 'keyboard-interactive' authentication callback */ 146 | #define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) \ 147 | void name_(const char *name, int name_len, const char *instruction, \ 148 | int instruction_len, int num_prompts, \ 149 | const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, \ 150 | LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract) 151 | 152 | int libssh2_userauth_keyboard_interactive_ex( 153 | const char *username, 154 | unsigned int username_len, 155 | LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback))); 156 | 157 | """, true) 158 | 159 | echo s 160 | -------------------------------------------------------------------------------- /old/tests/tMergeGroups.nim: -------------------------------------------------------------------------------- 1 | import hmisc/preludes/unittest 2 | import hmisc/algo/hseq_mapping 3 | import hmisc/types/hgraph 4 | import hnimast 5 | 6 | import hmisc/hasts/graphviz_ast 7 | 8 | 9 | import 10 | hcparse/[hc_parsefront, hc_impls], 11 | hcparse/codegen/hc_codegen, 12 | hcparse/processor/[hc_grouping, wrap_store] 13 | 14 | import std/[strutils, sets, sequtils] 15 | import compiler/ast/[ast] 16 | 17 | 18 | proc lib(path: varargs[string]): CxxLibImport = 19 | cxxLibImport("test", @path) 20 | 21 | let root = AbsDir("/tmp") 22 | 23 | template convFile(str, name: string): CxxFile = 24 | conf.onGetBind(): 25 | return cxxHeader(name) 26 | 27 | wrapViaTs(str, conf, lib(name)). 28 | postFixEntries(conf, lib(name)). 29 | cxxFile(lib(name), root /. name) 30 | 31 | configureDefaultTestContext( 32 | skipAfterException = true 33 | ) 34 | 35 | proc findFile(files: seq[CxxFile], name: string): CxxFile = 36 | files[files.findIt(it.getFilename().startsWith(name))] 37 | 38 | proc getTypes(decl: seq[NimDecl[PNode]]): seq[NimTypeDecl[PNode]] = 39 | decl.findItFirst(it of nekMultitype).typedecls 40 | 41 | proc genEntries(file: CxxFile): seq[NimDecl[PNode]] = 42 | toNNode[PNode](file.entries, cxxCodegenConf) 43 | 44 | suite "Forward-declare in files": 45 | var conf = baseFixConf.withIt do: 46 | it.typeStore = newTypeStore() 47 | 48 | it.onFixName(): 49 | result = name.nim 50 | cache.newRename(name.nim, result) 51 | 52 | test "Single file with forward declarattion": 53 | conf.typeStore = newTypeStore() 54 | let files = @[convFile("struct W { int f; }; typedef struct W W;", "decl_W.hpp")] 55 | let group = regroupFiles(files) 56 | let file = group.findFile("decl_W") 57 | let decl = file.entries.toNNode[:PNode](cxxCodegenConf). 58 | findItFirst(it of nekMultitype).typedecls[0].objectDecl 59 | 60 | check: 61 | decl.getField("f").fldType.head == "cint" 62 | decl.hasPragma("bycopy") 63 | decl.hasPragma("importcpp") 64 | 65 | test "forward declare, define elsewhere": 66 | conf.typeStore = newTypeStore() 67 | let files = @[ 68 | convFile("struct Forward; struct User { Forward* userField; }", "user.hpp"), 69 | convFile("struct Forward { int forwardField; };", "forward.hpp") 70 | ] 71 | 72 | let 73 | group = regroupFiles(files) 74 | forward = group.findFile("forward") 75 | user = group.findFile("user") 76 | 77 | check: 78 | lib("forward.hpp") in user.imports 79 | 80 | test "Two separate files, get pointer": 81 | conf.typeStore = newTypeStore() 82 | let files = @[ 83 | convFile( 84 | "struct Forward; struct GetForward { Forward* get(); };", 85 | "get_forward.hpp"), 86 | convFile("struct Forward {};", "forward.hpp") 87 | ] 88 | 89 | # TEST should generate two separate files with 'get_forward' importing 90 | # 'forward' 91 | # assert false 92 | 93 | test "two separate types, mutually recursive": 94 | conf.typeStore = newTypeStore() 95 | let files = @[ 96 | convFile("struct A; struct B { A* ptrA; };", "decl_B.hpp"), 97 | convFile("struct B; struct A { B* ptrB; };", "decl_A.hpp"), 98 | convFile("struct C { A* ptrA; B* ptrB; };", "decl_C.hpp") 99 | ] 100 | 101 | let group = regroupFiles(files) 102 | 103 | let 104 | fileA = group.findFile("decl_A") 105 | fileB = group.findFile("decl_B") 106 | fileC = group.findFile("decl_C") 107 | 108 | merged = "decl_A_decl_B" 109 | 110 | let 111 | typesM = group.findFile(merged).genEntries().getTypes() 112 | declA = typesM.getFirst("A").objectDecl 113 | declB = typesM.getFirst("B").objectDecl 114 | fieldB = declA.getField("ptrB") 115 | fieldA = declB.getField("ptrA") 116 | 117 | check: 118 | fieldB.fldType.head == "ptr" 119 | fieldA.fldType.head == "ptr" 120 | 121 | fieldB.fldType.genParams[0].head == "B" 122 | fieldA.fldType.genParams[0].head == "A" 123 | 124 | check: 125 | lib(merged) in fileA.imports 126 | lib(merged) in fileA.exports 127 | 128 | lib(merged) in fileB.imports 129 | lib(merged) in fileB.exports 130 | 131 | lib("decl_A.hpp") in fileC.imports 132 | lib("decl_B.hpp") in fileC.imports 133 | 134 | test "Depends on forward declaration": 135 | conf.typeStore = newTypeStore() 136 | let files = @[ 137 | convFile("struct Forward;", "forward.hpp"), 138 | convFile("typedef struct User { Forward* forward; } User;", "user.hpp") 139 | ] 140 | 141 | let group = regroupFiles(files) 142 | 143 | let 144 | userFile = group.findFile("user") 145 | userCode = userFile.genEntries().getTypes() 146 | userDecl = userCode.getFirst("User").objectDecl 147 | 148 | forwardFile = group.findFile("forward") 149 | forwardCode = forwardFile.genEntries().getTypes() 150 | forwardDecl = forwardCode.getFirst("Forward").objectDecl 151 | 152 | check: 153 | lib("forward.hpp") in userFile.imports 154 | 155 | forwardDecl.hasPragma("incompleteStruct") 156 | 157 | test "Forward declaration and recursive": 158 | conf.typeStore = newTypeStore() 159 | let files = @[ 160 | convFile("struct Forward1;", "forward1.hpp"), 161 | convFile("struct Forward2;", "forward2.hpp"), 162 | convFile(lit3""" 163 | struct User2; 164 | struct User1 { 165 | Forward1* forward1; 166 | Forward2* forward2; 167 | User2* user2; 168 | }; 169 | 170 | Forward1* procForward1_1(); 171 | Forward2* procForward1_2(); 172 | """, "user1.hpp"), 173 | convFile(lit3""" 174 | struct User1; 175 | struct User2 { 176 | Forward1* forward1; 177 | Forward2* forward2; 178 | User1* user1; 179 | }; 180 | 181 | Forward1* procForward2_1(); 182 | Forward2* procForward2_2(); 183 | """, "user2.hpp") 184 | ] 185 | 186 | 187 | let g = buildTypeGraph(files) 188 | 189 | check: 190 | ## User 2 links forward2 and forward1 because it contains forward declaration 191 | (g[lib("user2.hpp")], g[lib("forward2.hpp")]) in g 192 | (g[lib("user2.hpp")], g[lib("forward1.hpp")]) in g 193 | 194 | ## User 1 links also uses forward-declared types 195 | (g[lib("user1.hpp")], g[lib("forward2.hpp")]) in g 196 | (g[lib("user1.hpp")], g[lib("forward1.hpp")]) in g 197 | 198 | ## user1 and user2 form cyclic dependenncy due to usage of 199 | ## forward-declared pointers. 200 | (g[lib("user1.hpp")], g[lib("user2.hpp")]) in g 201 | (g[lib("user2.hpp")], g[lib("user1.hpp")]) in g 202 | 203 | let group = regroupFiles(files) 204 | 205 | let 206 | merged = "user1_user2" 207 | f1 = group.findFile("forward1") 208 | f2 = group.findFile("forward2") 209 | m = group.findFile(merged) 210 | u1 = group.findFile("user1") 211 | u2 = group.findFile("user2") 212 | 213 | check: 214 | lib(merged) in u1.exports 215 | lib(merged) in u2.exports 216 | 217 | lib(merged) in u1.imports 218 | lib(merged) in u2.imports 219 | 220 | lib("forward1.hpp") in m.imports 221 | lib("forward2.hpp") in m.imports 222 | 223 | lib("forward1.hpp") in m.imports 224 | lib("forward2.hpp") in m.imports 225 | 226 | g.dotRepr().toPng(getTestTempFile("png")) 227 | 228 | suite "Multipass merger": 229 | test "Ultimate": 230 | const 231 | # Base implementation of iterator (supposed to be generic, but this 232 | # does not matter here) 233 | implIterator = """ 234 | struct Iterator {}; 235 | """ 236 | 237 | # Implementation of the vector, relies on the base iterator 238 | # (concatenation emulates direct `#include`) 239 | implVector = implIterator & """ 240 | struct Vector { 241 | Iterator get(); 242 | } 243 | """ 244 | 245 | # String implementation also needs an iterator (concatenation 246 | # emulates direct `#include`) 247 | implString = implIterator & """ 248 | struct String { 249 | Iterator get(); 250 | } 251 | """ 252 | 253 | var conf = baseFixConf.withIt do: 254 | it.onFixName(): 255 | result = name.nim 256 | cache.newRename(name.nim, result) 257 | 258 | conf.typeStore = newTypeStore() 259 | let fileIterator = convFile(implIterator, "iterator.hpp") 260 | 261 | conf.typeStore = newTypeStore() 262 | let fileVector = convFile(implVector, "vector.hpp") 263 | 264 | conf.typeStore = newTypeStore() 265 | let fileString = convFile(implString, "string.hpp") 266 | 267 | let finalized = clearRepeated(@[ 268 | fileIterator, 269 | fileVector, 270 | fileString 271 | ]) 272 | 273 | let group = regroupFiles(finalized) 274 | let g = buildTypeGraph(finalized) 275 | echov g 276 | echov group.toString(cxxCodegenConf) 277 | -------------------------------------------------------------------------------- /old/tests/tReadConan.nim: -------------------------------------------------------------------------------- 1 | discard """ 2 | joinable: false 3 | """ 4 | 5 | import 6 | hmisc/preludes/unittest 7 | 8 | import 9 | hcparse/read_deps/conan, 10 | hcparse 11 | 12 | suite "conan 1": 13 | test "get conan info": 14 | let dir = getTestTempDir(true) 15 | let info = getBuildInfo("libgit2", (1, 3, 0), dir) 16 | 17 | test "Wrap package with dependencies": 18 | let sshDir = getTestTempDir(true) / "ssh" 19 | mkDir sshDir 20 | 21 | let 22 | sshInfo = getBuildInfo("libssh2", (1, 9, 0), sshDir) 23 | sshRoot = sshInfo.findIncludePath("libssh2")[0] 24 | 25 | let sshGrouped = wrapCSharedLibViaTsWave( 26 | inDir = sshRoot, 27 | outDir = sshDir / "res", 28 | tmpDir = sshDir / "tmp", 29 | libName = "ssh2", 30 | packageName = "libssh2" 31 | ) 32 | 33 | let gitDir = getTestTempDir(true) / "git" 34 | mkDir gitDir 35 | 36 | let 37 | gitInfo = getBuildInfo("libgit2", (1, 3, 0), gitDir) 38 | gitRoot = gitInfo.findIncludePath("libgit2")[0] 39 | 40 | let gitGrouped = wrapCSharedLibViaTsWave( 41 | inDir = gitRoot / "git2", 42 | outDir = gitDir / "res", 43 | tmpDir = gitDir / "tmp", 44 | libName = "git2", 45 | packageName = "libgit2", 46 | ignoreIn = @["stdint"] 47 | ) 48 | 49 | echov "git wrapper ok" 50 | -------------------------------------------------------------------------------- /old/tests/tWip.nim: -------------------------------------------------------------------------------- 1 | import hcparse/read_boost_wave/hc_wavereader 2 | var ctx = newWaveContext("0xff00000000000000ull") 3 | echo ctx.getExpanded() 4 | -------------------------------------------------------------------------------- /old/tests/wip_in.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "wip_in.hpp" 3 | 4 | void test0(H nice) {} 5 | void test1(H nice) {} 6 | void test2(H nice) {} 7 | void test3(Aggr aggr) {} 8 | void test4(Aggr2 aggr) {} 9 | void test5(Aggr2 aggr) {} 10 | H::H(int arg) : field(arg) {} 11 | H::H(std::initializer_list ilist) {} 12 | -------------------------------------------------------------------------------- /old/tests/wip_in.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Test { 4 | enum class Enum { 5 | first = 1 << 0, 6 | second = 1 << 1, 7 | third = 1 << 2 8 | // secondDifferentName = second 9 | }; 10 | 11 | void acceptsEnum(Enum en) {} 12 | }; 13 | 14 | void acceptsEnum(Test::Enum en) {} 15 | -------------------------------------------------------------------------------- /old/wip/.gitignore: -------------------------------------------------------------------------------- 1 | result* 2 | header.* 3 | index.h 4 | a.out -------------------------------------------------------------------------------- /old/wip/build.nims: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env nim 2 | import shell 3 | import strutils, sequtils, strformat 4 | 5 | proc generate_depgraph = 6 | shell: 7 | "clang++ -lboost_system -lboost_filesystem -lboost_thread -lboost_wave -odeps deps.cpp" 8 | "./deps -S/usr/include/c++/10.2.0 -S/usr/include/c++/10.2.0/x86_64-pc-linux-gnu test.cpp" 9 | 10 | generate_depgraph() 11 | 12 | proc generateLibclang_v0_1 = 13 | shell: 14 | "clang++" "-fcolor-diagnostics" -lfmt "-lclang" "-olibclang" "libclang-1.cpp" 15 | ./libclang 16 | # bat "--line-range 180:210 --color=always result.nim" 17 | ./fixshit.sh 18 | 19 | func makeFileName(file: string): string = 20 | "../src/hcparse/libclang_raw/" & file & ".nim" 21 | 22 | proc addImports(file: string, imports: seq[string]): void = 23 | let file = makeFileName(file) 24 | # let file = "../src/hcparse/libclang_raw/" & file & ".nim" 25 | echo &"updated {file}" 26 | let body = file.readFile() 27 | file.writeFile imports.mapIt(&"import {it}\n").join("") & body 28 | 29 | let importMap = { 30 | "index" : @[ 31 | "build_system", 32 | "cxcompilation_database", 33 | "cxerror_code", 34 | "cxstring", 35 | "externc", 36 | "fatal_error_handler", 37 | "opaque_impls", 38 | "platform" 39 | ], 40 | "build_system" : @[ 41 | "cxerror_code", 42 | "cxstring", 43 | "platform", 44 | "externc" 45 | ], 46 | "cxcompilation_database" : @[ 47 | "cxstring", 48 | ], 49 | "documentation" : @[ 50 | "externc", 51 | "index" 52 | ] 53 | } 54 | 55 | for (file, imports) in importMap: 56 | addImports(file, imports) 57 | 58 | var sedfix = { 59 | "index" : @[ 60 | "'s/PriorityForAll = 0/PriorityForAll = 4/'", 61 | "'s/CXCursor_FirstDecl/# CXCursor_FirstDecl = 1/'", 62 | "'s/CXCursor_LastDecl/# CXCursor_LastDecl = 39/'", 63 | "'s/CXCursor_FirstRef/# CXCursor_FirstRef = 40/'", 64 | "'s/CXCursor_InvalidFile = 70/# CXCursor_InvalidFile = 70/'", 65 | "'s/CXCursor_FirstExpr = 100/# CXCursor_FirstExpr = 100/'", 66 | "'s/CXCursor_FirstStmt = 200/# CXCursor_FirstStmt = 200/'", 67 | "'s/CXCursor_AsmStmt/# CXCursor_AsmStmt/'", 68 | "'s/CXCursor_UnexposedAttr = 400/# CXCursor_UnexposedAttr = 400/'", 69 | "'s/CXCursor_InclusionDirective = 503/# CXCursor_InclusionDirective = 503/'", 70 | "'s/CXCallingConv_X86_64SysV = 11/# CXCallingConv_X86_64SysV = 11/'", 71 | "'s/CXEval_UnExposed = 0//'", 72 | r"'s/CXEval_Int = 1/CXEval_UnExposed = 0\n CXEval_Int = 1/'", 73 | r"'s/ptr\[const /ptr\[/'" 74 | ]} 75 | 76 | for (file, fix) in sedfix: 77 | let file = makeFileName(file) 78 | for edit in fix: 79 | shell: 80 | sed -i ($edit) ($file) 81 | -------------------------------------------------------------------------------- /old/wip/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # -*- coding: utf-8 -*- 3 | set -o nounset 4 | set -o errexit 5 | 6 | clang++ libclang-3.cpp -lLLVM -lclang-cpp -olibclang-3 7 | ./libclang-3 8 | -------------------------------------------------------------------------------- /old/wip/fixshit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # -*- coding: utf-8 -*- 3 | # bash 4 | set -o nounset 5 | set -o errexit 6 | 7 | idxfile="../src/hcparse/libclang_raw/index.nim" 8 | 9 | sed -i \ 10 | "s/PriorityForAll = 0/PriorityForAll = 4/" \ 11 | $idxfile 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /old/wip/libclang-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | CXIndex index = clang_createIndex(0, 0); 6 | const char* args[] = {"-v"}; 7 | CXTranslationUnit unit = clang_parseTranslationUnit( 8 | index, 9 | "/tmp/test-file.cpp", 10 | args, 11 | 1, 12 | nullptr, 13 | 0, 14 | CXTranslationUnit_None); 15 | 16 | 17 | if (unit == nullptr) { 18 | std::cout << "Unable to parse translation unit. Quitting.\n"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /old/wip/libclang-3.cpp: -------------------------------------------------------------------------------- 1 | /// Third version of the C++-based wrapper generator 2 | 3 | #include "clang/Tooling/CommonOptionsParser.h" 4 | #include "clang/Tooling/Tooling.h" 5 | #include "clang/Frontend/CompilerInstance.h" 6 | #include "clang/AST/RecursiveASTVisitor.h" 7 | 8 | #include "llvm/Support/CommandLine.h" 9 | 10 | using namespace clang; 11 | using namespace clang::tooling; 12 | using namespace llvm; 13 | 14 | int main() {} 15 | -------------------------------------------------------------------------------- /old/wip/libclang_2.nim: -------------------------------------------------------------------------------- 1 | import hcparse/libclang 2 | 3 | let index = createIndex(0, 0) 4 | 5 | let args = allocCStringArray(["-v"]) 6 | 7 | let unit = parseTranslationUnit( 8 | index, 9 | "/tmp/test-file.cpp".cstring, 10 | args, 11 | 1, 12 | nil, 13 | 0, 14 | 0) 15 | 16 | echo cast[cuint](tufNone) 17 | 18 | if unit.isNil(): 19 | echo "error" 20 | -------------------------------------------------------------------------------- /old/wip/nim.cfg: -------------------------------------------------------------------------------- 1 | --warning[CommentXIgnored]:off -------------------------------------------------------------------------------- /src/embedded_includes.hpp.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | struct EmbeddedFile { 9 | const char* filename; 10 | const char* content; 11 | size_t size; 12 | template 13 | constexpr EmbeddedFile(const char* filename, const char (&data)[N]) 14 | : filename(filename), content(data), size(N - 1) {} 15 | constexpr EmbeddedFile() 16 | : filename(nullptr), content(nullptr), size(0) {} 17 | }; 18 | 19 | static constexpr EmbeddedFile EmbeddedFiles[] = { 20 | // clang-format off 21 | @EMBEDDED_DATA@ 22 | // clang-format on 23 | {}}; 24 | -------------------------------------------------------------------------------- /src/projectmanager.cpp: -------------------------------------------------------------------------------- 1 | #include "projectmanager.hpp" 2 | #include "stringbuilder.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | std::vector ProjectManager::systemProjects() { 10 | std::vector projects; 11 | 12 | std::istringstream stream("include;/usr/include/"); 13 | std::string current; 14 | std::string name; 15 | 16 | while (std::getline(stream, current, ';')) { 17 | if (name.empty()) { 18 | name = current; 19 | } else { 20 | projects.emplace_back(name, current, ProjectInfo::Internal); 21 | name.clear(); 22 | } 23 | } 24 | 25 | return projects; 26 | } 27 | 28 | 29 | ProjectManager::ProjectManager() { 30 | for (auto&& info : systemProjects()) { 31 | addProject(info); 32 | } 33 | } 34 | 35 | bool ProjectManager::addProject(ProjectInfo info) { 36 | if (info.source_path.empty()) { return false; } 37 | llvm::SmallString<256> filename; 38 | llvm::sys::fs::real_path(info.source_path, filename); 39 | if (filename.empty()) { return false; } 40 | if (filename[filename.size() - 1] != '/') { filename += '/'; } 41 | info.source_path = filename.c_str(); 42 | 43 | projects.push_back(std::move(info)); 44 | return true; 45 | } 46 | 47 | ProjectInfo* ProjectManager::projectForFile(llvm::StringRef filename) { 48 | unsigned int match_length = 0; 49 | ProjectInfo* result = nullptr; 50 | 51 | for (auto& it : projects) { 52 | const std::string& source_path = it.source_path; 53 | if (source_path.size() < match_length) { continue; } 54 | if (filename.startswith(source_path)) { 55 | result = ⁢ 56 | match_length = source_path.size(); 57 | } 58 | } 59 | return result; 60 | } 61 | 62 | std::string ProjectManager::includeRecovery( 63 | llvm::StringRef includeName, 64 | llvm::StringRef from) { 65 | 66 | if (includeRecoveryCache.empty()) { 67 | for (const auto& proj : projects) { 68 | // skip sub project 69 | llvm::StringRef sourcePath(proj.source_path); 70 | auto parentPath = sourcePath.substr(0, sourcePath.rfind('/')); 71 | if (projectForFile(parentPath)) { continue; } 72 | 73 | std::error_code EC; 74 | for (llvm::sys::fs::recursive_directory_iterator 75 | it(sourcePath, EC), 76 | DirEnd; 77 | it != DirEnd && !EC; 78 | it.increment(EC)) { 79 | auto fileName = llvm::sys::path::filename(it->path()); 80 | if (fileName.startswith(".")) { 81 | it.no_push(); 82 | continue; 83 | } 84 | includeRecoveryCache.insert( 85 | {std::string(fileName), it->path()}); 86 | } 87 | } 88 | } 89 | llvm::StringRef includeFileName = llvm::sys::path::filename( 90 | includeName); 91 | std::string resolved; 92 | int weight = -1000; 93 | auto range = includeRecoveryCache.equal_range( 94 | std::string(includeFileName)); 95 | for (auto it = range.first; it != range.second; ++it) { 96 | llvm::StringRef candidate(it->second); 97 | unsigned int suf_len = 0; 98 | while (suf_len < std::min(candidate.size(), includeName.size())) { 99 | if (candidate[candidate.size() - suf_len - 1] != 100 | includeName[includeName.size() - suf_len - 1]) { 101 | break; 102 | } else { 103 | suf_len++; 104 | } 105 | } 106 | // Each paths part that are similar from the expected name are 107 | // weighted 1000 points f 108 | int w = includeName.substr(includeName.size() - suf_len) 109 | .count('/') * 110 | 1000; 111 | if (w + 1000 < weight) { continue; } 112 | 113 | // after that, order by similarity with the from url 114 | unsigned int pref_len = 0; 115 | while (pref_len < std::min(candidate.size(), from.size())) { 116 | if (candidate[pref_len] != from[pref_len]) { 117 | break; 118 | } else { 119 | pref_len++; 120 | } 121 | } 122 | w += candidate.substr(0, pref_len).count('/') * 10; 123 | 124 | // and the smaller the path, the better 125 | w -= candidate.count('/'); 126 | 127 | if (w < weight) { continue; } 128 | 129 | weight = w; 130 | resolved = std::string(candidate); 131 | } 132 | return resolved; 133 | } 134 | -------------------------------------------------------------------------------- /src/projectmanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct ProjectInfo { 9 | std::string name; 10 | std::string source_path; 11 | // std::string description; 12 | // std::string version_info; 13 | // std::string repo_url; //may contains tags; 14 | std::string revision; 15 | 16 | std::string external_root_url; 17 | 18 | // TODO 19 | std::string fileRepoUrl(const std::string& file) const { return {}; } 20 | enum Type { 21 | Normal, 22 | Internal, // includes and stuffs 23 | External, // links to external projects somewhere else, do not 24 | // generate refs or anything, 25 | // and link to a different ref source 26 | } type = Normal; 27 | 28 | ProjectInfo(std::string name, std::string source_path, Type t = Normal) 29 | : name(std::move(name)) 30 | , source_path(std::move(source_path)) 31 | , type(t) {} 32 | ProjectInfo(std::string name, std::string source_path, std::string rev) 33 | : name(std::move(name)) 34 | , source_path(std::move(source_path)) 35 | , revision(std::move(rev)) {} 36 | }; 37 | 38 | struct ProjectManager { 39 | explicit ProjectManager(); 40 | 41 | bool addProject(ProjectInfo info); 42 | 43 | std::vector projects; 44 | 45 | /// \note the file name need to be canonicalized 46 | ProjectInfo* projectForFile(llvm::StringRef filename); 47 | 48 | std::string includeRecovery( 49 | llvm::StringRef includeName, 50 | llvm::StringRef from); 51 | 52 | private: 53 | static std::vector systemProjects(); 54 | 55 | std::unordered_multimap includeRecoveryCache; 56 | }; 57 | -------------------------------------------------------------------------------- /src/stringbuilder.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template struct string_builder_helper; 5 | 6 | template struct string_builder { 7 | typedef string_builder_helper HA; 8 | typedef string_builder_helper HB; 9 | operator std::string() const { 10 | std::string s; 11 | s.reserve(size()); 12 | HA::append_to(s, a); 13 | HB::append_to(s, b); 14 | return s; 15 | } 16 | unsigned int size() const { return HA::size(a) + HB::size(b); } 17 | 18 | string_builder(const A &a, const B &b) : a(a), b(b) {} 19 | const A &a; 20 | const B &b; 21 | }; 22 | 23 | template<> struct string_builder_helper { 24 | typedef std::string T; 25 | static unsigned int size(const std::string &s) { return s.size(); } 26 | static void append_to(std::string &s, const std::string &a) { s+=a; } 27 | }; 28 | 29 | template<> struct string_builder_helper { 30 | typedef const char *T; 31 | static unsigned int size(const char *s) { return std::strlen(s); } 32 | static void append_to(std::string &s, const char *a) { s+=a; } 33 | }; 34 | 35 | template struct string_builder_helper> { 36 | typedef string_builder T; 37 | static unsigned int size(const T &t) { return t.size(); } 38 | static void append_to(std::string &s, const T &t) { 39 | T::HA::append_to(s, t.a); 40 | T::HB::append_to(s, t.b); 41 | } 42 | }; 43 | 44 | template struct string_builder_helper { 45 | typedef char T[N]; 46 | static unsigned int size(const char *s) { return N-1; } 47 | static void append_to(std::string &s, const char *a) { s.append(a, N-1); } 48 | }; 49 | 50 | template 51 | string_builder::T, typename string_builder_helper::T> 52 | operator %(const A &a, const B &b) { 53 | return {a, b}; 54 | } 55 | 56 | template std::string &operator %=(std::string &s, const T &t) { 57 | typedef string_builder_helper H; 58 | s.reserve(s.size() + H::size(t)); 59 | H::append_to(s, t); 60 | return s; 61 | } 62 | 63 | #include 64 | template<> struct string_builder_helper { 65 | typedef llvm::StringRef T; 66 | static unsigned int size(llvm::StringRef s) { return s.size(); } 67 | static void append_to(std::string &s, llvm::StringRef a) { s+=a; } 68 | }; 69 | -------------------------------------------------------------------------------- /todo.org: -------------------------------------------------------------------------------- 1 | * COMPLETED 'Cleaned' libclang wrappers 2 | CLOSED: [2020-12-14 Mon 20:08] 3 | :LOGBOOK: 4 | - State "COMPLETED" from [2020-12-14 Mon 20:08] 5 | :END: 6 | 7 | - [X] Instead of simply dropping duplicate enum values generate 8 | constants with dropped names. 9 | - [X] Improve enum name conversion algorithm to also drop ~CXX~ in in 10 | the name. 11 | - [X] Completely remove underscores from generated type and function 12 | names 13 | 14 | * TODO Todo list 15 | :PROPERTIES: 16 | :CREATED: <2020-12-16 Wed 00:06> 17 | :END: 18 | 19 | - [X] Create fully qualified namespace access names 20 | - [X] Default operators assignment, constructors, move etc. 21 | - [X] Follow typedef alias dependencies 22 | - [X] Wrap alias as ~type A = B~ instead of declaring separate object 23 | - [ ] For all procs that have special arguments (wrappers for default 24 | arguments, newly generated args, removed, compressed and so on) should 25 | provide additional documentation for such parameters (via ~@arg{}~ 26 | annotation). 27 | - [ ] ~static~ fields 28 | - [ ] Convert distinct types (or enums) for 'special integers' like 29 | sourcetrail ids, and create overloads that use them. Mark original procs 30 | as ~deprecated~. Implement overloads as ~{.inline.}~ with ~{.push 31 | warning[Deprecated]:off.}~ in body. Functions that /return/ 'special 32 | integer' mmust be wrapped as ~funcNameRaw~. Result will be converted to 33 | corresponding enum/distincty type 34 | - [ ] Collect macro constant definitions into enums and use them for 35 | overloads from previous step. 36 | - [ ] Do not create constructors procs for abstract classes 37 | - [ ] Make closure override opt-in instead of opt-out feature as it largely 38 | useless for most libraries. 39 | - [ ] operator overloading reimplementation is broken and needs partial 40 | logic refactoring to fix. 41 | - [ ] Documentation templating system. 42 | - [ ] Generate ~cxxDynCast~ proc procedures for all derived types (and for 43 | all base types to derived ones). For each ~Dn~ derived from ~A~ create 44 | ~Dn -> A~ and ~A -> Bn~ conversion casts. 45 | - Can this be adopted for use with nim memory management? When placement 46 | new procedures will be generated. 47 | - Default implementation should check for ~nullptr~ results, and raise 48 | exception. Need to add 'raw' version of the procedure. 49 | - [ ] Allow completely overwriting output paths for generated files. That 50 | is necessary to avoid weird name clases for imports, or fix original file 51 | naming that might include dashes, or any other 'non-standard' path 52 | elements. [[code:NimImportSpec]] should also support imports from generated 53 | files and those two must be interlinked with each other to support this 54 | use case. 55 | 56 | 57 | 58 | * TODO Bugs 59 | :PROPERTIES: 60 | :CREATED: <2021-03-11 Thu 22:23> 61 | :END: 62 | 63 | - [ ] ~cxx11~ namespace is not correctly collapsed for wrapping methods. 64 | - [ ] Multiple annonymous enums are converter to the same name 65 | - [ ] Generated ~importcpp~ for nested anonymous enums is incorrect. 66 | 67 | 68 | Curious how boost::wave and c2nim each handle things like this. 69 | 70 | #+begin_src c 71 | # if ( \ 72 | defined __USE_GNU \ 73 | && (defined __cplusplus \ 74 | ? (__cplusplus < 201103L \ 75 | && !defined __GXX_EXPERIMENTAL_CXX0X__) \ 76 | : (!defined __STDC_VERSION__ \ 77 | || __STDC_VERSION__ < 199901L))) 78 | # define __GLIBC_USE_DEPRECATED_SCANF 1 79 | # else 80 | # define __GLIBC_USE_DEPRECATED_SCANF 0 81 | # endif 82 | #+end_src 83 | 84 | * else 85 | 86 | - https://news.ycombinator.com/item?id=28507758 87 | --------------------------------------------------------------------------------