mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Compare commits
	
		
			325 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | dcae381973 | ||
|  | 2142bc7cce | ||
|  | ae3f82264a | ||
|  | 710e83c098 | ||
|  | 4f46fff3be | ||
|  | 58ea21a9a2 | ||
|  | 0fd1aa82a6 | ||
|  | 5b7f9d84f9 | ||
|  | 4b7e8e74a7 | ||
|  | 5375c72d02 | ||
|  | 5c257be164 | ||
|  | 7fa17322dc | ||
|  | ed3640d945 | ||
|  | 87ce3ad61d | ||
|  | 6d75feb0ce | ||
|  | 168b8b6f6c | ||
|  | 3d063e932a | ||
|  | 157ec569b2 | ||
|  | f63c8dadf1 | ||
|  | d17f6116f0 | ||
|  | 2d6cb22e3a | ||
|  | 2de8b52e56 | ||
|  | 171576e538 | ||
|  | 2db9f65e8b | ||
|  | 2572b64bd1 | ||
|  | 533aaf85f2 | ||
|  | f67ddc1f77 | ||
|  | b1d64f3683 | ||
|  | 7e8840e03f | ||
|  | b003297b22 | ||
|  | 7341cec2c4 | ||
|  | a98b7f72fd | ||
|  | 2e97579394 | ||
|  | f960c7efd0 | ||
|  | c2e7f32cba | ||
|  | 137528fc53 | ||
|  | cbf4cc35fb | ||
|  | cd7b3de1b3 | ||
|  | fddc2270e5 | ||
|  | 2a96d9bd78 | ||
|  | fd554f0808 | ||
|  | 6776c51b23 | ||
|  | ef58295304 | ||
|  | 2e2c3e3e34 | ||
|  | e87bb44a2d | ||
|  | 0ba0a9cce5 | ||
|  | 97bb563ba0 | ||
|  | 8f047f842e | ||
|  | 9d596ef530 | ||
|  | 580ffa8cf7 | ||
|  | 341e0a320d | ||
|  | cff0a9703c | ||
|  | 38618532c4 | ||
|  | 6026dcd86d | ||
|  | 3949971546 | ||
|  | 6146f442fb | ||
|  | 7090c1bfdf | ||
|  | 563babc969 | ||
|  | b649c2b9af | ||
|  | f7f887789c | ||
|  | a8fcdcc528 | ||
|  | a988578cc7 | ||
|  | ee585b24f0 | ||
|  | 3d6e980990 | ||
|  | f5d19416a9 | ||
|  | 4187fa5a09 | ||
|  | eb7613c03f | ||
|  | 7910429037 | ||
|  | cd1cc736a7 | ||
|  | e6d6805f25 | ||
|  | 9733879360 | ||
|  | 725712f796 | ||
|  | 2122cea5c4 | ||
|  | 5466e716a9 | ||
|  | 0dc0e3d9a1 | ||
|  | 4bb12b2caa | ||
|  | 0d9c5f5150 | ||
|  | 4030031a2c | ||
|  | 3143c87f1c | ||
|  | f16f02c4c7 | ||
|  | 3e13b2461d | ||
|  | 5fd0d1589e | ||
|  | 23e6d234d0 | ||
|  | cf2a97f8aa | ||
|  | 5a815e0cd6 | ||
|  | 06a3af2a1d | ||
|  | 0558d95fa3 | ||
|  | 81f9246ab8 | ||
|  | 6979567429 | ||
|  | 348de4165d | ||
|  | 0755d420dd | ||
|  | dead21bce5 | ||
|  | 4cf451ce60 | ||
|  | 72298ac805 | ||
|  | 3d1ad81652 | ||
|  | 88c79169b6 | ||
|  | d9747b9021 | ||
|  | 256976a5a1 | ||
|  | 0ba4b82e10 | ||
|  | ffd9e28b42 | ||
|  | 9c919c786d | ||
|  | 47a9a56959 | ||
|  | 6e03bc604a | ||
|  | feea6a027a | ||
|  | 08fa06b7fe | ||
|  | 8a976edef9 | ||
|  | c71d8d6c74 | ||
|  | e809af7426 | ||
|  | ab05db9040 | ||
|  | 04f916741e | ||
|  | f6224f3718 | ||
|  | 10185bb7a1 | ||
|  | d565960c70 | ||
|  | c21073294f | ||
|  | 3cd95de434 | ||
|  | 6552dba9aa | ||
|  | c8ebe55aa9 | ||
|  | 1eefa2d604 | ||
|  | a359394eea | ||
|  | 9f13026bec | ||
|  | 8fcc99b2a1 | ||
|  | 125a0536ff | ||
|  | 4115947d80 | ||
|  | 2f1dcd7c9a | ||
|  | 5e00ffca13 | ||
|  | ac27095493 | ||
|  | e27ca5cd4c | ||
|  | cc72ac6327 | ||
|  | 5443aa6501 | ||
|  | 902bf32169 | ||
|  | d200633747 | ||
|  | a48b749c2e | ||
|  | 46fab84b95 | ||
|  | b0290f858c | ||
|  | fe09c12cd6 | ||
|  | b5ae5a1cea | ||
|  | 113cb85512 | ||
|  | da276bcb3b | ||
|  | 9a78d0f38c | ||
|  | ec2e1666e7 | ||
|  | 478df40d4b | ||
|  | a8b9d79cb1 | ||
|  | 23865d1a10 | ||
|  | 458b3f24fe | ||
|  | 86fa23e6fa | ||
|  | dd9d5aaed5 | ||
|  | b22df17bb5 | ||
|  | b81e609e66 | ||
|  | d41e57cba6 | ||
|  | da7e83e257 | ||
|  | 83be12fcf1 | ||
|  | a999e2d6c9 | ||
|  | 6d6251e757 | ||
|  | be8b26ef94 | ||
|  | c6b8bce5d6 | ||
|  | d8b3452c07 | ||
|  | eddbd43cd9 | ||
|  | 168189180d | ||
|  | 9e092bab6a | ||
|  | 2c35126b3a | ||
|  | 7dc0e4ca31 | ||
|  | 96257f89d5 | ||
|  | 09919343b4 | ||
|  | b070c1068c | ||
|  | 5628a576db | ||
|  | 073c78e25f | ||
|  | 6a826d6eb5 | ||
|  | 11a6143d4c | ||
|  | 6127c9a46d | ||
|  | 98f7febef7 | ||
|  | 85afadacf0 | ||
|  | 01cd812162 | ||
|  | 39329acc77 | ||
|  | bdc96038ef | ||
|  | 93760d989a | ||
|  | b306c7063b | ||
|  | e3d7fa69d8 | ||
|  | f6c0e5405a | ||
|  | fc12a2662c | ||
|  | ab5b16488c | ||
|  | 4d5900268b | ||
|  | b5c5a4335d | ||
|  | e76235541a | ||
|  | e75e1a6e27 | ||
|  | aa220ecbcb | ||
|  | edc8d74418 | ||
|  | 2831aa09ae | ||
|  | e1b4b0d3a3 | ||
|  | e5df6ca33b | ||
|  | 68c3cbb020 | ||
|  | ca3c37d20a | ||
|  | 6fcd9233ea | ||
|  | 3761c4b1e2 | ||
|  | c89c53b1c7 | ||
|  | be0f63a133 | ||
|  | a8216995ad | ||
|  | 995359ef45 | ||
|  | bc84e3c8a0 | ||
|  | af12a25a9d | ||
|  | f6b2821221 | ||
|  | 458601a139 | ||
|  | a89130edbd | ||
|  | c95cd8a4da | ||
|  | 4d313a8495 | ||
|  | 263eef3442 | ||
|  | 2e97996211 | ||
|  | 7035b9c3c2 | ||
|  | 5628d2ca06 | ||
|  | 61cf7fbccf | ||
|  | ce347c6326 | ||
|  | 94119b19fe | ||
|  | 9c7be1268f | ||
|  | a9d59f67ba | ||
|  | 8d2a72228f | ||
|  | 60b95dd3f3 | ||
|  | b1094f40dc | ||
|  | e40ea80e34 | ||
|  | 9e1222d38a | ||
|  | 4446785729 | ||
|  | 790f015d72 | ||
|  | ccb0dcea3c | ||
|  | 15a0632af0 | ||
|  | 3c0da28947 | ||
|  | 95227f32ca | ||
|  | edf75b5cda | ||
|  | af87c48451 | ||
|  | 7cde8e3aa6 | ||
|  | 34fe6f0a5f | ||
|  | 76c9674f3f | ||
|  | addbabd123 | ||
|  | 46b90d9c36 | ||
|  | 7ee67082aa | ||
|  | e8042ed5f3 | ||
|  | 8828874c25 | ||
|  | 1bdb093319 | ||
|  | a1e2191ad5 | ||
|  | e61fcf1d9b | ||
|  | 610ef0dc4b | ||
|  | 273d38f237 | ||
|  | 8194a08382 | ||
|  | 6170b704b1 | ||
|  | b05f5e7caa | ||
|  | 4b38fc6044 | ||
|  | cee16a75ca | ||
|  | 9fd85a8289 | ||
|  | 2f1eff1474 | ||
|  | 8c582b8d72 | ||
|  | e49673329d | ||
|  | 07ebed83bf | ||
|  | 1def87fdc3 | ||
|  | d91fed7dd4 | ||
|  | 5f2f7e70ef | ||
|  | 83432beff6 | ||
|  | 979b550178 | ||
|  | 9062a531f3 | ||
|  | e2a6fbcf3c | ||
|  | ec16931f3a | ||
|  | 0ec0ca7495 | ||
|  | 51fa7c9371 | ||
|  | 6c69f10fe7 | ||
|  | 206e85a356 | ||
|  | 8d7dd4867b | ||
|  | d1524f78fb | ||
|  | b26735d520 | ||
|  | 603baee777 | ||
|  | e105b7f498 | ||
|  | bb3fbccb50 | ||
|  | c8edcd963d | ||
|  | 3b60cdc707 | ||
|  | ea061d65c9 | ||
|  | da64c0237f | ||
|  | d2b1602881 | ||
|  | 1afd45068c | ||
|  | f01b30e112 | ||
|  | b5f7fbe14e | ||
|  | 8b6073ccbb | ||
|  | f902c759df | ||
|  | 996fdbc0f5 | ||
|  | 9ff3e3b42a | ||
|  | 0a5604521e | ||
|  | 786636ef5d | ||
|  | 18bdb27225 | ||
|  | faca35dec0 | ||
|  | f8813daae3 | ||
|  | da5a20390f | ||
|  | 3ab3db92f5 | ||
|  | a3cd3dd9dc | ||
|  | 918868e9e8 | ||
|  | cf05a25445 | ||
|  | 5d5399a267 | ||
|  | 2de7af0ba5 | ||
|  | 0382c304ad | ||
|  | 182d9946fe | ||
|  | f24e4029b4 | ||
|  | 4ebda29171 | ||
|  | 53026f3d02 | ||
|  | 99c0e95a2f | ||
|  | dfa56c6b08 | ||
|  | 0419df4b2d | ||
|  | 70bdcd0978 | ||
|  | 022df995aa | ||
|  | dcbe7ec41d | ||
|  | df4d27eefe | ||
|  | 8f233f55e9 | ||
|  | 7db49aec21 | ||
|  | b5eaec0778 | ||
|  | 06b126a2e7 | ||
|  | ed96ebac79 | ||
|  | c6e34d2d88 | ||
|  | 53ac8bad79 | ||
|  | d2e163bc3b | ||
|  | 1404123281 | ||
|  | 01a7afd28a | ||
|  | 3a42911e6f | ||
|  | 8e5d52f2c7 | ||
|  | dfff5d7230 | ||
|  | 19b63786c8 | ||
|  | 5293e1c18b | ||
|  | 36b120bdbe | ||
|  | cc169d414f | ||
|  | 0fcb2075e0 | ||
|  | 2bda78fb40 | ||
|  | e878c6eef6 | ||
|  | 9ce405cec5 | ||
|  | f064d413b3 | 
							
								
								
									
										63
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										63
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							| @@ -8,19 +8,21 @@ concurrency: | ||||
|  | ||||
| jobs: | ||||
|   build-linux: | ||||
|     runs-on: ubuntu-22.04 | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine' | ||||
|         path: 'fluxengine' | ||||
|         submodules: 'true' | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine-testdata' | ||||
|         path: 'fluxengine-testdata' | ||||
|     - name: apt | ||||
|       run: | | ||||
|         sudo apt install libudev-dev libsqlite3-dev protobuf-compiler libwxgtk3.0-gtk3-dev libfmt-dev libprotobuf-dev wx-common | ||||
|         sudo apt update | ||||
|         sudo apt install libudev-dev libsqlite3-dev protobuf-compiler libwxgtk3.2-dev libfmt-dev libprotobuf-dev libmagic-dev libmbedtls-dev libcurl4-openssl-dev libmagic-dev nlohmann-json3-dev libdbus-1-dev libglfw3-dev libmd4c-dev libfreetype-dev libcli11-dev libboost-regex-dev | ||||
|     - name: make | ||||
|       run: CXXFLAGS="-Wp,-D_GLIBCXX_ASSERTIONS" make -j`nproc` -C fluxengine | ||||
|  | ||||
| @@ -50,53 +52,61 @@ jobs: | ||||
|   build-macos-current: | ||||
|     strategy: | ||||
|       matrix: | ||||
|         runs-on: [macos-13, macos-latest] | ||||
|         runs-on: [macos-15, macos-15-intel] | ||||
|     runs-on: ${{ matrix.runs-on }} | ||||
|     steps: | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine' | ||||
|         path: 'fluxengine' | ||||
|         submodules: 'true' | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine-testdata' | ||||
|         path: 'fluxengine-testdata' | ||||
|     - name: brew | ||||
|       run: | | ||||
|         brew install sqlite pkg-config libusb protobuf wxwidgets fmt make coreutils dylibbundler libjpeg | ||||
|         brew install sqlite pkg-config libusb protobuf wxwidgets fmt make coreutils dylibbundler libjpeg libmagic nlohmann-json cli11 boost glfw3 md4c ninja python freetype2 mbedtls | ||||
|         brew upgrade | ||||
|     - name: make | ||||
|       run: gmake -C fluxengine -j2 | ||||
|       run: gmake -C fluxengine | ||||
|     - name: Upload build artifacts | ||||
|       uses: actions/upload-artifact@v4 | ||||
|       with: | ||||
|         name: ${{ github.event.repository.name }}.${{ github.sha }}.fluxengine.${{ runner.arch }}.pkg | ||||
|         path: fluxengine/FluxEngine.pkg | ||||
|         path: | | ||||
|           fluxengine/FluxEngine.pkg | ||||
|           fluxengine/FluxEngine.app.zip | ||||
|  | ||||
|   build-windows: | ||||
|     runs-on: windows-latest | ||||
|     defaults: | ||||
|       run: | ||||
|         shell: msys2 {0} | ||||
|  | ||||
|     steps: | ||||
|     - name: setup WSL | ||||
|       run: | | ||||
|         curl -L https://github.com/WhitewaterFoundry/Fedora-Remix-for-WSL/releases/download/41.0.0/Fedora-Remix-for-WSL-SL_41.0.0.0_x64_arm64.msixbundle -o fedora.msixbundle | ||||
|         unzip fedora.msixbundle Fedora-Remix-for-WSL-SL_41.0.0.0_x64.msix | ||||
|         unzip Fedora-Remix-for-WSL-SL_41.0.0.0_x64.msix install.tar.gz | ||||
|         wsl --update | ||||
|         wsl --set-default-version 1 | ||||
|         wsl --import fedora fedora install.tar.gz | ||||
|         wsl --set-default fedora | ||||
|         wsl sh -c 'dnf -y install https://github.com/rpmsphere/noarch/raw/master/r/rpmsphere-release-40-1.noarch.rpm' | ||||
|         wsl sh -c 'dnf -y install gcc gcc-c++ protobuf-c-compiler protobuf-devel fmt-devel systemd-devel sqlite-devel wxGTK-devel mingw32-gcc mingw32-gcc-c++ mingw32-zlib-static mingw32-protobuf-static mingw32-sqlite-static mingw32-wxWidgets3-static mingw32-libpng-static mingw32-libjpeg-static mingw32-libtiff-static mingw32-nsis png2ico' | ||||
|     - uses: msys2/setup-msys2@v2 | ||||
|       with: | ||||
|         msystem: mingw64 | ||||
|         update: true | ||||
|         install: | | ||||
|           python diffutils ninja make zip | ||||
|         pacboy: | | ||||
|           protobuf:p pkgconf:p curl-winssl:p file:p glfw:p mbedtls:p | ||||
|           sqlite:p freetype:p boost:p gcc:p binutils:p nsis:p abseil-cpp:p | ||||
|  | ||||
|     - name: fix line endings | ||||
|     - name: debug | ||||
|       run: | | ||||
|         git config --global core.autocrlf false | ||||
|         git config --global core.eol lf | ||||
|          | ||||
|         pacboy -Q --info protobuf:p | ||||
|         cat /mingw64/lib/pkgconfig/protobuf.pc | ||||
|         /mingw64/bin/pkg-config.exe protobuf --cflags | ||||
|         /mingw64/bin/pkg-config.exe protobuf --cflags --static | ||||
|  | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine' | ||||
|         path: 'fluxengine' | ||||
|         submodules: 'true' | ||||
|  | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
| @@ -105,17 +115,18 @@ jobs: | ||||
|  | ||||
|     - name: run | ||||
|       run: | | ||||
|         wsl sh -c 'make -C fluxengine BUILDTYPE=windows -j$(nproc)' | ||||
|         make -C fluxengine BUILDTYPE=windows | ||||
|  | ||||
|     - name: nsis | ||||
|       run: | | ||||
|         wsl sh -c 'cd fluxengine && strip fluxengine.exe -o fluxengine-stripped.exe' | ||||
|         wsl sh -c 'cd fluxengine && strip fluxengine-gui.exe -o fluxengine-gui-stripped.exe' | ||||
|         wsl sh -c 'cd fluxengine && makensis -v2 -nocd -dOUTFILE=fluxengine-installer.exe extras/windows-installer.nsi' | ||||
|         cd fluxengine | ||||
|         strip fluxengine.exe -o fluxengine-stripped.exe | ||||
|         strip fluxengine-gui.exe -o fluxengine-gui-stripped.exe | ||||
|         makensis -v2 -nocd -dOUTFILE=fluxengine-installer.exe extras/windows-installer.nsi | ||||
|  | ||||
|     - name: zip | ||||
|       run: | | ||||
|         wsl sh -c 'cd fluxengine && zip -9 fluxengine-windows.zip fluxengine.exe fluxengine-gui.exe upgrade-flux-file.exe brother120tool.exe brother240tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex fluxengine-installer.exe' | ||||
|         cd fluxengine && zip -9 fluxengine-windows.zip fluxengine.exe fluxengine-gui.exe upgrade-flux-file.exe brother120tool.exe brother240tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex fluxengine-installer.exe | ||||
|  | ||||
|     - name: Upload build artifacts | ||||
|       uses: actions/upload-artifact@v4 | ||||
|   | ||||
							
								
								
									
										7
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -24,7 +24,7 @@ jobs: | ||||
|         wsl --import fedora fedora install.tar.gz | ||||
|         wsl --set-default fedora | ||||
|         wsl sh -c 'dnf -y install https://github.com/rpmsphere/noarch/raw/master/r/rpmsphere-release-40-1.noarch.rpm' | ||||
|         wsl sh -c 'dnf -y install gcc gcc-c++ protobuf-c-compiler protobuf-devel fmt-devel systemd-devel sqlite-devel wxGTK-devel mingw32-gcc mingw32-gcc-c++ mingw32-zlib-static mingw32-protobuf-static mingw32-sqlite-static mingw32-wxWidgets3-static mingw32-libpng-static mingw32-libjpeg-static mingw32-libtiff-static mingw32-nsis png2ico' | ||||
|         wsl sh -c 'dnf -y install gcc gcc-c++ protobuf-c-compiler protobuf-devel fmt-devel systemd-devel sqlite-devel wxGTK-devel mingw32-gcc mingw32-gcc-c++ mingw32-zlib-static mingw32-protobuf-static mingw32-sqlite-static mingw32-wxWidgets3-static mingw32-libpng-static mingw32-libjpeg-static mingw32-libtiff-static mingw32-nsis png2ico ninja-build' | ||||
|  | ||||
|     - name: fix line endings | ||||
|       run: | | ||||
| @@ -97,8 +97,9 @@ jobs: | ||||
|  | ||||
|     - name: make | ||||
|       run: | | ||||
|         gmake -j2 | ||||
|         gmake | ||||
|         mv FluxEngine.pkg FluxEngine-${{ runner.arch }}.pkg | ||||
|         mv FluxEngine.app.zip FluxEngine-${{ runner.arch }}.app.zip | ||||
|  | ||||
|     - name: tag | ||||
|       uses: EndBug/latest-tag@latest | ||||
| @@ -115,6 +116,7 @@ jobs: | ||||
|         tag: dev | ||||
|         assets: |  | ||||
|           FluxEngine-${{ runner.arch }}.pkg | ||||
|           FluxEngine-${{ runner.arch }}.app.zip | ||||
|         fail-if-no-assets: false | ||||
|  | ||||
|     - name: release | ||||
| @@ -123,6 +125,7 @@ jobs: | ||||
|         name: Development build ${{ env.RELEASE_DATE }} | ||||
|         files: | | ||||
|           FluxEngine-${{ runner.arch }}.pkg | ||||
|           FluxEngine-${{ runner.arch }}.app.zip | ||||
|         tag_name: dev | ||||
|       env: | ||||
|         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|   | ||||
							
								
								
									
										36
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| [submodule "dep/imhex"] | ||||
| 	path = dep/imhex | ||||
| 	url = git@github.com:davidgiven/ImHex.git | ||||
| [submodule "dep/libwolv"] | ||||
| 	path = dep/libwolv | ||||
| 	url = https://github.com/WerWolv/libwolv.git | ||||
| [submodule "dep/imgui"] | ||||
| 	path = dep/imgui | ||||
| 	url = https://github.com/ocornut/imgui.git | ||||
| [submodule "dep/pattern-language"] | ||||
| 	path = dep/pattern-language | ||||
| 	url = https://github.com/WerWolv/PatternLanguage.git | ||||
| [submodule "dep/native-file-dialog"] | ||||
| 	path = dep/native-file-dialog | ||||
| 	url = https://github.com/btzy/nativefiledialog-extended.git | ||||
| [submodule "dep/xdgpp"] | ||||
| 	path = dep/xdgpp | ||||
| 	url = https://github.com/WerWolv/xdgpp.git | ||||
| [submodule "dep/libromfs"] | ||||
| 	path = dep/libromfs | ||||
| 	url = https://github.com/WerWolv/libromfs.git | ||||
| [submodule "dep/throwing_ptr"] | ||||
| 	path = dep/throwing_ptr | ||||
| 	url = https://github.com/rockdreamer/throwing_ptr.git | ||||
| [submodule "dep/lunasvg"] | ||||
| 	path = dep/lunasvg | ||||
| 	url = https://github.com/sammycage/lunasvg.git | ||||
| [submodule "dep/md4c"] | ||||
| 	path = dep/md4c | ||||
| 	url = https://github.com/mity/md4c | ||||
| [submodule "dep/nlohmann_json"] | ||||
| 	path = dep/nlohmann_json | ||||
| 	url = https://github.com/nlohmann/json | ||||
| [submodule "dep/cli11"] | ||||
| 	path = dep/cli11 | ||||
| 	url = https://github.com/CLIUtils/CLI11 | ||||
							
								
								
									
										110
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								Makefile
									
									
									
									
									
								
							| @@ -8,25 +8,54 @@ ifeq ($(BUILDTYPE),) | ||||
| endif | ||||
| export BUILDTYPE | ||||
|  | ||||
| OPTFLAGS = -g -O3 | ||||
|  | ||||
| ifeq ($(BUILDTYPE),windows) | ||||
| 	MINGW = i686-w64-mingw32- | ||||
| 	MINGW = x86_64-w64-mingw32- | ||||
| 	CC = $(MINGW)gcc | ||||
| 	CXX = $(MINGW)g++ -std=c++20 | ||||
| 	CFLAGS += -g -O3 | ||||
| 	CXX = $(MINGW)g++ | ||||
| 	CFLAGS += \ | ||||
| 		$(OPTFLAGS) \ | ||||
| 		-ffunction-sections \ | ||||
| 		-fdata-sections \ | ||||
| 		-Wno-attributes \ | ||||
| 		-Wa,-mbig-obj \ | ||||
| 		-static | ||||
| 	CXXFLAGS += \ | ||||
| 		-fext-numeric-literals \ | ||||
| 		$(OPTFLAGS) \ | ||||
| 		-std=c++23 \ | ||||
| 		-Wno-deprecated-enum-float-conversion \ | ||||
| 		-Wno-deprecated-enum-enum-conversion | ||||
| 	LDFLAGS += -static | ||||
| 	AR = $(MINGW)ar | ||||
| 	PKG_CONFIG = $(MINGW)pkg-config -static | ||||
| 		-Wno-deprecated-enum-enum-conversion \ | ||||
| 		-Wno-attributes \ | ||||
| 		-Wa,-mbig-obj \ | ||||
| 		-static | ||||
| 	LDFLAGS += -Wl,--gc-sections -static | ||||
| 	AR = $(MINGW)gcc-ar | ||||
| 	PKG_CONFIG = $(MINGW)pkg-config --static | ||||
| 	WINDRES = $(MINGW)windres | ||||
| 	WX_CONFIG = /usr/i686-w64-mingw32/sys-root/mingw/bin/wx-config-3.0 --static=yes | ||||
| 	NINJA = /bin/ninja | ||||
| 	PROTOC = /mingw64/bin/protoc | ||||
| 	PROTOC_SEPARATOR = ; | ||||
| 	EXT = .exe | ||||
|  | ||||
| 	AB_SANDBOX = no | ||||
| else | ||||
| 	CC = gcc | ||||
| 	CXX = g++ -std=c++17 | ||||
| 	CFLAGS = -g -O3 | ||||
| 	CC = clang | ||||
| 	CXX = clang++ | ||||
| 	CFLAGS = \ | ||||
| 		$(OPTFLAGS) \ | ||||
| 		-I/opt/homebrew/include -I/usr/local/include \ | ||||
| 		-Wno-unknown-warning-option | ||||
| 	CXXFLAGS = \ | ||||
| 		$(OPTFLAGS) \ | ||||
| 		-std=c++23 \ | ||||
| 		-fexperimental-library \ | ||||
| 		-I/opt/homebrew/include -I/usr/local/include \ | ||||
| 		-Wformat \ | ||||
| 		-Wformat-security \ | ||||
| 		-Wno-deprecated-enum-float-conversion \ | ||||
| 		-Wno-deprecated-enum-enum-conversion | ||||
| 	LDFLAGS = | ||||
| 	AR = ar | ||||
| 	PKG_CONFIG = pkg-config | ||||
| @@ -34,11 +63,10 @@ else | ||||
| 	else | ||||
| 		LDFLAGS += -pthread -Wl,--no-as-needed | ||||
| 	endif | ||||
|  | ||||
| endif | ||||
|  | ||||
| HOSTCC = gcc | ||||
| HOSTCXX = g++ -std=c++17 | ||||
| HOSTCXX = g++ -std=c++20 | ||||
| HOSTCFLAGS = -g -O3 | ||||
| HOSTLDFLAGS = | ||||
|  | ||||
| @@ -50,31 +78,33 @@ BINDIR ?= $(PREFIX)/bin | ||||
|  | ||||
| # Special Windows settings. | ||||
|  | ||||
| ifeq ($(OS), Windows_NT) | ||||
| 	EXT ?= .exe | ||||
| 	MINGWBIN = /mingw32/bin | ||||
| 	CCPREFIX = $(MINGWBIN)/ | ||||
| 	PKG_CONFIG = $(MINGWBIN)/pkg-config | ||||
| 	WX_CONFIG = /usr/bin/sh $(MINGWBIN)/wx-config --static=yes | ||||
| 	PROTOC = $(MINGWBIN)/protoc | ||||
| 	WINDRES = windres | ||||
| 	LDFLAGS += \ | ||||
| 		-static | ||||
| 	CXXFLAGS += \ | ||||
| 		-fext-numeric-literals \ | ||||
| 		-Wno-deprecated-enum-float-conversion \ | ||||
| 		-Wno-deprecated-enum-enum-conversion | ||||
|  | ||||
| 	# Required to get the gcc run - time libraries on the path. | ||||
| 	export PATH := $(PATH):$(MINGWBIN) | ||||
| endif | ||||
| #ifeq ($(OS), Windows_NT) | ||||
| #	EXT ?= .exe | ||||
| #	MINGWBIN = /mingw32/bin | ||||
| #	CCPREFIX = $(MINGWBIN)/ | ||||
| #	PKG_CONFIG = $(MINGWBIN)/pkg-config | ||||
| #	WX_CONFIG = /usr/bin/sh $(MINGWBIN)/wx-config --static=yes | ||||
| #	PROTOC = $(MINGWBIN)/protoc | ||||
| #	WINDRES = windres | ||||
| #	LDFLAGS += \ | ||||
| #		-static | ||||
| #	CXXFLAGS += \ | ||||
| #		-fext-numeric-literals \ | ||||
| #		-Wno-deprecated-enum-float-conversion \ | ||||
| #		-Wno-deprecated-enum-enum-conversion | ||||
| # | ||||
| #	# Required to get the gcc run - time libraries on the path. | ||||
| #	export PATH := $(PATH):$(MINGWBIN) | ||||
| #endif | ||||
|  | ||||
| # Special OSX settings. | ||||
|  | ||||
| ifeq ($(shell uname),Darwin) | ||||
| 	LDFLAGS += \ | ||||
| 		-framework IOKit \ | ||||
| 		-framework Foundation  | ||||
| 		-framework AppKit  \ | ||||
| 		-framework UniformTypeIdentifiers \ | ||||
| 		-framework UserNotifications | ||||
| endif | ||||
|  | ||||
| .PHONY: all | ||||
| @@ -85,33 +115,23 @@ binaries: all | ||||
| tests: all | ||||
| 	 | ||||
| README.md: $(OBJ)/scripts/+mkdocindex/mkdocindex$(EXT) | ||||
| 	@echo $(PROGRESSINFO) MKDOC $@ | ||||
| 	@echo $(PROGRESSINFO)MKDOC $@ | ||||
| 	@csplit -s -f$(OBJ)/README. README.md '/<!-- FORMATSSTART -->/' '%<!-- FORMATSEND -->%' | ||||
| 	@(cat $(OBJ)/README.00 && $< && cat $(OBJ)/README.01) > README.md | ||||
|  | ||||
| .PHONY: tests | ||||
|  | ||||
| .PHONY: install install-bin | ||||
| install:: all install-bin | ||||
|  | ||||
| clean:: | ||||
| 	$(hide) rm -rf $(REALOBJ) | ||||
|  | ||||
| install-bin: | ||||
| 	@echo "INSTALL" | ||||
| 	$(hide) install -D -v "$(OBJ)/src+fluxengine/src+fluxengine" "$(DESTDIR)$(BINDIR)/fluxengine" | ||||
| 	$(hide) install -D -v "$(OBJ)/src/gui+gui/gui+gui" "$(DESTDIR)$(BINDIR)/fluxengine-gui" | ||||
| 	$(hide) install -D -v "$(OBJ)/tools+brother120tool/tools+brother120tool" "$(DESTDIR)$(BINDIR)/brother120tool" | ||||
| 	$(hide) install -D -v "$(OBJ)/tools+brother240tool/tools+brother240tool" "$(DESTDIR)$(BINDIR)/brother240tool" | ||||
| 	$(hide) install -D -v "$(OBJ)/tools+upgrade-flux-file/tools+upgrade-flux-file" "$(DESTDIR)$(BINDIR)/upgrade-flux-file" | ||||
|  | ||||
| include build/ab.mk | ||||
|  | ||||
| DOCKERFILES = \ | ||||
| 	debian11 \ | ||||
|     debian12 \ | ||||
|     fedora40 \ | ||||
|     fedora41 | ||||
|     fedora41 \ | ||||
| 	manjaro | ||||
|  | ||||
| docker-%: tests/docker/Dockerfile.% | ||||
| 	docker build -t $* -f $< . | ||||
|   | ||||
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							| @@ -125,6 +125,7 @@ choices because they can store multiple types of file system. | ||||
| | [`hplif`](doc/disk-hplif.md) | Hewlett-Packard LIF: a variety of disk formats used by HP | 🦄 | 🦄 | LIF  | | ||||
| | [`ibm`](doc/disk-ibm.md) | IBM PC: Generic PC 3.5"/5.25" disks | 🦄 | 🦄 | FATFS  | | ||||
| | [`icl30`](doc/disk-icl30.md) | ICL Model 30: CP/M; 263kB 35-track DSSD | 🦖 |  | CPMFS  | | ||||
| | [`juku`](doc/disk-juku.md) | Juku E5104: CP/M |  |  | CPMFS  | | ||||
| | [`mac`](doc/disk-mac.md) | Macintosh: 400kB/800kB 3.5" GCR | 🦄 | 🦄 | MACHFS  | | ||||
| | [`micropolis`](doc/disk-micropolis.md) | Micropolis: 100tpi MetaFloppy disks | 🦄 | 🦄 |  | | ||||
| | [`ms2000`](doc/disk-ms2000.md) | : MS2000 Microdisk Development System |  |  | MICRODOS  | | ||||
| @@ -136,6 +137,7 @@ choices because they can store multiple types of file system. | ||||
| | [`rx50`](doc/disk-rx50.md) | Digital RX50: 400kB 5.25" 80-track 10-sector SSDD | 🦖 | 🦖 |  | | ||||
| | [`smaky6`](doc/disk-smaky6.md) | Smaky 6: 308kB 5.25" 77-track 16-sector SSDD, hard sectored | 🦖 |  | SMAKY6  | | ||||
| | [`tartu`](doc/disk-tartu.md) | Tartu: The Palivere and variations | 🦄 | 🦖 | CPMFS  | | ||||
| | [`ti99`](doc/disk-ti99.md) | TI-99: 90kB 35-track SSSD | 🦖 |  |  | | ||||
| | [`tids990`](doc/disk-tids990.md) | Texas Instruments DS990: 1126kB 8" DSSD | 🦖 | 🦖 |  | | ||||
| | [`tiki`](doc/disk-tiki.md) | Tiki 100: CP/M |  |  | CPMFS  | | ||||
| | [`victor9k`](doc/disk-victor9k.md) | Victor 9000 / Sirius One: 1224kB 5.25" DSDD GCR | 🦖 | 🦖 |  | | ||||
| @@ -257,6 +259,15 @@ package, written by Robert Leslie et al, taken from | ||||
| https://www.mars.org/home/rob/proj/hfs. It is GPL 2.0 licensed. Please see the | ||||
| contents of the directory for the full text. | ||||
|  | ||||
| As an exception, `dep/lexy` contains a partial copy of the lexy package, written | ||||
| by foonathen@github, taken from https://github.com/foonathan/lexy. It is BSL 1.0 | ||||
| licensed. Please see the contents of the directory for the full text. | ||||
|  | ||||
| As an exception, `dep/alphanum` contains a copy of the alphanum package, | ||||
| written by Dave Koelle, taken from | ||||
| https://web.archive.org/web/20210207124255/davekoelle.com/alphanum.html. It is | ||||
| MIT licensed. Please see the source for the full text. | ||||
|  | ||||
| __Important:__ Because of all these exceptions, if you distribute the | ||||
| FluxEngine package as a whole, you must comply with the terms of _all_ of the | ||||
| licensing terms. This means that __effectively the FluxEngine package is | ||||
|   | ||||
| @@ -36,8 +36,8 @@ public: | ||||
|             decodeFmMfm(rawbits).slice(0, AESLANIER_RECORD_SIZE); | ||||
|         const auto& reversed = bytes.reverseBits(); | ||||
|  | ||||
|         _sector->logicalTrack = reversed[1]; | ||||
|         _sector->logicalSide = 0; | ||||
|         _sector->logicalCylinder = reversed[1]; | ||||
|         _sector->logicalHead = 0; | ||||
|         _sector->logicalSector = reversed[2]; | ||||
|  | ||||
|         /* Check header 'checksum' (which seems far too simple to mean much). */ | ||||
|   | ||||
| @@ -59,9 +59,9 @@ public: | ||||
|         if (bytes[3] != 0x5a) | ||||
|             return; | ||||
|  | ||||
|         _sector->logicalTrack = bytes[1] >> 1; | ||||
|         _sector->logicalCylinder = bytes[1] >> 1; | ||||
|         _sector->logicalSector = bytes[2]; | ||||
|         _sector->logicalSide = bytes[1] & 1; | ||||
|         _sector->logicalHead = bytes[1] & 1; | ||||
|         _sector->status = Sector::DATA_MISSING; /* unintuitive but correct */ | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -58,13 +58,10 @@ private: | ||||
|     }; | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
|         auto trackLayout = Layout::getLayoutOfTrack( | ||||
|             trackInfo->logicalTrack, trackInfo->logicalSide); | ||||
|  | ||||
|         double clockRateUs = _config.target_clock_period_us() / 2.0; | ||||
|         int bitsPerRevolution = | ||||
|             (_config.target_rotational_period_ms() * 1000.0) / clockRateUs; | ||||
| @@ -80,7 +77,7 @@ public: | ||||
|             writeFillerRawBytes(_config.pre_sector_gap_bytes(), 0xaaaa); | ||||
|             writeRawBits(SECTOR_ID, 64); | ||||
|             writeByte(0x5a); | ||||
|             writeByte((sector->logicalTrack << 1) | sector->logicalSide); | ||||
|             writeByte((sector->logicalCylinder << 1) | sector->logicalHead); | ||||
|             writeByte(sector->logicalSector); | ||||
|             writeByte(0x5a); | ||||
|  | ||||
|   | ||||
| @@ -52,8 +52,8 @@ public: | ||||
|         Bytes header = amigaDeinterleave(ptr, 4); | ||||
|         Bytes recoveryinfo = amigaDeinterleave(ptr, 16); | ||||
|  | ||||
|         _sector->logicalTrack = header[1] >> 1; | ||||
|         _sector->logicalSide = header[1] & 1; | ||||
|         _sector->logicalCylinder = header[1] >> 1; | ||||
|         _sector->logicalHead = header[1] & 1; | ||||
|         _sector->logicalSector = header[2]; | ||||
|  | ||||
|         uint32_t wantedheaderchecksum = | ||||
|   | ||||
| @@ -84,7 +84,7 @@ static void write_sector(std::vector<bool>& bits, | ||||
|  | ||||
|     checksum = 0; | ||||
|     Bytes header = {0xff, /* Amiga 1.0 format byte */ | ||||
|         (uint8_t)((sector->logicalTrack << 1) | sector->logicalSide), | ||||
|         (uint8_t)((sector->logicalCylinder << 1) | sector->logicalHead), | ||||
|         (uint8_t)sector->logicalSector, | ||||
|         (uint8_t)(AMIGA_SECTORS_PER_TRACK - sector->logicalSector)}; | ||||
|     write_interleaved_bytes(header); | ||||
| @@ -110,7 +110,7 @@ public: | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/data/sector.h" | ||||
| #include "lib/data/layout.h" | ||||
| #include "arch/apple2/apple2.h" | ||||
| #include "arch/apple2/apple2.pb.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
| @@ -93,24 +94,25 @@ public: | ||||
|         ByteReader br(header); | ||||
|  | ||||
|         uint8_t volume = combine(br.read_be16()); | ||||
|         _sector->logicalTrack = combine(br.read_be16()); | ||||
|         _sector->logicalSide = _sector->physicalSide; | ||||
|         _sector->logicalCylinder = combine(br.read_be16()); | ||||
|         _sector->logicalHead = _ltl->logicalHead; | ||||
|         _sector->logicalSector = combine(br.read_be16()); | ||||
|         uint8_t checksum = combine(br.read_be16()); | ||||
|  | ||||
|         // If the checksum is correct, upgrade the sector from MISSING | ||||
|         // to DATA_MISSING in anticipation of its data record | ||||
|         if (checksum == | ||||
|             (volume ^ _sector->logicalTrack ^ _sector->logicalSector)) | ||||
|             (volume ^ _sector->logicalCylinder ^ _sector->logicalSector)) | ||||
|             _sector->status = | ||||
|                 Sector::DATA_MISSING; /* unintuitive but correct */ | ||||
|  | ||||
|         if (_sector->logicalSide == 1) | ||||
|             _sector->logicalTrack -= _config.apple2().side_one_track_offset(); | ||||
|         if (_sector->logicalHead == 1) | ||||
|             _sector->logicalCylinder -= | ||||
|                 _config.apple2().side_one_track_offset(); | ||||
|  | ||||
|         /* Sanity check. */ | ||||
|  | ||||
|         if (_sector->logicalTrack > 100) | ||||
|         if (_sector->logicalCylinder > 100) | ||||
|         { | ||||
|             _sector->status = Sector::MISSING; | ||||
|             return; | ||||
|   | ||||
| @@ -36,7 +36,7 @@ private: | ||||
|     const Apple2EncoderProto& _config; | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
| @@ -129,8 +129,8 @@ private: | ||||
|             // extra padding. | ||||
|             write_ff40(sector.logicalSector == 0 ? 32 : 8); | ||||
|  | ||||
|             int track = sector.logicalTrack; | ||||
|             if (sector.logicalSide == 1) | ||||
|             int track = sector.logicalCylinder; | ||||
|             if (sector.logicalHead == 1) | ||||
|                 track += _config.side_one_track_offset(); | ||||
|  | ||||
|             // Write address field: APPLE2_SECTOR_RECORD + sector identifier + | ||||
|   | ||||
| @@ -75,14 +75,14 @@ public: | ||||
|         const auto& bytes = toBytes(rawbits).slice(0, 4); | ||||
|  | ||||
|         ByteReader br(bytes); | ||||
|         _sector->logicalTrack = decode_header_gcr(br.read_be16()); | ||||
|         _sector->logicalCylinder = decode_header_gcr(br.read_be16()); | ||||
|         _sector->logicalSector = decode_header_gcr(br.read_be16()); | ||||
|  | ||||
|         /* Sanity check the values read; there's no header checksum and | ||||
|          * occasionally we get garbage due to bit errors. */ | ||||
|         if (_sector->logicalSector > 11) | ||||
|             return; | ||||
|         if (_sector->logicalTrack > 79) | ||||
|         if (_sector->logicalCylinder > 79) | ||||
|             return; | ||||
|  | ||||
|         _sector->status = Sector::DATA_MISSING; | ||||
|   | ||||
| @@ -107,7 +107,7 @@ public: | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
| @@ -127,7 +127,7 @@ public: | ||||
|             fillBitmapTo(bits, cursor, headerCursor, {true, false}); | ||||
|             write_sector_header(bits, | ||||
|                 cursor, | ||||
|                 sectorData->logicalTrack, | ||||
|                 sectorData->logicalCylinder, | ||||
|                 sectorData->logicalSector); | ||||
|             fillBitmapTo(bits, cursor, dataCursor, {true, false}); | ||||
|             write_sector_data(bits, cursor, sectorData->data); | ||||
|   | ||||
| @@ -74,8 +74,8 @@ public: | ||||
|  | ||||
|         uint8_t checksum = bytes[0]; | ||||
|         _sector->logicalSector = bytes[1]; | ||||
|         _sector->logicalSide = 0; | ||||
|         _sector->logicalTrack = bytes[2] - 1; | ||||
|         _sector->logicalHead = 0; | ||||
|         _sector->logicalCylinder = bytes[2] - 1; | ||||
|         if (checksum == xorBytes(bytes.slice(1, 4))) | ||||
|             _sector->status = | ||||
|                 Sector::DATA_MISSING; /* unintuitive but correct */ | ||||
|   | ||||
| @@ -155,7 +155,7 @@ public: | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
| @@ -178,7 +178,7 @@ public: | ||||
|         else | ||||
|             _formatByte1 = _formatByte2 = 0; | ||||
|  | ||||
|         double clockRateUs = clockPeriodForC64Track(trackInfo->logicalTrack); | ||||
|         double clockRateUs = clockPeriodForC64Track(ltl.logicalCylinder); | ||||
|         int bitsPerRevolution = 200000.0 / clockRateUs; | ||||
|  | ||||
|         std::vector<bool> bits(bitsPerRevolution); | ||||
| @@ -245,7 +245,7 @@ private: | ||||
|              *   06-07 - $0F ("off" bytes) | ||||
|              */ | ||||
|             uint8_t encodedTrack = | ||||
|                 ((sector->logicalTrack) + | ||||
|                 ((sector->logicalCylinder) + | ||||
|                     1); // C64 track numbering starts with 1. Fluxengine with 0. | ||||
|             uint8_t encodedSector = sector->logicalSector; | ||||
|             // uint8_t formatByte1 = C64_FORMAT_ID_BYTE1; | ||||
|   | ||||
| @@ -76,8 +76,8 @@ public: | ||||
|         const auto& bytes = decode(readRawBits(6 * 10)); | ||||
|  | ||||
|         _sector->logicalSector = bytes[2]; | ||||
|         _sector->logicalSide = 0; | ||||
|         _sector->logicalTrack = bytes[0]; | ||||
|         _sector->logicalHead = 0; | ||||
|         _sector->logicalCylinder = bytes[0]; | ||||
|  | ||||
|         uint16_t wantChecksum = bytes.reader().seek(4).read_be16(); | ||||
|         uint16_t gotChecksum = crc16(CCITT_POLY, 0xef21, bytes.slice(0, 4)); | ||||
|   | ||||
| @@ -126,8 +126,8 @@ public: | ||||
|             return; | ||||
|  | ||||
|         uint8_t abssector = id[2]; | ||||
|         _sector->logicalTrack = abssector >> 1; | ||||
|         _sector->logicalSide = 0; | ||||
|         _sector->logicalCylinder = abssector >> 1; | ||||
|         _sector->logicalHead = 0; | ||||
|         _sector->logicalSector = abssector & 1; | ||||
|         _sector->data.writer().append(id.slice(5, 12)).append(payload); | ||||
|  | ||||
|   | ||||
| @@ -141,11 +141,10 @@ public: | ||||
|         bw += decodeFmMfm(bits).slice(0, IBM_IDAM_LEN); | ||||
|  | ||||
|         IbmDecoderProto::TrackdataProto trackdata; | ||||
|         getTrackFormat( | ||||
|             trackdata, _sector->physicalTrack, _sector->physicalSide); | ||||
|         getTrackFormat(trackdata, _ltl->logicalCylinder, _ltl->logicalHead); | ||||
|  | ||||
|         _sector->logicalTrack = br.read_8(); | ||||
|         _sector->logicalSide = br.read_8(); | ||||
|         _sector->logicalCylinder = br.read_8(); | ||||
|         _sector->logicalHead = br.read_8(); | ||||
|         _sector->logicalSector = br.read_8(); | ||||
|         _currentSectorSize = 1 << (br.read_8() + 7); | ||||
|  | ||||
| @@ -156,11 +155,10 @@ public: | ||||
|                 Sector::DATA_MISSING; /* correct but unintuitive */ | ||||
|  | ||||
|         if (trackdata.ignore_side_byte()) | ||||
|             _sector->logicalSide = | ||||
|                 Layout::remapSidePhysicalToLogical(_sector->physicalSide); | ||||
|         _sector->logicalSide ^= trackdata.invert_side_byte(); | ||||
|             _sector->logicalHead = _ltl->logicalHead; | ||||
|         _sector->logicalHead ^= trackdata.invert_side_byte(); | ||||
|         if (trackdata.ignore_track_byte()) | ||||
|             _sector->logicalTrack = _sector->physicalTrack; | ||||
|             _sector->logicalCylinder = _ltl->logicalCylinder; | ||||
|  | ||||
|         for (int sector : trackdata.ignore_sector()) | ||||
|             if (_sector->logicalSector == sector) | ||||
| @@ -209,16 +207,14 @@ public: | ||||
|         _sector->status = | ||||
|             (wantCrc == gotCrc) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|  | ||||
|         auto layout = Layout::getLayoutOfTrack( | ||||
|             _sector->logicalTrack, _sector->logicalSide); | ||||
|         if (_currentSectorSize != layout->sectorSize) | ||||
|         if (_currentSectorSize != _ltl->sectorSize) | ||||
|             std::cerr << fmt::format( | ||||
|                 "Warning: configured sector size for t{}.h{}.s{} is {} bytes " | ||||
|                 "but that seen on disk is {} bytes\n", | ||||
|                 _sector->logicalTrack, | ||||
|                 _sector->logicalSide, | ||||
|                 _sector->logicalCylinder, | ||||
|                 _sector->logicalHead, | ||||
|                 _sector->logicalSector, | ||||
|                 layout->sectorSize, | ||||
|                 _ltl->sectorSize, | ||||
|                 _currentSectorSize); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -107,16 +107,12 @@ private: | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
|         IbmEncoderProto::TrackdataProto trackdata; | ||||
|         getEncoderTrackData( | ||||
|             trackdata, trackInfo->logicalTrack, trackInfo->logicalSide); | ||||
|  | ||||
|         auto trackLayout = Layout::getLayoutOfTrack( | ||||
|             trackInfo->logicalTrack, trackInfo->logicalSide); | ||||
|         getEncoderTrackData(trackdata, ltl.logicalCylinder, ltl.logicalHead); | ||||
|  | ||||
|         auto writeBytes = [&](const Bytes& bytes) | ||||
|         { | ||||
| @@ -152,7 +148,7 @@ public: | ||||
|  | ||||
|         uint8_t sectorSize = 0; | ||||
|         { | ||||
|             int s = trackLayout->sectorSize >> 7; | ||||
|             int s = ltl.sectorSize >> 7; | ||||
|             while (s > 1) | ||||
|             { | ||||
|                 s >>= 1; | ||||
| @@ -202,9 +198,9 @@ public: | ||||
|                         bw.write_8(MFM_RECORD_SEPARATOR_BYTE); | ||||
|                 } | ||||
|                 bw.write_8(idamUnencoded); | ||||
|                 bw.write_8(sectorData->logicalTrack); | ||||
|                 bw.write_8(sectorData->logicalCylinder); | ||||
|                 bw.write_8( | ||||
|                     sectorData->logicalSide ^ trackdata.invert_side_byte()); | ||||
|                     sectorData->logicalHead ^ trackdata.invert_side_byte()); | ||||
|                 bw.write_8(sectorData->logicalSector); | ||||
|                 bw.write_8(sectorSize); | ||||
|                 uint16_t crc = crc16(CCITT_POLY, header); | ||||
| @@ -237,8 +233,7 @@ public: | ||||
|                 } | ||||
|                 bw.write_8(damUnencoded); | ||||
|  | ||||
|                 Bytes truncatedData = | ||||
|                     sectorData->data.slice(0, trackLayout->sectorSize); | ||||
|                 Bytes truncatedData = sectorData->data.slice(0, ltl.sectorSize); | ||||
|                 bw += truncatedData; | ||||
|                 uint16_t crc = crc16(CCITT_POLY, data); | ||||
|                 bw.write_be16(crc); | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/data/sector.h" | ||||
| #include "lib/data/layout.h" | ||||
| #include "arch/macintosh/macintosh.h" | ||||
| #include "lib/core/bytes.h" | ||||
| #include "fmt/format.h" | ||||
| @@ -146,7 +147,7 @@ public: | ||||
|         auto header = toBytes(readRawBits(7 * 8)).slice(0, 7); | ||||
|  | ||||
|         uint8_t encodedTrack = decode_data_gcr(header[0]); | ||||
|         if (encodedTrack != (_sector->physicalTrack & 0x3f)) | ||||
|         if (encodedTrack != (_ltl->logicalCylinder & 0x3f)) | ||||
|             return; | ||||
|  | ||||
|         uint8_t encodedSector = decode_data_gcr(header[1]); | ||||
| @@ -157,8 +158,8 @@ public: | ||||
|         if (encodedSector > 11) | ||||
|             return; | ||||
|  | ||||
|         _sector->logicalTrack = _sector->physicalTrack; | ||||
|         _sector->logicalSide = decode_side(encodedSide); | ||||
|         _sector->logicalCylinder = _ltl->logicalCylinder; | ||||
|         _sector->logicalHead = decode_side(encodedSide); | ||||
|         _sector->logicalSector = encodedSector; | ||||
|         uint8_t gotsum = | ||||
|             (encodedTrack ^ encodedSector ^ encodedSide ^ formatByte) & 0x3f; | ||||
|   | ||||
| @@ -181,10 +181,10 @@ static void write_sector(std::vector<bool>& bits, | ||||
|         write_bits(bits, cursor, 0xff3fcff3fcffLL, 6 * 8); /* sync */ | ||||
|     write_bits(bits, cursor, MAC_SECTOR_RECORD, 3 * 8); | ||||
|  | ||||
|     uint8_t encodedTrack = sector->logicalTrack & 0x3f; | ||||
|     uint8_t encodedTrack = sector->logicalCylinder & 0x3f; | ||||
|     uint8_t encodedSector = sector->logicalSector; | ||||
|     uint8_t encodedSide = | ||||
|         encode_side(sector->logicalTrack, sector->logicalSide); | ||||
|         encode_side(sector->logicalCylinder, sector->logicalHead); | ||||
|     uint8_t formatByte = MAC_FORMAT_BYTE; | ||||
|     uint8_t headerChecksum = | ||||
|         (encodedTrack ^ encodedSector ^ encodedSide ^ formatByte) & 0x3f; | ||||
| @@ -220,11 +220,11 @@ public: | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
|         double clockRateUs = clockRateUsForTrack(trackInfo->logicalTrack); | ||||
|         double clockRateUs = clockRateUsForTrack(ltl.logicalCylinder); | ||||
|         int bitsPerRevolution = 200000.0 / clockRateUs; | ||||
|         std::vector<bool> bits(bitsPerRevolution); | ||||
|         unsigned cursor = 0; | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| #include "lib/data/fluxpattern.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/data/sector.h" | ||||
| #include "lib/data/layout.h" | ||||
| #include "arch/micropolis/micropolis.h" | ||||
| #include "lib/core/bytes.h" | ||||
| #include "fmt/format.h" | ||||
| @@ -222,14 +223,14 @@ public: | ||||
|         if (syncByte != 0xFF) | ||||
|             return; | ||||
|  | ||||
|         _sector->logicalTrack = br.read_8(); | ||||
|         _sector->logicalSide = _sector->physicalSide; | ||||
|         _sector->logicalCylinder = br.read_8(); | ||||
|         _sector->logicalHead = _ltl->logicalHead; | ||||
|         _sector->logicalSector = br.read_8(); | ||||
|         if (_sector->logicalSector > 15) | ||||
|             return; | ||||
|         if (_sector->logicalTrack > 76) | ||||
|         if (_sector->logicalCylinder > 76) | ||||
|             return; | ||||
|         if (_sector->logicalTrack != _sector->physicalTrack) | ||||
|         if (_sector->logicalCylinder != _ltl->logicalCylinder) | ||||
|             return; | ||||
|  | ||||
|         br.read(10); /* OS data or padding */ | ||||
|   | ||||
| @@ -40,7 +40,7 @@ static void write_sector(std::vector<bool>& bits, | ||||
|     { | ||||
|         ByteWriter writer(sectorData); | ||||
|         writer.write_8(0xff); /* Sync */ | ||||
|         writer.write_8(sector->logicalTrack); | ||||
|         writer.write_8(sector->logicalCylinder); | ||||
|         writer.write_8(sector->logicalSector); | ||||
|         for (int i = 0; i < 10; i++) | ||||
|             writer.write_8(0); /* Padding */ | ||||
| @@ -87,7 +87,7 @@ public: | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| #include "lib/data/fluxmapreader.h" | ||||
| #include "lib/data/fluxpattern.h" | ||||
| #include "lib/data/sector.h" | ||||
| #include "lib/data/layout.h" | ||||
| #include <string.h> | ||||
|  | ||||
| const int SECTOR_SIZE = 256; | ||||
| @@ -64,8 +65,8 @@ public: | ||||
|             gotChecksum += br.read_be16(); | ||||
|         uint16_t wantChecksum = br.read_be16(); | ||||
|  | ||||
|         _sector->logicalTrack = _sector->physicalTrack; | ||||
|         _sector->logicalSide = _sector->physicalSide; | ||||
|         _sector->logicalCylinder = _ltl->logicalCylinder; | ||||
|         _sector->logicalHead = _ltl->logicalHead; | ||||
|         _sector->logicalSector = _currentSector; | ||||
|         _sector->data = bytes.slice(0, SECTOR_SIZE).swab(); | ||||
|         _sector->status = | ||||
|   | ||||
| @@ -17,6 +17,7 @@ | ||||
| #include "lib/data/fluxpattern.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/data/sector.h" | ||||
| #include "lib/data/layout.h" | ||||
| #include "arch/northstar/northstar.h" | ||||
| #include "lib/core/bytes.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
| @@ -159,9 +160,9 @@ public: | ||||
|         auto bytes = decodeFmMfm(rawbits).slice(0, recordSize); | ||||
|         ByteReader br(bytes); | ||||
|  | ||||
|         _sector->logicalSide = _sector->physicalSide; | ||||
|         _sector->logicalHead = _ltl->logicalHead; | ||||
|         _sector->logicalSector = _hardSectorId; | ||||
|         _sector->logicalTrack = _sector->physicalTrack; | ||||
|         _sector->logicalCylinder = _ltl->logicalCylinder; | ||||
|  | ||||
|         if (headerSize == NORTHSTAR_HEADER_SIZE_DD) | ||||
|         { | ||||
|   | ||||
| @@ -129,7 +129,7 @@ public: | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include "protocol.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/data/sector.h" | ||||
| #include "lib/data/layout.h" | ||||
| #include "arch/smaky6/smaky6.h" | ||||
| #include "lib/core/bytes.h" | ||||
| #include "lib/core/crc.h" | ||||
| @@ -129,11 +130,11 @@ public: | ||||
|         uint8_t wantedChecksum = br.read_8(); | ||||
|         uint8_t gotChecksum = sumBytes(data) & 0xff; | ||||
|  | ||||
|         if (track != _sector->physicalTrack) | ||||
|         if (track != _ltl->logicalCylinder) | ||||
|             return; | ||||
|  | ||||
|         _sector->logicalTrack = _sector->physicalTrack; | ||||
|         _sector->logicalSide = _sector->physicalSide; | ||||
|         _sector->logicalCylinder = _ltl->physicalCylinder; | ||||
|         _sector->logicalHead = _ltl->logicalHead; | ||||
|         _sector->logicalSector = _sectorId; | ||||
|  | ||||
|         _sector->data = data; | ||||
|   | ||||
| @@ -43,8 +43,8 @@ public: | ||||
|  | ||||
|         ByteReader br(bytes); | ||||
|         uint8_t track = br.read_8(); | ||||
|         _sector->logicalTrack = track >> 1; | ||||
|         _sector->logicalSide = track & 1; | ||||
|         _sector->logicalCylinder = track >> 1; | ||||
|         _sector->logicalHead = track & 1; | ||||
|         br.skip(1); /* seems always to be 1 */ | ||||
|         _sector->logicalSector = br.read_8(); | ||||
|         uint8_t wantChecksum = br.read_8(); | ||||
|   | ||||
| @@ -17,7 +17,7 @@ public: | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
| @@ -83,7 +83,7 @@ private: | ||||
|             Bytes bytes; | ||||
|             ByteWriter bw(bytes); | ||||
|             bw.write_8( | ||||
|                 (sectorData->logicalTrack << 1) | sectorData->logicalSide); | ||||
|                 (sectorData->logicalCylinder << 1) | sectorData->logicalHead); | ||||
|             bw.write_8(1); | ||||
|             bw.write_8(sectorData->logicalSector); | ||||
|             bw.write_8(~sumBytes(bytes.slice(0, 3))); | ||||
|   | ||||
| @@ -64,8 +64,8 @@ public: | ||||
|         uint16_t gotChecksum = | ||||
|             crc16(CCITT_POLY, bytes.slice(1, TIDS990_SECTOR_RECORD_SIZE - 3)); | ||||
|  | ||||
|         _sector->logicalSide = br.read_8() >> 3; | ||||
|         _sector->logicalTrack = br.read_8(); | ||||
|         _sector->logicalHead = br.read_8() >> 3; | ||||
|         _sector->logicalCylinder = br.read_8(); | ||||
|         br.read_8(); /* number of sectors per track */ | ||||
|         _sector->logicalSector = br.read_8(); | ||||
|         br.read_be16(); /* sector size */ | ||||
|   | ||||
| @@ -59,7 +59,7 @@ private: | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
| @@ -95,8 +95,8 @@ public: | ||||
|  | ||||
|                 writeBytes(12, 0x55); | ||||
|                 bw.write_8(am1Unencoded); | ||||
|                 bw.write_8(sectorData->logicalSide << 3); | ||||
|                 bw.write_8(sectorData->logicalTrack); | ||||
|                 bw.write_8(sectorData->logicalHead << 3); | ||||
|                 bw.write_8(sectorData->logicalCylinder); | ||||
|                 bw.write_8(_config.sector_count()); | ||||
|                 bw.write_8(sectorData->logicalSector); | ||||
|                 bw.write_be16(sectorData->data.size()); | ||||
|   | ||||
| @@ -80,11 +80,11 @@ public: | ||||
|         _sector->logicalSector = bytes[1]; | ||||
|         uint8_t gotChecksum = bytes[2]; | ||||
|  | ||||
|         _sector->logicalTrack = rawTrack & 0x7f; | ||||
|         _sector->logicalSide = rawTrack >> 7; | ||||
|         _sector->logicalCylinder = rawTrack & 0x7f; | ||||
|         _sector->logicalHead = rawTrack >> 7; | ||||
|         uint8_t wantChecksum = bytes[0] + bytes[1]; | ||||
|         if ((_sector->logicalSector > 20) || (_sector->logicalTrack > 85) || | ||||
|             (_sector->logicalSide > 1)) | ||||
|         if ((_sector->logicalSector > 20) || (_sector->logicalCylinder > 85) || | ||||
|             (_sector->logicalHead > 1)) | ||||
|             return; | ||||
|  | ||||
|         if (wantChecksum == gotChecksum) | ||||
|   | ||||
| @@ -112,7 +112,7 @@ static void write_sector(std::vector<bool>& bits, | ||||
|     write_one_bits(bits, cursor, trackdata.pre_header_sync_bits()); | ||||
|     write_bits(bits, cursor, VICTOR9K_SECTOR_RECORD, 10); | ||||
|  | ||||
|     uint8_t encodedTrack = sector.logicalTrack | (sector.logicalSide << 7); | ||||
|     uint8_t encodedTrack = sector.logicalCylinder | (sector.logicalHead << 7); | ||||
|     uint8_t encodedSector = sector.logicalSector; | ||||
|     write_bytes(bits, | ||||
|         cursor, | ||||
| @@ -164,13 +164,12 @@ private: | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|     std::unique_ptr<Fluxmap> encode(const LogicalTrackLayout& ltl, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
|         Victor9kEncoderProto::TrackdataProto trackdata; | ||||
|         getTrackFormat( | ||||
|             trackdata, trackInfo->logicalTrack, trackInfo->logicalSide); | ||||
|         getTrackFormat(trackdata, ltl.logicalCylinder, ltl.logicalHead); | ||||
|  | ||||
|         unsigned bitsPerRevolution = (trackdata.rotational_period_ms() * 1e3) / | ||||
|                                      trackdata.clock_period_us(); | ||||
|   | ||||
| @@ -34,11 +34,11 @@ public: | ||||
|         ByteReader br(bytes); | ||||
|  | ||||
|         _sector->logicalSector = br.read_8() & 0x1f; | ||||
|         _sector->logicalSide = 0; | ||||
|         _sector->logicalTrack = br.read_8() & 0x7f; | ||||
|         _sector->logicalHead = 0; | ||||
|         _sector->logicalCylinder = br.read_8() & 0x7f; | ||||
|         if (_sector->logicalSector > 31) | ||||
|             return; | ||||
|         if (_sector->logicalTrack > 80) | ||||
|         if (_sector->logicalCylinder > 80) | ||||
|             return; | ||||
|  | ||||
|         _sector->data = br.read(132); | ||||
|   | ||||
							
								
								
									
										37
									
								
								build.py
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								build.py
									
									
									
									
									
								
							| @@ -7,6 +7,12 @@ from glob import glob | ||||
| import config | ||||
| import re | ||||
|  | ||||
| # Hack for building on Fedora/WSL; executables get the .exe extension, | ||||
| # but the build system detects it as Linux. | ||||
| import build.toolchain | ||||
|  | ||||
| toolchain.Toolchain.EXE = "$(EXT)" | ||||
|  | ||||
| package(name="protobuf_lib", package="protobuf") | ||||
| package(name="z_lib", package="zlib") | ||||
| package(name="fmt_lib", package="fmt", fallback="dep/fmt") | ||||
| @@ -22,7 +28,7 @@ else: | ||||
|         ("acorndfs", "", "--200"), | ||||
|         ("agat", "", ""), | ||||
|         ("amiga", "", ""), | ||||
|         ("apple2", "", "--140 40track_drive"), | ||||
|         ("apple2", "", "--140 --drivetype=40"), | ||||
|         ("atarist", "", "--360"), | ||||
|         ("atarist", "", "--370"), | ||||
|         ("atarist", "", "--400"), | ||||
| @@ -32,17 +38,17 @@ else: | ||||
|         ("atarist", "", "--800"), | ||||
|         ("atarist", "", "--820"), | ||||
|         ("bk", "", ""), | ||||
|         ("brother", "", "--120 40track_drive"), | ||||
|         ("brother", "", "--120 --drivetype=40"), | ||||
|         ("brother", "", "--240"), | ||||
|         ( | ||||
|             "commodore", | ||||
|             "scripts/commodore1541_test.textpb", | ||||
|             "--171 40track_drive", | ||||
|             "--171 --drivetype=40", | ||||
|         ), | ||||
|         ( | ||||
|             "commodore", | ||||
|             "scripts/commodore1541_test.textpb", | ||||
|             "--192 40track_drive", | ||||
|             "--192 --drivetype=40", | ||||
|         ), | ||||
|         ("commodore", "", "--800"), | ||||
|         ("commodore", "", "--1620"), | ||||
| @@ -54,17 +60,17 @@ else: | ||||
|         ("ibm", "", "--1232"), | ||||
|         ("ibm", "", "--1440"), | ||||
|         ("ibm", "", "--1680"), | ||||
|         ("ibm", "", "--180 40track_drive"), | ||||
|         ("ibm", "", "--160 40track_drive"), | ||||
|         ("ibm", "", "--320 40track_drive"), | ||||
|         ("ibm", "", "--360 40track_drive"), | ||||
|         ("ibm", "", "--180 --drivetype=40"), | ||||
|         ("ibm", "", "--160 --drivetype=40"), | ||||
|         ("ibm", "", "--320 --drivetype=40"), | ||||
|         ("ibm", "", "--360 --drivetype=40"), | ||||
|         ("ibm", "", "--720_96"), | ||||
|         ("ibm", "", "--720_135"), | ||||
|         ("mac", "scripts/mac400_test.textpb", "--400"), | ||||
|         ("mac", "scripts/mac800_test.textpb", "--800"), | ||||
|         ("n88basic", "", ""), | ||||
|         ("rx50", "", ""), | ||||
|         ("tartu", "", "--390 40track_drive"), | ||||
|         ("tartu", "", "--390 --drivetype=40"), | ||||
|         ("tartu", "", "--780"), | ||||
|         ("tids990", "", ""), | ||||
|         ("victor9k", "", "--612"), | ||||
| @@ -87,7 +93,7 @@ else: | ||||
|                     + c[1] | ||||
|                     + "' '" | ||||
|                     + c[2] | ||||
|                     + "' $(dir $[outs[0]]) > /dev/null" | ||||
|                     + "' $[dirname(filenameof(outs[0]))] > /dev/null" | ||||
|                 ], | ||||
|                 label="CORPUSTEST", | ||||
|             ) | ||||
| @@ -98,11 +104,18 @@ export( | ||||
|     name="all", | ||||
|     items={ | ||||
|         "fluxengine$(EXT)": "src+fluxengine", | ||||
|         "fluxengine-gui$(EXT)": "src/gui", | ||||
|         "fluxengine-gui$(EXT)": "src/gui2", | ||||
|         "brother120tool$(EXT)": "tools+brother120tool", | ||||
|         "brother240tool$(EXT)": "tools+brother240tool", | ||||
|         "upgrade-flux-file$(EXT)": "tools+upgrade-flux-file", | ||||
|     } | ||||
|     | ({"FluxEngine.pkg": "src/gui+fluxengine_pkg"} if config.osx else {}), | ||||
|     | ( | ||||
|         { | ||||
|             "FluxEngine.pkg": "src/gui2+fluxengine_pkg", | ||||
|             "FluxEngine.app.zip": "src/gui2+fluxengine_app_zip", | ||||
|         } | ||||
|         if config.osx | ||||
|         else {} | ||||
|     ), | ||||
|     deps=["tests", "src/formats+docs", "scripts+mkdocindex"] + corpustests, | ||||
| ) | ||||
|   | ||||
| @@ -26,7 +26,7 @@ def main(): | ||||
|                 print("link", sf) | ||||
|             os.makedirs(dirname(sf), exist_ok=True) | ||||
|             try: | ||||
|                 os.link(abspath(f), sf) | ||||
|                 os.symlink(abspath(f), sf) | ||||
|             except PermissionError: | ||||
|                 shutil.copy(f, sf) | ||||
|  | ||||
| @@ -38,6 +38,11 @@ def main(): | ||||
|             df = dirname(f) | ||||
|             if df: | ||||
|                 os.makedirs(df, exist_ok=True) | ||||
|  | ||||
|             try: | ||||
|                 os.remove(f) | ||||
|             except FileNotFoundError: | ||||
|                 pass | ||||
|             os.rename(sf, f) | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										72
									
								
								build/ab.mk
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								build/ab.mk
									
									
									
									
									
								
							| @@ -15,16 +15,17 @@ HOSTCC ?= gcc | ||||
| HOSTCXX ?= g++ | ||||
| HOSTAR ?= ar | ||||
| HOSTCFLAGS ?= -g -Og | ||||
| HOSTCXXFLAGS ?= $(HOSTCFLAGS) | ||||
| HOSTLDFLAGS ?= -g | ||||
|  | ||||
| CC ?= $(HOSTCC) | ||||
| CXX ?= $(HOSTCXX) | ||||
| AR ?= $(HOSTAR) | ||||
| CFLAGS ?= $(HOSTCFLAGS) | ||||
| CXXFLAGS ?= $(CFLAGS) | ||||
| LDFLAGS ?= $(HOSTLDFLAGS) | ||||
|  | ||||
| export PKG_CONFIG | ||||
| export HOST_PKG_CONFIG | ||||
| NINJA ?= ninja | ||||
|  | ||||
| ifdef VERBOSE | ||||
| 	hide = | ||||
| @@ -63,32 +64,36 @@ EXT ?= | ||||
|  | ||||
| CWD=$(shell pwd) | ||||
|  | ||||
| ifeq ($(AB_ENABLE_PROGRESS_INFO),true) | ||||
| 	ifeq ($(PROGRESSINFO),) | ||||
| 	# The first make invocation here has to have its output discarded or else it | ||||
| 	# produces spurious 'Leaving directory' messages... don't know why. | ||||
| 	rulecount := $(strip $(shell $(MAKE) --no-print-directory -q $(OBJ)/build.mk PROGRESSINFO=1 > /dev/null \ | ||||
| 		&& $(MAKE) --no-print-directory -n $(MAKECMDGOALS) PROGRESSINFO=XXXPROGRESSINFOXXX | grep XXXPROGRESSINFOXXX | wc -l)) | ||||
| 	ruleindex := 1 | ||||
| 	PROGRESSINFO = "[$(ruleindex)/$(rulecount)]$(eval ruleindex := $(shell expr $(ruleindex) + 1)) " | ||||
| 	endif | ||||
| else | ||||
| 	PROGRESSINFO = "" | ||||
| endif | ||||
| define newline | ||||
|  | ||||
| PKG_CONFIG_HASHES = $(OBJ)/.pkg-config-hashes/target-$(word 1, $(shell $(PKG_CONFIG) --list-all | md5sum)) | ||||
| HOST_PKG_CONFIG_HASHES = $(OBJ)/.pkg-config-hashes/host-$(word 1, $(shell $(HOST_PKG_CONFIG) --list-all | md5sum)) | ||||
|  | ||||
| $(OBJ)/build.mk : $(PKG_CONFIG_HASHES) $(HOST_PKG_CONFIG_HASHES) | ||||
| $(PKG_CONFIG_HASHES) $(HOST_PKG_CONFIG_HASHES) &: | ||||
| 	$(hide) rm -rf $(OBJ)/.pkg-config-hashes | ||||
| 	$(hide) mkdir -p $(OBJ)/.pkg-config-hashes | ||||
| 	$(hide) touch $(PKG_CONFIG_HASHES) $(HOST_PKG_CONFIG_HASHES) | ||||
| endef | ||||
|  | ||||
| include $(OBJ)/build.mk | ||||
| define check_for_command | ||||
|   $(shell command -v $1 >/dev/null || (echo "Required command '$1' missing" >&2 && kill $$PPID)) | ||||
| endef | ||||
|  | ||||
| MAKEFLAGS += -r -j$(shell nproc) | ||||
| .DELETE_ON_ERROR: | ||||
| $(call check_for_command,ninja) | ||||
| $(call check_for_command,cmp) | ||||
| $(call check_for_command,$(PYTHON)) | ||||
|  | ||||
| pkg-config-hash = $(shell ($(PKG_CONFIG) --list-all && $(HOST_PKG_CONFIG) --list-all) | md5sum) | ||||
| build-files = $(shell find . -name .obj -prune -o \( -name 'build.py' -a -type f \) -print) $(wildcard build/*.py) $(wildcard config.py) | ||||
| build-file-timestamps = $(shell ls -l $(build-files) | md5sum) | ||||
|  | ||||
| # Wipe the build file (forcing a regeneration) if the make environment is different. | ||||
| # (Conveniently, this includes the pkg-config hash calculated above.) | ||||
|  | ||||
| ignored-variables = MAKE_RESTARTS .VARIABLES MAKECMDGOALS MAKEFLAGS MFLAGS PAGER _ \ | ||||
| 	DESKTOP_STARTUP_ID XAUTHORITY ICEAUTHORITY SSH_AUTH_SOCK SESSION_MANAGER \ | ||||
| 	INVOCATION_ID SYSTEMD_EXEC_PID MANAGER_PID SSH_AGENT_PID JOURNAL_STREAM \ | ||||
| 	GPG_TTY WINDOWID MANAGERPID MAKE_TERMOUT MAKE_TERMERR OLDPWD | ||||
| $(shell mkdir -p $(OBJ)) | ||||
| $(file >$(OBJ)/newvars.txt,$(foreach v,$(filter-out $(ignored-variables),$(.VARIABLES)),$(v)=$($(v))$(newline))) | ||||
| $(shell touch $(OBJ)/vars.txt) | ||||
| #$(shell diff -u $(OBJ)/vars.txt $(OBJ)/newvars.txt >&2) | ||||
| $(shell cmp -s $(OBJ)/newvars.txt $(OBJ)/vars.txt || (rm -f $(OBJ)/build.ninja && echo "Environment changed --- regenerating" >&2)) | ||||
| $(shell mv $(OBJ)/newvars.txt $(OBJ)/vars.txt) | ||||
|  | ||||
| .PHONY: update-ab | ||||
| update-ab: | ||||
| @@ -102,10 +107,19 @@ clean:: | ||||
| 	@echo CLEAN | ||||
| 	$(hide) rm -rf $(OBJ) | ||||
|  | ||||
| compile_commands.json: $(OBJ)/build.ninja | ||||
| 	+$(hide) $(NINJA) -f $(OBJ)/build.ninja -t compdb > $@ | ||||
|  | ||||
| export PYTHONHASHSEED = 1 | ||||
| build-files = $(shell find . -name 'build.py') $(wildcard build/*.py) $(wildcard config.py) | ||||
| $(OBJ)/build.mk: Makefile $(build-files) build/ab.mk | ||||
| $(OBJ)/build.ninja $(OBJ)/build.targets &: | ||||
| 	@echo "AB" | ||||
| 	@mkdir -p $(OBJ) | ||||
| 	$(hide) $(PYTHON) -X pycache_prefix=$(OBJ)/__pycache__ build/ab.py -o $@ build.py \ | ||||
| 		|| rm -f $@ | ||||
| 	$(hide) $(PYTHON) -X pycache_prefix=$(OBJ)/__pycache__ build/ab.py \ | ||||
| 		-o $(OBJ) build.py \ | ||||
| 		-v $(OBJ)/vars.txt \ | ||||
| 		|| (rm -f $@ && false) | ||||
|  | ||||
| include $(OBJ)/build.targets | ||||
| .PHONY: $(ninja-targets) | ||||
| .NOTPARALLEL: | ||||
| $(ninja-targets): $(OBJ)/build.ninja | ||||
| 	+$(hide) $(NINJA) -f $(OBJ)/build.ninja $@ | ||||
|   | ||||
							
								
								
									
										2
									
								
								build/ab.ninja
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								build/ab.ninja
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| rule rule | ||||
|     command = $command | ||||
							
								
								
									
										275
									
								
								build/ab.py
									
									
									
									
									
								
							
							
						
						
									
										275
									
								
								build/ab.py
									
									
									
									
									
								
							| @@ -1,36 +1,32 @@ | ||||
| from collections import namedtuple | ||||
| from copy import copy | ||||
| from importlib.machinery import SourceFileLoader, PathFinder, ModuleSpec | ||||
| from os.path import * | ||||
| from pathlib import Path | ||||
| from typing import Iterable | ||||
| import argparse | ||||
| import ast | ||||
| import builtins | ||||
| from copy import copy | ||||
| import functools | ||||
| import hashlib | ||||
| import importlib | ||||
| import importlib.util | ||||
| from importlib.machinery import ( | ||||
|     SourceFileLoader, | ||||
|     PathFinder, | ||||
|     ModuleSpec, | ||||
| ) | ||||
| import inspect | ||||
| import os | ||||
| import re | ||||
| import string | ||||
| import sys | ||||
| import hashlib | ||||
| import re | ||||
| import ast | ||||
| from collections import namedtuple | ||||
| import types | ||||
|  | ||||
| VERBOSE_MK_FILE = False | ||||
| VERBOSE_NINJA_FILE = False | ||||
|  | ||||
| verbose = False | ||||
| quiet = False | ||||
| cwdStack = [""] | ||||
| targets = {} | ||||
| unmaterialisedTargets = {}  # dict, not set, to get consistent ordering | ||||
| materialisingStack = [] | ||||
| defaultGlobals = {} | ||||
| globalId = 1 | ||||
| wordCache = {} | ||||
| outputTargets = set() | ||||
|  | ||||
| RE_FORMAT_SPEC = re.compile( | ||||
|     r"(?:(?P<fill>[\s\S])?(?P<align>[<>=^]))?" | ||||
| @@ -52,6 +48,15 @@ sys.path += ["."] | ||||
| old_import = builtins.__import__ | ||||
|  | ||||
|  | ||||
| class Environment(types.SimpleNamespace): | ||||
|     def setdefault(self, name, value): | ||||
|         if not hasattr(self, name): | ||||
|             setattr(self, name, value) | ||||
|  | ||||
|  | ||||
| G = Environment() | ||||
|  | ||||
|  | ||||
| class PathFinderImpl(PathFinder): | ||||
|     def find_spec(self, fullname, path, target=None): | ||||
|         # The second test here is needed for Python 3.9. | ||||
| @@ -102,27 +107,88 @@ def error(message): | ||||
|     raise ABException(message) | ||||
|  | ||||
|  | ||||
| def _undo_escaped_dollar(s, op): | ||||
|     return s.replace(f"$${op}", f"${op}") | ||||
|  | ||||
|  | ||||
| class BracketedFormatter(string.Formatter): | ||||
|     def parse(self, format_string): | ||||
|         while format_string: | ||||
|             left, *right = format_string.split("$[", 1) | ||||
|             if not right: | ||||
|                 yield (left, None, None, None) | ||||
|             m = re.search(f"(?:[^$]|^)()\\$\\[()", format_string) | ||||
|             if not m: | ||||
|                 yield ( | ||||
|                     _undo_escaped_dollar(format_string, "["), | ||||
|                     None, | ||||
|                     None, | ||||
|                     None, | ||||
|                 ) | ||||
|                 break | ||||
|             right = right[0] | ||||
|             left = format_string[: m.start(1)] | ||||
|             right = format_string[m.end(2) :] | ||||
|  | ||||
|             offset = len(right) + 1 | ||||
|             try: | ||||
|                 ast.parse(right) | ||||
|             except SyntaxError as e: | ||||
|                 if not str(e).startswith("unmatched ']'"): | ||||
|                 if not str(e).startswith(f"unmatched ']'"): | ||||
|                     raise e | ||||
|                 offset = e.offset | ||||
|  | ||||
|             expr = right[0 : offset - 1] | ||||
|             format_string = right[offset:] | ||||
|  | ||||
|             yield (left if left else None, expr, None, None) | ||||
|             yield ( | ||||
|                 _undo_escaped_dollar(left, "[") if left else None, | ||||
|                 expr, | ||||
|                 None, | ||||
|                 None, | ||||
|             ) | ||||
|  | ||||
|  | ||||
| class GlobalFormatter(string.Formatter): | ||||
|     def parse(self, format_string): | ||||
|         while format_string: | ||||
|             m = re.search(f"(?:[^$]|^)()\\$\\(([^)]*)\\)()", format_string) | ||||
|             if not m: | ||||
|                 yield ( | ||||
|                     format_string, | ||||
|                     None, | ||||
|                     None, | ||||
|                     None, | ||||
|                 ) | ||||
|                 break | ||||
|             left = format_string[: m.start(1)] | ||||
|             var = m[2] | ||||
|             format_string = format_string[m.end(3) :] | ||||
|  | ||||
|             yield ( | ||||
|                 left if left else None, | ||||
|                 var, | ||||
|                 None, | ||||
|                 None, | ||||
|             ) | ||||
|  | ||||
|     def get_field(self, name, a1, a2): | ||||
|         return ( | ||||
|             getattr(G, name), | ||||
|             False, | ||||
|         ) | ||||
|  | ||||
|     def format_field(self, value, format_spec): | ||||
|         if not value: | ||||
|             return "" | ||||
|         return str(value) | ||||
|  | ||||
|  | ||||
| globalFormatter = GlobalFormatter() | ||||
|  | ||||
|  | ||||
| def substituteGlobalVariables(value): | ||||
|     while True: | ||||
|         oldValue = value | ||||
|         value = globalFormatter.format(value) | ||||
|         if value == oldValue: | ||||
|             return _undo_escaped_dollar(value, "(") | ||||
|  | ||||
|  | ||||
| def Rule(func): | ||||
| @@ -187,12 +253,10 @@ def _isiterable(xs): | ||||
|  | ||||
| class Target: | ||||
|     def __init__(self, cwd, name): | ||||
|         if verbose: | ||||
|             print("rule('%s', cwd='%s'" % (name, cwd)) | ||||
|         self.name = name | ||||
|         self.localname = self.name.rsplit("+")[-1] | ||||
|         self.traits = set() | ||||
|         self.dir = join("$(OBJ)", name) | ||||
|         self.dir = join(G.OBJ, name) | ||||
|         self.ins = [] | ||||
|         self.outs = [] | ||||
|         self.deps = [] | ||||
| @@ -232,7 +296,8 @@ class Target: | ||||
|                     [selfi.templateexpand(f) for f in filenamesof(value)] | ||||
|                 ) | ||||
|  | ||||
|         return Formatter().format(s) | ||||
|         s = Formatter().format(s) | ||||
|         return substituteGlobalVariables(s) | ||||
|  | ||||
|     def materialise(self, replacing=False): | ||||
|         if self not in unmaterialisedTargets: | ||||
| @@ -341,10 +406,10 @@ def targetof(value, cwd=None): | ||||
|             elif value.startswith("./"): | ||||
|                 value = normpath(join(cwd, value)) | ||||
|         # Explicit directories are always raw files. | ||||
|         elif value.endswith("/"): | ||||
|         if value.endswith("/"): | ||||
|             return _filetarget(value, cwd) | ||||
|         # Anything starting with a variable expansion is always a raw file. | ||||
|         elif value.startswith("$"): | ||||
|         # Anything in .obj is a raw file. | ||||
|         elif value.startswith(outputdir) or value.startswith(G.OBJ): | ||||
|             return _filetarget(value, cwd) | ||||
|  | ||||
|         # If this is not a rule lookup... | ||||
| @@ -467,79 +532,75 @@ def emit(*args, into=None): | ||||
|     if into is not None: | ||||
|         into += [s] | ||||
|     else: | ||||
|         outputFp.write(s) | ||||
|         ninjaFp.write(s) | ||||
|  | ||||
|  | ||||
| def shell(*args): | ||||
|     s = "".join(args) + "\n" | ||||
|     shellFp.write(s) | ||||
|  | ||||
|  | ||||
| def emit_rule(self, ins, outs, cmds=[], label=None): | ||||
|     name = self.name | ||||
|     fins_list = filenamesof(ins) | ||||
|     fins = set(fins_list) | ||||
|     fouts = filenamesof(outs) | ||||
|     nonobjs = [f for f in fouts if not f.startswith("$(OBJ)")] | ||||
|     fins = [self.templateexpand(f) for f in set(filenamesof(ins))] | ||||
|     fouts = [self.templateexpand(f) for f in filenamesof(outs)] | ||||
|  | ||||
|     global outputTargets | ||||
|     outputTargets.update(fouts) | ||||
|     outputTargets.add(name) | ||||
|  | ||||
|     emit("") | ||||
|     if VERBOSE_MK_FILE: | ||||
|     if VERBOSE_NINJA_FILE: | ||||
|         for k, v in self.args.items(): | ||||
|             emit(f"# {k} = {v}") | ||||
|  | ||||
|     lines = [] | ||||
|     if nonobjs: | ||||
|         emit("clean::", into=lines) | ||||
|         emit("\t$(hide) rm -f", *nonobjs, into=lines) | ||||
|  | ||||
|     hashable = cmds + fins_list + fouts | ||||
|     hash = hashlib.sha1(bytes("\n".join(hashable), "utf-8")).hexdigest() | ||||
|     hashfile = join(self.dir, f"hash_{hash}") | ||||
|  | ||||
|     global globalId | ||||
|     emit(".PHONY:", name, into=lines) | ||||
|     if outs: | ||||
|         outsn = globalId | ||||
|         globalId = globalId + 1 | ||||
|         insn = globalId | ||||
|         globalId = globalId + 1 | ||||
|         os.makedirs(self.dir, exist_ok=True) | ||||
|         rule = [] | ||||
|  | ||||
|         emit(f"OUTS_{outsn}", "=", *fouts, into=lines) | ||||
|         emit(f"INS_{insn}", "=", *fins, into=lines) | ||||
|         emit( | ||||
|             name, | ||||
|             ":", | ||||
|             hashfile, | ||||
|             f"$(OUTS_{outsn})", | ||||
|             into=lines, | ||||
|         ) | ||||
|         emit(f"$(OUTS_{outsn})", ":", hashfile, into=lines) | ||||
|         emit(hashfile, ":", f"$(INS_{insn})", into=lines) | ||||
|         if G.AB_SANDBOX == "yes": | ||||
|             sandbox = join(self.dir, "sandbox") | ||||
|             emit(f"rm -rf {sandbox}", into=rule) | ||||
|             emit( | ||||
|                 f"{G.PYTHON} build/_sandbox.py --link -s", sandbox, *fins, into=rule | ||||
|             ) | ||||
|             for c in cmds: | ||||
|                 emit(f"(cd {sandbox} &&", c, ")", into=rule) | ||||
|             emit( | ||||
|                 f"{G.PYTHON} build/_sandbox.py --export -s", | ||||
|                 sandbox, | ||||
|                 *fouts, | ||||
|                 into=rule, | ||||
|             ) | ||||
|         else: | ||||
|             for c in cmds: | ||||
|                 emit(c, into=rule) | ||||
|  | ||||
|         ruletext = "".join(rule) | ||||
|         if len(ruletext) > 7000: | ||||
|             rulehash = hashlib.sha1(ruletext.encode()).hexdigest() | ||||
|  | ||||
|             rulef = join(self.dir, f"rule-{rulehash}.sh") | ||||
|             with open(rulef, "wt") as fp: | ||||
|                 fp.write("set -e\n") | ||||
|                 fp.write(ruletext) | ||||
|  | ||||
|             emit("build", *fouts, ":rule", *fins) | ||||
|             emit(" command=sh", rulef) | ||||
|         else: | ||||
|             emit("build", *fouts, ":rule", *fins) | ||||
|             emit( | ||||
|                 " command=", | ||||
|                 "&&".join([s.strip() for s in rule]).replace("$", "$$"), | ||||
|             ) | ||||
|         if label: | ||||
|             emit("\t$(hide)", "$(ECHO) $(PROGRESSINFO)" + label, into=lines) | ||||
|             emit(" description=", label) | ||||
|         emit("build", name, ":phony", *fouts) | ||||
|  | ||||
|         sandbox = join(self.dir, "sandbox") | ||||
|         emit("\t$(hide)", f"rm -rf {sandbox}", into=lines) | ||||
|         emit( | ||||
|             "\t$(hide)", | ||||
|             "$(PYTHON) build/_sandbox.py --link -s", | ||||
|             sandbox, | ||||
|             f"$(INS_{insn})", | ||||
|             into=lines, | ||||
|         ) | ||||
|         for c in cmds: | ||||
|             emit(f"\t$(hide) cd {sandbox} && (", c, ")", into=lines) | ||||
|         emit( | ||||
|             "\t$(hide)", | ||||
|             "$(PYTHON) build/_sandbox.py --export -s", | ||||
|             sandbox, | ||||
|             f"$(OUTS_{outsn})", | ||||
|             into=lines, | ||||
|         ) | ||||
|     else: | ||||
|         assert len(cmds) == 0, "rules with no outputs cannot have commands" | ||||
|         emit(name, ":", *fins, into=lines) | ||||
|         emit("build", name, ":phony", *fins) | ||||
|  | ||||
|     outputFp.write("".join(lines)) | ||||
|  | ||||
|     if outs: | ||||
|         emit(f"\t$(hide) touch {hashfile}") | ||||
|     emit("") | ||||
|  | ||||
|  | ||||
| @@ -586,47 +647,66 @@ def export(self, name=None, items: TargetsMap = {}, deps: Targets = []): | ||||
|         dest = self.targetof(dest) | ||||
|         outs += [dest] | ||||
|  | ||||
|         destf = filenameof(dest) | ||||
|         destf = self.templateexpand(filenameof(dest)) | ||||
|         outputTargets.update([destf]) | ||||
|  | ||||
|         srcs = filenamesof([src]) | ||||
|         assert ( | ||||
|             len(srcs) == 1 | ||||
|         ), "a dependency of an exported file must have exactly one output file" | ||||
|         srcf = self.templateexpand(srcs[0]) | ||||
|  | ||||
|         subrule = simplerule( | ||||
|             name=f"{self.localname}/{destf}", | ||||
|             cwd=self.cwd, | ||||
|             ins=[srcs[0]], | ||||
|             outs=[destf], | ||||
|             commands=["$(CP) -H %s %s" % (srcs[0], destf)], | ||||
|             label="", | ||||
|             commands=["$(CP) -H %s %s" % (srcf, destf)], | ||||
|             label="EXPORT", | ||||
|         ) | ||||
|         subrule.materialise() | ||||
|  | ||||
|     self.ins = [] | ||||
|     self.outs = deps + outs | ||||
|     outputTargets.add(name) | ||||
|  | ||||
|     emit("") | ||||
|     emit(".PHONY:", name) | ||||
|     emit(name, ":", *filenamesof(outs + deps)) | ||||
|     emit( | ||||
|         "build", | ||||
|         name, | ||||
|         ":phony", | ||||
|         *[self.templateexpand(f) for f in filenamesof(outs + deps)], | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     parser = argparse.ArgumentParser() | ||||
|     parser.add_argument("-v", "--verbose", action="store_true") | ||||
|     parser.add_argument("-q", "--quiet", action="store_true") | ||||
|     parser.add_argument("-o", "--output") | ||||
|     parser.add_argument("-v", "--varfile") | ||||
|     parser.add_argument("-o", "--outputdir") | ||||
|     parser.add_argument("-D", "--define", action="append", default=[]) | ||||
|     parser.add_argument("files", nargs="+") | ||||
|     args = parser.parse_args() | ||||
|  | ||||
|     global verbose | ||||
|     verbose = args.verbose | ||||
|  | ||||
|     global quiet | ||||
|     quiet = args.quiet | ||||
|  | ||||
|     global outputFp | ||||
|     outputFp = open(args.output, "wt") | ||||
|     vardefs = args.define | ||||
|     if args.varfile: | ||||
|         with open(args.varfile, "rt") as fp: | ||||
|             vardefs = vardefs + list(fp) | ||||
|  | ||||
|     for line in vardefs: | ||||
|         if "=" in line: | ||||
|             name, value = line.split("=", 1) | ||||
|             G.setdefault(name.strip(), value.strip()) | ||||
|     G.setdefault("AB_SANDBOX", "yes") | ||||
|  | ||||
|     global ninjaFp, shellFp, outputdir | ||||
|     outputdir = args.outputdir | ||||
|     G.setdefault("OBJ", outputdir) | ||||
|     ninjaFp = open(outputdir + "/build.ninja", "wt") | ||||
|     ninjaFp.write(f"include build/ab.ninja\n") | ||||
|  | ||||
|     for k in ["Rule"]: | ||||
|         defaultGlobals[k] = globals()[k] | ||||
| @@ -641,7 +721,10 @@ def main(): | ||||
|     while unmaterialisedTargets: | ||||
|         t = next(iter(unmaterialisedTargets)) | ||||
|         t.materialise() | ||||
|     emit("AB_LOADED = 1\n") | ||||
|  | ||||
|     with open(outputdir + "/build.targets", "wt") as fp: | ||||
|         fp.write("ninja-targets =") | ||||
|         fp.write(substituteGlobalVariables(" ".join(outputTargets))) | ||||
|  | ||||
|  | ||||
| main() | ||||
|   | ||||
							
								
								
									
										55
									
								
								build/c.py
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								build/c.py
									
									
									
									
									
								
							| @@ -7,23 +7,22 @@ from build.ab import ( | ||||
|     flatten, | ||||
|     simplerule, | ||||
|     emit, | ||||
|     G, | ||||
| ) | ||||
| from build.utils import filenamesmatchingof, stripext, collectattrs | ||||
| from build.utils import stripext, collectattrs | ||||
| from build.toolchain import Toolchain, HostToolchain | ||||
| from os.path import * | ||||
|  | ||||
| emit( | ||||
|     """ | ||||
| ifeq ($(OSX),no) | ||||
| STARTGROUP ?= -Wl,--start-group | ||||
| ENDGROUP ?= -Wl,--end-group | ||||
| endif | ||||
| """ | ||||
| ) | ||||
| if G.OSX != "yes": | ||||
|     G.STARTGROUP = "-Wl,--start-group" | ||||
|     G.ENDGROUP = "-Wl,--end-group" | ||||
| else: | ||||
|     G.STARTGROUP = "" | ||||
|     G.ENDGROUP = "" | ||||
|  | ||||
| Toolchain.CC = ["$(CC) -c -o $[outs[0]] $[ins[0]] $(CFLAGS) $[cflags]"] | ||||
| Toolchain.CPP = ["$(CC) -E -P -o $[outs] $[cflags] -x c $[ins]"] | ||||
| Toolchain.CXX = ["$(CXX) -c -o $[outs[0]] $[ins[0]] $(CFLAGS) $[cflags]"] | ||||
| Toolchain.CXX = ["$(CXX) -c -o $[outs[0]] $[ins[0]] $(CXXFLAGS) $[cflags]"] | ||||
| Toolchain.AR = ["$(AR) cqs $[outs[0]] $[ins]"] | ||||
| Toolchain.ARXX = ["$(AR) cqs $[outs[0]] $[ins]"] | ||||
| Toolchain.CLINK = [ | ||||
| @@ -70,13 +69,9 @@ def _toolchain_find_header_targets(deps, initial=[]): | ||||
| Toolchain.find_c_header_targets = _toolchain_find_header_targets | ||||
|  | ||||
|  | ||||
| HostToolchain.CC = [ | ||||
|     "$(HOSTCC) -c -o $[outs[0]] $[ins[0]] $(HOSTCFLAGS) $[cflags]" | ||||
| ] | ||||
| HostToolchain.CC = ["$(HOSTCC) -c -o $[outs[0]] $[ins[0]] $(HOSTCFLAGS) $[cflags]"] | ||||
| HostToolchain.CPP = ["$(HOSTCC) -E -P -o $[outs] $[cflags] -x c $[ins]"] | ||||
| HostToolchain.CXX = [ | ||||
|     "$(HOSTCXX) -c -o $[outs[0]] $[ins[0]] $(HOSTCFLAGS) $[cflags]" | ||||
| ] | ||||
| HostToolchain.CXX = ["$(HOSTCXX) -c -o $[outs[0]] $[ins[0]] $(HOSTCFLAGS) $[cflags]"] | ||||
| HostToolchain.AR = ["$(HOSTAR) cqs $[outs[0]] $[ins]"] | ||||
| HostToolchain.ARXX = ["$(HOSTAR) cqs $[outs[0]] $[ins]"] | ||||
| HostToolchain.CLINK = [ | ||||
| @@ -102,9 +97,7 @@ def _indirect(deps, name): | ||||
|     return r | ||||
|  | ||||
|  | ||||
| def cfileimpl( | ||||
|     self, name, srcs, deps, suffix, commands, label, toolchain, cflags | ||||
| ): | ||||
| def cfileimpl(self, name, srcs, deps, suffix, commands, label, toolchain, cflags): | ||||
|     outleaf = "=" + stripext(basename(filenameof(srcs[0]))) + suffix | ||||
|  | ||||
|     hdr_deps = toolchain.find_c_header_targets(deps) | ||||
| @@ -114,9 +107,7 @@ def cfileimpl( | ||||
|         if ("cheader_deps" not in d.args) and ("clibrary_deps" not in d.args) | ||||
|     ] | ||||
|     hdr_files = collectattrs(targets=hdr_deps, name="cheader_files") | ||||
|     cflags = collectattrs( | ||||
|         targets=hdr_deps, name="caller_cflags", initial=cflags | ||||
|     ) | ||||
|     cflags = collectattrs(targets=hdr_deps, name="caller_cflags", initial=cflags) | ||||
|  | ||||
|     t = simplerule( | ||||
|         replaces=self, | ||||
| @@ -194,7 +185,7 @@ def findsources(self, srcs, deps, cflags, filerule, toolchain, cwd): | ||||
|     for s in flatten(srcs): | ||||
|         objs += [ | ||||
|             filerule( | ||||
|                 name=join(self.localname, _removeprefix(f, "$(OBJ)/")), | ||||
|                 name=join(self.localname, _removeprefix(f, G.OBJ + "/")), | ||||
|                 srcs=[f], | ||||
|                 deps=deps, | ||||
|                 cflags=sorted(set(cflags)), | ||||
| @@ -239,9 +230,7 @@ def libraryimpl( | ||||
|         i = 0 | ||||
|         for dest, src in hdrs.items(): | ||||
|             s = filenamesof([src]) | ||||
|             assert ( | ||||
|                 len(s) == 1 | ||||
|             ), "the target of a header must return exactly one file" | ||||
|             assert len(s) == 1, "the target of a header must return exactly one file" | ||||
|  | ||||
|             cs += [f"$(CP) $[ins[{i}]] $[outs[{i}]]"] | ||||
|             outs += ["=" + dest] | ||||
| @@ -431,20 +420,16 @@ def programimpl( | ||||
|     label, | ||||
|     filerule, | ||||
| ): | ||||
|     cfiles = findsources( | ||||
|         self, srcs, deps, cflags, filerule, toolchain, self.cwd | ||||
|     ) | ||||
|     cfiles = findsources(self, srcs, deps, cflags, filerule, toolchain, self.cwd) | ||||
|  | ||||
|     lib_deps = toolchain.find_c_library_targets(deps) | ||||
|     libs = collectattrs(targets=lib_deps, name="clibrary_files") | ||||
|     ldflags = collectattrs( | ||||
|         targets=lib_deps, name="caller_ldflags", initial=ldflags | ||||
|     ) | ||||
|     ldflags = collectattrs(targets=lib_deps, name="caller_ldflags", initial=ldflags) | ||||
|  | ||||
|     simplerule( | ||||
|         replaces=self, | ||||
|         ins=cfiles + libs, | ||||
|         outs=[f"={self.localname}$(EXT)"], | ||||
|         outs=[f"={self.localname}{toolchain.EXE}"], | ||||
|         deps=deps, | ||||
|         label=label, | ||||
|         commands=commands, | ||||
| @@ -558,9 +543,7 @@ def hostcxxprogram( | ||||
|  | ||||
| def _cppfileimpl(self, name, srcs, deps, cflags, toolchain): | ||||
|     hdr_deps = _indirect(deps, "cheader_deps") | ||||
|     cflags = collectattrs( | ||||
|         targets=hdr_deps, name="caller_cflags", initial=cflags | ||||
|     ) | ||||
|     cflags = collectattrs(targets=hdr_deps, name="caller_cflags", initial=cflags) | ||||
|  | ||||
|     simplerule( | ||||
|         replaces=self, | ||||
|   | ||||
							
								
								
									
										10
									
								
								build/pkg.py
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								build/pkg.py
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| from build.ab import Rule, Target | ||||
| from build.ab import Rule, Target, G | ||||
| import os | ||||
| import subprocess | ||||
|  | ||||
| @@ -31,8 +31,8 @@ class _PkgConfig: | ||||
|         return self.package_properties[p] | ||||
|  | ||||
|  | ||||
| TargetPkgConfig = _PkgConfig(os.getenv("PKG_CONFIG")) | ||||
| HostPkgConfig = _PkgConfig(os.getenv("HOST_PKG_CONFIG")) | ||||
| TargetPkgConfig = _PkgConfig(G.PKG_CONFIG) | ||||
| HostPkgConfig = _PkgConfig(G.HOST_PKG_CONFIG) | ||||
|  | ||||
|  | ||||
| def _package(self, name, package, fallback, pkgconfig): | ||||
| @@ -49,9 +49,7 @@ def _package(self, name, package, fallback, pkgconfig): | ||||
|         self.traits.update({"clibrary", "cxxlibrary"}) | ||||
|         return | ||||
|  | ||||
|     assert ( | ||||
|         fallback | ||||
|     ), f"Required package '{package}' not installed when materialising target '$[name]'" | ||||
|     assert fallback, f"Required package '{package}' not installed" | ||||
|  | ||||
|     if "cheader_deps" in fallback.args: | ||||
|         self.args["cheader_deps"] = fallback.args["cheader_deps"] | ||||
|   | ||||
| @@ -1,18 +1,16 @@ | ||||
| from build.ab import Rule, Targets, emit, simplerule, filenamesof | ||||
| from build.ab import Rule, Targets, emit, simplerule, filenamesof, G | ||||
| from build.utils import filenamesmatchingof, collectattrs | ||||
| from os.path import join, abspath, dirname, relpath | ||||
| from build.pkg import has_package | ||||
|  | ||||
| emit( | ||||
|     """ | ||||
| PROTOC ?= protoc | ||||
| HOSTPROTOC ?= protoc | ||||
| """ | ||||
| ) | ||||
| G.setdefault("PROTOC", "protoc") | ||||
| G.setdefault("PROTOC_SEPARATOR", ":") | ||||
| G.setdefault("HOSTPROTOC", "hostprotoc") | ||||
|  | ||||
| assert has_package("protobuf"), "required package 'protobuf' not installed" | ||||
|  | ||||
|  | ||||
|  | ||||
| def _getprotodeps(deps): | ||||
|     r = set() | ||||
|     for d in deps: | ||||
| @@ -23,7 +21,7 @@ def _getprotodeps(deps): | ||||
| @Rule | ||||
| def proto(self, name, srcs: Targets = [], deps: Targets = []): | ||||
|     protodeps = _getprotodeps(deps) | ||||
|     descriptorlist = ":".join( | ||||
|     descriptorlist = (G.PROTOC_SEPARATOR).join( | ||||
|         [ | ||||
|             relpath(f, start=self.dir) | ||||
|             for f in filenamesmatchingof(protodeps, "*.descriptor") | ||||
| @@ -50,7 +48,7 @@ def proto(self, name, srcs: Targets = [], deps: Targets = []): | ||||
|                             f"--descriptor_set_out={self.localname}.descriptor", | ||||
|                         ] | ||||
|                         + ( | ||||
|                             [f"--descriptor_set_in={descriptorlist}"] | ||||
|                             [f"--descriptor_set_in='{descriptorlist}'"] | ||||
|                             if descriptorlist | ||||
|                             else [] | ||||
|                         ) | ||||
| @@ -93,7 +91,7 @@ def protocc(self, name, srcs: Targets = [], deps: Targets = []): | ||||
|         outs += ["=" + cc, "=" + h] | ||||
|  | ||||
|     protodeps = _getprotodeps(deps + srcs) | ||||
|     descriptorlist = ":".join( | ||||
|     descriptorlist = G.PROTOC_SEPARATOR.join( | ||||
|         [ | ||||
|             relpath(f, start=self.dir) | ||||
|             for f in filenamesmatchingof(protodeps, "*.descriptor") | ||||
| @@ -114,7 +112,7 @@ def protocc(self, name, srcs: Targets = [], deps: Targets = []): | ||||
|                         "$(PROTOC)", | ||||
|                         "--proto_path=.", | ||||
|                         "--cpp_out=.", | ||||
|                         f"--descriptor_set_in={descriptorlist}", | ||||
|                         f"--descriptor_set_in='{descriptorlist}'", | ||||
|                     ] | ||||
|                     + protos | ||||
|                 ) | ||||
|   | ||||
| @@ -1,5 +1,10 @@ | ||||
| import platform | ||||
|  | ||||
| _is_windows = (platform.system() == "Windows") | ||||
|  | ||||
| class Toolchain: | ||||
|     PREFIX = "" | ||||
|     EXE = ".exe" if _is_windows else "" | ||||
|  | ||||
|  | ||||
| class HostToolchain(Toolchain): | ||||
|   | ||||
| @@ -7,10 +7,13 @@ from build.ab import ( | ||||
|     cwdStack, | ||||
|     error, | ||||
|     simplerule, | ||||
|     G | ||||
| ) | ||||
| from os.path import relpath, splitext, join, basename, isfile | ||||
| from glob import iglob | ||||
| import fnmatch | ||||
| import subprocess | ||||
| import shutil | ||||
|  | ||||
|  | ||||
| def filenamesmatchingof(xs, pattern): | ||||
| @@ -51,6 +54,16 @@ def itemsof(pattern, root=None, cwd=None): | ||||
|     return result | ||||
|  | ||||
|  | ||||
| def does_command_exist(cmd): | ||||
|     basecmd = cmd.strip().split()[0] | ||||
|     return shutil.which(basecmd) | ||||
|  | ||||
|  | ||||
| def shell(cmd): | ||||
|     r = subprocess.check_output([G.SHELL, "-c", cmd]) | ||||
|     return r.decode("utf-8").strip() | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def objectify(self, name, src: Target, symbol): | ||||
|     simplerule( | ||||
|   | ||||
| @@ -7,9 +7,7 @@ from build.ab import ( | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def zip( | ||||
|     self, name, flags="", items: TargetsMap = {}, extension="zip", label="ZIP" | ||||
| ): | ||||
| def zip(self, name, flags="", items: TargetsMap = {}, extension="zip", label="ZIP"): | ||||
|     cs = ["$(PYTHON) build/_zip.py -z $[outs]"] | ||||
|  | ||||
|     ins = [] | ||||
|   | ||||
| @@ -35,7 +35,7 @@ clibrary( | ||||
|         "./config.h", | ||||
|         "./src/adflib.h", | ||||
|     ], | ||||
|     cflags=["-Idep/adflib", "-Idep/adflib/src"], | ||||
|     cflags=["-Wno-stringop-overflow"], | ||||
|     hdrs={ | ||||
|         "adf_blk.h": "./src/adf_blk.h", | ||||
|         "adf_defs.h": "./src/adf_defs.h", | ||||
|   | ||||
							
								
								
									
										2
									
								
								dep/alphanum/UPSTREAM.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								dep/alphanum/UPSTREAM.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| Downloaded from: | ||||
| https://web.archive.org/web/20210918044134/http://davekoelle.com/files/alphanum.hpp | ||||
							
								
								
									
										450
									
								
								dep/alphanum/alphanum.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										450
									
								
								dep/alphanum/alphanum.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,450 @@ | ||||
| #ifndef ALPHANUM__HPP | ||||
| #define ALPHANUM__HPP | ||||
|  | ||||
| /* | ||||
|  Released under the MIT License - https://opensource.org/licenses/MIT | ||||
|  | ||||
|  Permission is hereby granted, free of charge, to any person obtaining | ||||
|  a copy of this software and associated documentation files (the "Software"), | ||||
|  to deal in the Software without restriction, including without limitation | ||||
|  the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  and/or sell copies of the Software, and to permit persons to whom the | ||||
|  Software is furnished to do so, subject to the following conditions: | ||||
|  | ||||
|  The above copyright notice and this permission notice shall be included | ||||
|  in all copies or substantial portions of the Software. | ||||
|  | ||||
|  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
|  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
|  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||
|  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | ||||
|  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||||
|  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||||
|  USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
|  | ||||
| /* $Header: /code/doj/alphanum.hpp,v 1.3 2008/01/28 23:06:47 doj Exp $ */ | ||||
|  | ||||
| #include <cassert> | ||||
| #include <functional> | ||||
| #include <string> | ||||
| #include <sstream> | ||||
|  | ||||
| #ifdef ALPHANUM_LOCALE | ||||
| #include <cctype> | ||||
| #endif | ||||
|  | ||||
| #ifdef DOJDEBUG | ||||
| #include <iostream> | ||||
| #include <typeinfo> | ||||
| #endif | ||||
|  | ||||
| // TODO: make comparison with hexadecimal numbers. Extend the alphanum_comp() function by traits to choose between decimal and hexadecimal. | ||||
|  | ||||
| namespace doj | ||||
| { | ||||
|  | ||||
|   // anonymous namespace for functions we use internally. But if you | ||||
|   // are coding in C, you can use alphanum_impl() directly, since it | ||||
|   // uses not C++ features. | ||||
|   namespace { | ||||
|  | ||||
|     // if you want to honour the locale settings for detecting digit | ||||
|     // characters, you should define ALPHANUM_LOCALE | ||||
| #ifdef ALPHANUM_LOCALE | ||||
|     /** wrapper function for ::isdigit() */ | ||||
|     bool alphanum_isdigit(int c) | ||||
|     { | ||||
|       return isdigit(c); | ||||
|     } | ||||
| #else | ||||
|     /** this function does not consider the current locale and only | ||||
| 	works with ASCII digits. | ||||
| 	@return true if c is a digit character | ||||
|     */ | ||||
|     bool alphanum_isdigit(const char c) | ||||
|     { | ||||
|       return c>='0' && c<='9'; | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     /** | ||||
|        compare l and r with strcmp() semantics, but using | ||||
|        the "Alphanum Algorithm". This function is designed to read | ||||
|        through the l and r strings only one time, for | ||||
|        maximum performance. It does not allocate memory for | ||||
|        substrings. It can either use the C-library functions isdigit() | ||||
|        and atoi() to honour your locale settings, when recognizing | ||||
|        digit characters when you "#define ALPHANUM_LOCALE=1" or use | ||||
|        it's own digit character handling which only works with ASCII | ||||
|        digit characters, but provides better performance. | ||||
|  | ||||
|        @param l NULL-terminated C-style string | ||||
|        @param r NULL-terminated C-style string | ||||
|        @return negative if l<r, 0 if l equals r, positive if l>r | ||||
|      */ | ||||
|     int alphanum_impl(const char *l, const char *r) | ||||
|     { | ||||
|       enum mode_t { STRING, NUMBER } mode=STRING; | ||||
|  | ||||
|       while(*l && *r) | ||||
| 	{ | ||||
| 	  if(mode == STRING) | ||||
| 	    { | ||||
| 	      char l_char, r_char; | ||||
| 	      while((l_char=*l) && (r_char=*r)) | ||||
| 		{ | ||||
| 		  // check if this are digit characters | ||||
| 		  const bool l_digit=alphanum_isdigit(l_char), r_digit=alphanum_isdigit(r_char); | ||||
| 		  // if both characters are digits, we continue in NUMBER mode | ||||
| 		  if(l_digit && r_digit) | ||||
| 		    { | ||||
| 		      mode=NUMBER; | ||||
| 		      break; | ||||
| 		    } | ||||
| 		  // if only the left character is a digit, we have a result | ||||
| 		  if(l_digit) return -1; | ||||
| 		  // if only the right character is a digit, we have a result | ||||
| 		  if(r_digit) return +1; | ||||
| 		  // compute the difference of both characters | ||||
| 		  const int diff=l_char - r_char; | ||||
| 		  // if they differ we have a result | ||||
| 		  if(diff != 0) return diff; | ||||
| 		  // otherwise process the next characters | ||||
| 		  ++l; | ||||
| 		  ++r; | ||||
| 		} | ||||
| 	    } | ||||
| 	  else // mode==NUMBER | ||||
| 	    { | ||||
| #ifdef ALPHANUM_LOCALE | ||||
| 	      // get the left number | ||||
| 	      char *end; | ||||
| 	      unsigned long l_int=strtoul(l, &end, 0); | ||||
| 	      l=end; | ||||
|  | ||||
| 	      // get the right number | ||||
| 	      unsigned long r_int=strtoul(r, &end, 0); | ||||
| 	      r=end; | ||||
| #else | ||||
| 	      // get the left number | ||||
| 	      unsigned long l_int=0; | ||||
| 	      while(*l && alphanum_isdigit(*l)) | ||||
| 		{ | ||||
| 		  // TODO: this can overflow | ||||
| 		  l_int=l_int*10 + *l-'0'; | ||||
| 		  ++l; | ||||
| 		} | ||||
|  | ||||
| 	      // get the right number | ||||
| 	      unsigned long r_int=0; | ||||
| 	      while(*r && alphanum_isdigit(*r)) | ||||
| 		{ | ||||
| 		  // TODO: this can overflow | ||||
| 		  r_int=r_int*10 + *r-'0'; | ||||
| 		  ++r; | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| 	      // if the difference is not equal to zero, we have a comparison result | ||||
| 	      const long diff=l_int-r_int; | ||||
| 	      if(diff != 0) | ||||
| 		return diff; | ||||
|  | ||||
| 	      // otherwise we process the next substring in STRING mode | ||||
| 	      mode=STRING; | ||||
| 	    } | ||||
| 	} | ||||
|  | ||||
|       if(*r) return -1; | ||||
|       if(*l) return +1; | ||||
|       return 0; | ||||
|     } | ||||
|  | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|      Compare left and right with the same semantics as strcmp(), but with the | ||||
|      "Alphanum Algorithm" which produces more human-friendly | ||||
|      results. The classes lT and rT must implement "std::ostream | ||||
|      operator<< (std::ostream&, const Ty&)". | ||||
|  | ||||
|      @return negative if left<right, 0 if left==right, positive if left>right. | ||||
|   */ | ||||
|   template <typename lT, typename rT> | ||||
|   int alphanum_comp(const lT& left, const rT& right) | ||||
|   { | ||||
| #ifdef DOJDEBUG | ||||
|     std::clog << "alphanum_comp<" << typeid(left).name() << "," << typeid(right).name() << "> " << left << "," << right << std::endl; | ||||
| #endif | ||||
|     std::ostringstream l; l << left; | ||||
|     std::ostringstream r; r << right; | ||||
|     return alphanum_impl(l.str().c_str(), r.str().c_str()); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|      Compare l and r with the same semantics as strcmp(), but with | ||||
|      the "Alphanum Algorithm" which produces more human-friendly | ||||
|      results. | ||||
|  | ||||
|      @return negative if l<r, 0 if l==r, positive if l>r. | ||||
|   */ | ||||
|   template <> | ||||
|   int alphanum_comp<std::string>(const std::string& l, const std::string& r) | ||||
|   { | ||||
| #ifdef DOJDEBUG | ||||
|     std::clog << "alphanum_comp<std::string,std::string> " << l << "," << r << std::endl; | ||||
| #endif | ||||
|     return alphanum_impl(l.c_str(), r.c_str()); | ||||
|   } | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   // now follow a lot of overloaded alphanum_comp() functions to get a | ||||
|   // direct call to alphanum_impl() upon the various combinations of c | ||||
|   // and c++ strings. | ||||
|  | ||||
|   /** | ||||
|      Compare l and r with the same semantics as strcmp(), but with | ||||
|      the "Alphanum Algorithm" which produces more human-friendly | ||||
|      results. | ||||
|  | ||||
|      @return negative if l<r, 0 if l==r, positive if l>r. | ||||
|   */ | ||||
|   int alphanum_comp(char* l, char* r) | ||||
|   { | ||||
|     assert(l); | ||||
|     assert(r); | ||||
| #ifdef DOJDEBUG | ||||
|     std::clog << "alphanum_comp<char*,char*> " << l << "," << r << std::endl; | ||||
| #endif | ||||
|     return alphanum_impl(l, r); | ||||
|   } | ||||
|  | ||||
|   int alphanum_comp(const char* l, const char* r) | ||||
|   { | ||||
|     assert(l); | ||||
|     assert(r); | ||||
| #ifdef DOJDEBUG | ||||
|     std::clog << "alphanum_comp<const char*,const char*> " << l << "," << r << std::endl; | ||||
| #endif | ||||
|     return alphanum_impl(l, r); | ||||
|   } | ||||
|  | ||||
|   int alphanum_comp(char* l, const char* r) | ||||
|   { | ||||
|     assert(l); | ||||
|     assert(r); | ||||
| #ifdef DOJDEBUG | ||||
|     std::clog << "alphanum_comp<char*,const char*> " << l << "," << r << std::endl; | ||||
| #endif | ||||
|     return alphanum_impl(l, r); | ||||
|   } | ||||
|  | ||||
|   int alphanum_comp(const char* l, char* r) | ||||
|   { | ||||
|     assert(l); | ||||
|     assert(r); | ||||
| #ifdef DOJDEBUG | ||||
|     std::clog << "alphanum_comp<const char*,char*> " << l << "," << r << std::endl; | ||||
| #endif | ||||
|     return alphanum_impl(l, r); | ||||
|   } | ||||
|  | ||||
|   int alphanum_comp(const std::string& l, char* r) | ||||
|   { | ||||
|     assert(r); | ||||
| #ifdef DOJDEBUG | ||||
|     std::clog << "alphanum_comp<std::string,char*> " << l << "," << r << std::endl; | ||||
| #endif | ||||
|     return alphanum_impl(l.c_str(), r); | ||||
|   } | ||||
|  | ||||
|   int alphanum_comp(char* l, const std::string& r) | ||||
|   { | ||||
|     assert(l); | ||||
| #ifdef DOJDEBUG | ||||
|     std::clog << "alphanum_comp<char*,std::string> " << l << "," << r << std::endl; | ||||
| #endif | ||||
|     return alphanum_impl(l, r.c_str()); | ||||
|   } | ||||
|  | ||||
|   int alphanum_comp(const std::string& l, const char* r) | ||||
|   { | ||||
|     assert(r); | ||||
| #ifdef DOJDEBUG | ||||
|     std::clog << "alphanum_comp<std::string,const char*> " << l << "," << r << std::endl; | ||||
| #endif | ||||
|     return alphanum_impl(l.c_str(), r); | ||||
|   } | ||||
|  | ||||
|   int alphanum_comp(const char* l, const std::string& r) | ||||
|   { | ||||
|     assert(l); | ||||
| #ifdef DOJDEBUG | ||||
|     std::clog << "alphanum_comp<const char*,std::string> " << l << "," << r << std::endl; | ||||
| #endif | ||||
|     return alphanum_impl(l, r.c_str()); | ||||
|   } | ||||
|  | ||||
|   //////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   /** | ||||
|      Functor class to compare two objects with the "Alphanum | ||||
|      Algorithm". If the objects are no std::string, they must | ||||
|      implement "std::ostream operator<< (std::ostream&, const Ty&)". | ||||
|   */ | ||||
|   template<class Ty> | ||||
|   struct alphanum_less | ||||
|   { | ||||
|     bool operator()(const Ty& left, const Ty& right) const | ||||
|     { | ||||
|       return alphanum_comp(left, right) < 0; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| } | ||||
|  | ||||
| #ifdef TESTMAIN | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
| #include <iterator> | ||||
| #include <map> | ||||
| #include <set> | ||||
| #include <vector> | ||||
| int main() | ||||
| { | ||||
|   // testcases for the algorithm | ||||
|   assert(doj::alphanum_comp("","") == 0); | ||||
|   assert(doj::alphanum_comp("","a") < 0); | ||||
|   assert(doj::alphanum_comp("a","") > 0); | ||||
|   assert(doj::alphanum_comp("a","a") == 0); | ||||
|   assert(doj::alphanum_comp("","9") < 0); | ||||
|   assert(doj::alphanum_comp("9","") > 0); | ||||
|   assert(doj::alphanum_comp("1","1") == 0); | ||||
|   assert(doj::alphanum_comp("1","2") < 0); | ||||
|   assert(doj::alphanum_comp("3","2") > 0); | ||||
|   assert(doj::alphanum_comp("a1","a1") == 0); | ||||
|   assert(doj::alphanum_comp("a1","a2") < 0); | ||||
|   assert(doj::alphanum_comp("a2","a1") > 0); | ||||
|   assert(doj::alphanum_comp("a1a2","a1a3") < 0); | ||||
|   assert(doj::alphanum_comp("a1a2","a1a0") > 0); | ||||
|   assert(doj::alphanum_comp("134","122") > 0); | ||||
|   assert(doj::alphanum_comp("12a3","12a3") == 0); | ||||
|   assert(doj::alphanum_comp("12a1","12a0") > 0); | ||||
|   assert(doj::alphanum_comp("12a1","12a2") < 0); | ||||
|   assert(doj::alphanum_comp("a","aa") < 0); | ||||
|   assert(doj::alphanum_comp("aaa","aa") > 0); | ||||
|   assert(doj::alphanum_comp("Alpha 2","Alpha 2") == 0); | ||||
|   assert(doj::alphanum_comp("Alpha 2","Alpha 2A") < 0); | ||||
|   assert(doj::alphanum_comp("Alpha 2 B","Alpha 2") > 0); | ||||
|  | ||||
|   assert(doj::alphanum_comp(1,1) == 0); | ||||
|   assert(doj::alphanum_comp(1,2) < 0); | ||||
|   assert(doj::alphanum_comp(2,1) > 0); | ||||
|   assert(doj::alphanum_comp(1.2,3.14) < 0); | ||||
|   assert(doj::alphanum_comp(3.14,2.71) > 0); | ||||
|   assert(doj::alphanum_comp(true,true) == 0); | ||||
|   assert(doj::alphanum_comp(true,false) > 0); | ||||
|   assert(doj::alphanum_comp(false,true) < 0); | ||||
|  | ||||
|   std::string str("Alpha 2"); | ||||
|   assert(doj::alphanum_comp(str,"Alpha 2") == 0); | ||||
|   assert(doj::alphanum_comp(str,"Alpha 2A") < 0); | ||||
|   assert(doj::alphanum_comp("Alpha 2 B",str) > 0); | ||||
|  | ||||
|   assert(doj::alphanum_comp(str,strdup("Alpha 2")) == 0); | ||||
|   assert(doj::alphanum_comp(str,strdup("Alpha 2A")) < 0); | ||||
|   assert(doj::alphanum_comp(strdup("Alpha 2 B"),str) > 0); | ||||
|  | ||||
| #if 1 | ||||
|   // show usage of the comparison functor with a set | ||||
|   std::set<std::string, doj::alphanum_less<std::string> > s; | ||||
|   s.insert("Xiph Xlater 58"); | ||||
|   s.insert("Xiph Xlater 5000"); | ||||
|   s.insert("Xiph Xlater 500"); | ||||
|   s.insert("Xiph Xlater 50"); | ||||
|   s.insert("Xiph Xlater 5"); | ||||
|   s.insert("Xiph Xlater 40"); | ||||
|   s.insert("Xiph Xlater 300"); | ||||
|   s.insert("Xiph Xlater 2000"); | ||||
|   s.insert("Xiph Xlater 10000"); | ||||
|   s.insert("QRS-62F Intrinsia Machine"); | ||||
|   s.insert("QRS-62 Intrinsia Machine"); | ||||
|   s.insert("QRS-60F Intrinsia Machine"); | ||||
|   s.insert("QRS-60 Intrinsia Machine"); | ||||
|   s.insert("Callisto Morphamax 7000 SE2"); | ||||
|   s.insert("Callisto Morphamax 7000 SE"); | ||||
|   s.insert("Callisto Morphamax 7000"); | ||||
|   s.insert("Callisto Morphamax 700"); | ||||
|   s.insert("Callisto Morphamax 600"); | ||||
|   s.insert("Callisto Morphamax 5000"); | ||||
|   s.insert("Callisto Morphamax 500"); | ||||
|   s.insert("Callisto Morphamax"); | ||||
|   s.insert("Alpha 2A-900"); | ||||
|   s.insert("Alpha 2A-8000"); | ||||
|   s.insert("Alpha 2A"); | ||||
|   s.insert("Alpha 200"); | ||||
|   s.insert("Alpha 2"); | ||||
|   s.insert("Alpha 100"); | ||||
|   s.insert("Allegia 60 Clasteron"); | ||||
|   s.insert("Allegia 52 Clasteron"); | ||||
|   s.insert("Allegia 51B Clasteron"); | ||||
|   s.insert("Allegia 51 Clasteron"); | ||||
|   s.insert("Allegia 500 Clasteron"); | ||||
|   s.insert("Allegia 50 Clasteron"); | ||||
|   s.insert("40X Radonius"); | ||||
|   s.insert("30X Radonius"); | ||||
|   s.insert("20X Radonius Prime"); | ||||
|   s.insert("20X Radonius"); | ||||
|   s.insert("200X Radonius"); | ||||
|   s.insert("10X Radonius"); | ||||
|   s.insert("1000X Radonius Maximus"); | ||||
|   // print sorted set to cout | ||||
|   std::copy(s.begin(), s.end(), std::ostream_iterator<std::string>(std::cout, "\n")); | ||||
|  | ||||
|   // show usage of comparision functor with a map | ||||
|   typedef std::map<std::string, int, doj::alphanum_less<std::string> > m_t; | ||||
|   m_t m; | ||||
|   m["z1.doc"]=1; | ||||
|   m["z10.doc"]=2; | ||||
|   m["z100.doc"]=3; | ||||
|   m["z101.doc"]=4; | ||||
|   m["z102.doc"]=5; | ||||
|   m["z11.doc"]=6; | ||||
|   m["z12.doc"]=7; | ||||
|   m["z13.doc"]=8; | ||||
|   m["z14.doc"]=9; | ||||
|   m["z15.doc"]=10; | ||||
|   m["z16.doc"]=11; | ||||
|   m["z17.doc"]=12; | ||||
|   m["z18.doc"]=13; | ||||
|   m["z19.doc"]=14; | ||||
|   m["z2.doc"]=15; | ||||
|   m["z20.doc"]=16; | ||||
|   m["z3.doc"]=17; | ||||
|   m["z4.doc"]=18; | ||||
|   m["z5.doc"]=19; | ||||
|   m["z6.doc"]=20; | ||||
|   m["z7.doc"]=21; | ||||
|   m["z8.doc"]=22; | ||||
|   m["z9.doc"]=23; | ||||
|   // print sorted map to cout | ||||
|   for(m_t::iterator i=m.begin(); i!=m.end(); ++i) | ||||
|     std::cout << i->first << '\t' << i->second << std::endl; | ||||
|  | ||||
|   // show usage of comparison functor with an STL algorithm on a vector | ||||
|   std::vector<std::string> v; | ||||
|   // vector contents are reversed sorted contents of the old set | ||||
|   std::copy(s.rbegin(), s.rend(), std::back_inserter(v)); | ||||
|   // now sort the vector with the algorithm | ||||
|   std::sort(v.begin(), v.end(), doj::alphanum_less<std::string>()); | ||||
|   // and print the vector to cout | ||||
|   std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>(std::cout, "\n")); | ||||
| #endif | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										8
									
								
								dep/alphanum/build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								dep/alphanum/build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| from build.c import clibrary | ||||
|  | ||||
| clibrary( | ||||
|     name="alphanum", | ||||
|     srcs=[], | ||||
|     hdrs={"dep/alphanum/alphanum.h": "./alphanum.h"}, | ||||
| ) | ||||
|  | ||||
							
								
								
									
										1
									
								
								dep/cli11
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								dep/cli11
									
									
									
									
									
										Submodule
									
								
							 Submodule dep/cli11 added at 89dc726939
									
								
							
							
								
								
									
										1
									
								
								dep/imgui
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								dep/imgui
									
									
									
									
									
										Submodule
									
								
							 Submodule dep/imgui added at 4d216d4510
									
								
							
							
								
								
									
										1
									
								
								dep/imhex
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								dep/imhex
									
									
									
									
									
										Submodule
									
								
							 Submodule dep/imhex added at a76eae2c11
									
								
							
							
								
								
									
										23
									
								
								dep/lexy/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								dep/lexy/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| Boost Software License - Version 1.0 - August 17th, 2003 | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person or organization | ||||
| obtaining a copy of the software and accompanying documentation covered by | ||||
| this license (the "Software") to use, reproduce, display, distribute, | ||||
| execute, and transmit the Software, and to prepare derivative works of the | ||||
| Software, and to permit third-parties to whom the Software is furnished to | ||||
| do so, all subject to the following: | ||||
|  | ||||
| The copyright notices in the Software and this entire statement, including | ||||
| the above license grant, this restriction and the following disclaimer, | ||||
| must be included in all copies of the Software, in whole or in part, and | ||||
| all derivative works of the Software, unless such copies or derivative | ||||
| works are solely in the form of machine-executable object code generated by | ||||
| a source language processor. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT | ||||
| SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE | ||||
| FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, | ||||
| ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||
| DEALINGS IN THE SOFTWARE. | ||||
							
								
								
									
										175
									
								
								dep/lexy/README.adoc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								dep/lexy/README.adoc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,175 @@ | ||||
| = lexy | ||||
|  | ||||
| ifdef::env-github[] | ||||
| image:https://img.shields.io/endpoint?url=https%3A%2F%2Fwww.jonathanmueller.dev%2Fproject%2Flexy%2Findex.json[Project Status,link=https://www.jonathanmueller.dev/project/] | ||||
| image:https://github.com/foonathan/lexy/workflows/Main%20CI/badge.svg[Build Status] | ||||
| image:https://img.shields.io/badge/try_it_online-blue[Playground,link=https://lexy.foonathan.net/playground] | ||||
| endif::[] | ||||
|  | ||||
| lexy is a parser combinator library for {cpp}17 and onwards. | ||||
| It allows you to write a parser by specifying it in a convenient {cpp} DSL, | ||||
| which gives you all the flexibility and control of a handwritten parser without any of the manual work. | ||||
|  | ||||
| ifdef::env-github[] | ||||
| *Documentation*: https://lexy.foonathan.net/[lexy.foonathan.net] | ||||
| endif::[] | ||||
|  | ||||
| .IPv4 address parser | ||||
| -- | ||||
| ifndef::env-github[] | ||||
| [.godbolt-example] | ||||
| .+++<a href="https://godbolt.org/z/scvajjE17", title="Try it online">{{< svg "icons/play.svg" >}}</a>+++ | ||||
| endif::[] | ||||
| [source,cpp] | ||||
| ---- | ||||
| namespace dsl = lexy::dsl; | ||||
|  | ||||
| // Parse an IPv4 address into a `std::uint32_t`. | ||||
| struct ipv4_address | ||||
| { | ||||
|     // What is being matched. | ||||
|     static constexpr auto rule = []{ | ||||
|         // Match a sequence of (decimal) digits and convert it into a std::uint8_t. | ||||
|         auto octet = dsl::integer<std::uint8_t>; | ||||
|  | ||||
|         // Match four of them separated by periods. | ||||
|         return dsl::times<4>(octet, dsl::sep(dsl::period)) + dsl::eof; | ||||
|     }(); | ||||
|  | ||||
|     // How the matched output is being stored. | ||||
|     static constexpr auto value | ||||
|         = lexy::callback<std::uint32_t>([](std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d) { | ||||
|             return (a << 24) | (b << 16) | (c << 8) | d; | ||||
|         }); | ||||
| }; | ||||
| ---- | ||||
| -- | ||||
|  | ||||
| == Features | ||||
|  | ||||
| Full control:: | ||||
|   * *Describe the parser, not some abstract grammar*: | ||||
|     Unlike parser generators that use some table driven magic for parsing, lexy's grammar is just syntax sugar for a hand-written recursive descent parser. | ||||
|     The parsing algorithm does exactly what you've instructed it to do -- no more ambiguities or weird shift/reduce errors! | ||||
|   * *No implicit backtracking or lookahead*: | ||||
|     It will only backtrack when you say it should, and only lookahead when and how far you want it. | ||||
|     Don't worry about rules that have side-effects, they won't be executed unnecessarily thanks to the user-specified lookahead conditions. | ||||
|     https://lexy.foonathan.net/playground?example=peek[Try it online]. | ||||
|   * *Escape hatch for manual parsing*: | ||||
|     Sometimes you want to parse something that can't be expressed easily with lexy's facilities. | ||||
|     Don't worry, you can integrate a hand-written parser into the grammar at any point. | ||||
|     https://lexy.foonathan.net/playground/?example=scan[Try it online]. | ||||
|   * *Tracing*: | ||||
|     Figure out why the grammar isn't working the way you want it to. | ||||
|     https://lexy.foonathan.net/playground/?example=trace&mode=trace[Try it online]. | ||||
|  | ||||
| Easily integrated:: | ||||
|   * *A pure {cpp} DSL*: | ||||
|     No need to use an external grammar file; embed the grammar directly in your {cpp} project using operator overloading and functions. | ||||
|   * *Bring your own data structures*: | ||||
|     You can directly store results into your own types and have full control over all heap allocations. | ||||
|   * *Fully `constexpr` parsing*: | ||||
|     You want to parse a string literal at compile-time? You can do so. | ||||
|   * *Minimal standard library dependencies*: | ||||
|     The core parsing library only depends on fundamental headers such as `<type_traits>` or `<cstddef>`; no big includes like `<vector>` or `<algorithm>`. | ||||
|   * *Header-only core library* (by necessity, not by choice -- it's `constexpr` after all). | ||||
|  | ||||
| ifdef::env-github[Designed for text::] | ||||
| ifndef::env-github[Designed for text (e.g. {{< github-example json >}}, {{< github-example xml >}}, {{< github-example email >}}) ::] | ||||
|   * *Unicode support*: parse UTF-8, UTF-16, or UTF-32, and access the Unicode character database to query char classes or perform case folding. | ||||
|     https://lexy.foonathan.net/playground?example=identifier-unicode[Try it online]. | ||||
|   * *Convenience*: | ||||
|     Built-in rules for parsing nested structures, quotes and escape sequences. | ||||
|     https://lexy.foonathan.net/playground?example=parenthesized[Try it online]. | ||||
|   * *Automatic whitespace skipping*: | ||||
|     No need to manually handle whitespace or comments. | ||||
|     https://lexy.foonathan.net/playground/?example=whitespace_comment[Try it online]. | ||||
|  | ||||
| ifdef::env-github[Designed for programming languages::] | ||||
| ifndef::env-github[Designed for programming languages (e.g. {{< github-example calculator >}}, {{< github-example shell >}})::] | ||||
|   * *Keyword and identifier parsing*: | ||||
|     Reserve a set of keywords that won't be matched as regular identifiers. | ||||
|     https://lexy.foonathan.net/playground/?example=reserved_identifier[Try it online]. | ||||
|   * *Operator parsing*: | ||||
|     Parse unary/binary operators with different precedences and associativity, including chained comparisons `a < b < c`. | ||||
|     https://lexy.foonathan.net/playground/?example=expr[Try it online]. | ||||
|   * *Automatic error recovery*: | ||||
|     Log an error, recover, and continue parsing! | ||||
|     https://lexy.foonathan.net/playground/?example=recover[Try it online]. | ||||
|  | ||||
| ifdef::env-github[Designed for binary input::] | ||||
| ifndef::env-github[Designed for binary input (e.g. {{< github-example protobuf >}})::] | ||||
|   * *Bytes*: Rules for parsing `N` bytes or Nbit big/little endian integer. | ||||
|   * *Bits*: Rules for parsing individual bit patterns. | ||||
|   * *Blobs*: Rules for parsing TLV formats. | ||||
|  | ||||
| == FAQ | ||||
|  | ||||
| Why should I use lexy over XYZ?:: | ||||
|   lexy is closest to other PEG parsers. | ||||
|   However, they usually do more implicit backtracking, which can hurt performance and you need to be very careful with rules that have side-effects. | ||||
|   This is not the case for lexy, where backtracking is controlled using branch conditions. | ||||
|   lexy also gives you a lot of control over error reporting, supports error recovery, special support for operator precedence parsing, and other advanced features. | ||||
|  | ||||
|   http://boost-spirit.com/home/[Boost.Spirit]::: | ||||
|     The main difference: it is not a Boost library. | ||||
|     In addition, Boost.Spirit is quite old and doesn't support e.g. non-common ranges as input.  | ||||
|     Boost.Spirit also eagerly creates attributes from the rules, which can lead to nested tuples/variants while lexy uses callbacks which enables zero-copy parsing directly into your own data structure. | ||||
|     However, lexy's grammar is more verbose and designed to parser bigger grammars instead of the small one-off rules that Boost.Spirit is good at. | ||||
|   https://github.com/taocpp/PEGTL[PEGTL]::: | ||||
|     PEGTL is very similar and was a big inspiration. | ||||
|     The biggest difference is that lexy uses an operator based DSL instead of inheriting from templated classes as PEGTL does; | ||||
|     depending on your preference this can be an advantage or disadvantage. | ||||
|   Hand-written Parsers::: | ||||
|     Writing a handwritten parser is more manual work and error prone. | ||||
|     lexy automates that away without having to sacrifice control. | ||||
|     You can use it to quickly prototype a parser and then slowly replace more and more with a handwritten parser over time; | ||||
|     mixing a hand-written parser and a lexy grammar works seamlessly. | ||||
|  | ||||
| How bad are the compilation times?:: | ||||
| They're not as bad as you might expect (in debug mode, that is). | ||||
| + | ||||
| The example JSON parser compiles in about 2s on my machine. | ||||
| If we remove all the lexy specific parts and just benchmark the time it takes for the compiler to process the datastructure (and stdlib includes), | ||||
| that takes about 700ms. | ||||
| If we validate JSON only instead of parsing it, so remove the data structures and keep only the lexy specific parts, we're looking at about 840ms. | ||||
| + | ||||
| Keep in mind, that you can fully isolate lexy in a single translation unit that only needs to be touched when you change the parser. | ||||
| You can also split a lexy grammar into multiple translation units using the `dsl::subgrammar` rule. | ||||
|  | ||||
| How bad are the {cpp} error messages if you mess something up?:: | ||||
|   They're certainly worse than the error message lexy gives you. | ||||
|   The big problem here is that the first line gives you the error, followed by dozens of template instantiations, which end at your `lexy::parse` call. | ||||
|   Besides providing an external tool to filter those error messages, there is nothing I can do about that. | ||||
|  | ||||
| How fast is it?:: | ||||
|   Benchmarks are available in the `benchmarks/` directory. | ||||
|   A sample result of the JSON validator benchmark which compares the example JSON parser with various other implementations is available https://lexy.foonathan.net/benchmark_json/[here]. | ||||
|  | ||||
| Why is it called lexy?:: | ||||
|   I previously had a tokenizer library called foonathan/lex. | ||||
|   I've tried adding a parser to it, but found that the line between pure tokenization and parsing has become increasingly blurred. | ||||
|   lexy is a re-imagination on of the parser I've added to foonathan/lex, and I've simply kept a similar name. | ||||
|  | ||||
| ifdef::env-github[] | ||||
| == Documentation | ||||
|  | ||||
| The documentation, including tutorials, reference documentation, and an interactive playground can be found at https://lexy.foonathan.net/[lexy.foonathan.net]. | ||||
|  | ||||
| A minimal `CMakeLists.txt` that uses lexy can look like this: | ||||
|  | ||||
| .`CMakeLists.txt` | ||||
| ```cmake | ||||
| project(lexy-example) | ||||
|  | ||||
| include(FetchContent) | ||||
| FetchContent_Declare(lexy URL https://lexy.foonathan.net/download/lexy-src.zip) | ||||
| FetchContent_MakeAvailable(lexy) | ||||
|  | ||||
| add_executable(lexy_example) | ||||
| target_sources(lexy_example PRIVATE main.cpp) | ||||
| target_link_libraries(lexy_example PRIVATE foonathan::lexy) | ||||
| ``` | ||||
|  | ||||
| endif::[] | ||||
|  | ||||
							
								
								
									
										2
									
								
								dep/lexy/UPSTREAM.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								dep/lexy/UPSTREAM.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| This is a heavily truncated copy of https://github.com/foonathan/lexy, commit | ||||
| 20926cf. | ||||
							
								
								
									
										11
									
								
								dep/lexy/build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								dep/lexy/build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| from build.c import cxxlibrary | ||||
| from glob import glob | ||||
|  | ||||
| cxxlibrary( | ||||
|     name="lexy", | ||||
|     srcs=[], | ||||
|     hdrs={ | ||||
|         h: f"./include/{h}" | ||||
|         for h in glob("**/*.hpp", root_dir="dep/lexy/include", recursive=True) | ||||
|     }, | ||||
| ) | ||||
							
								
								
									
										68
									
								
								dep/lexy/include/lexy/_detail/any_ref.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								dep/lexy/include/lexy/_detail/any_ref.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_ANY_REF_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_ANY_REF_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/config.hpp> | ||||
|  | ||||
| // Essentially a void*, but we can cast it in a constexpr context. | ||||
| // The cost is an extra layer of indirection. | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename T> | ||||
| class any_holder; | ||||
|  | ||||
| // Store a pointer to this instead of a void*. | ||||
| class any_base | ||||
| { | ||||
| public: | ||||
|     any_base(const any_base&)            = delete; | ||||
|     any_base& operator=(const any_base&) = delete; | ||||
|  | ||||
|     template <typename T> | ||||
|     constexpr T& get() noexcept | ||||
|     { | ||||
|         return static_cast<any_holder<T>*>(this)->get(); | ||||
|     } | ||||
|     template <typename T> | ||||
|     constexpr const T& get() const noexcept | ||||
|     { | ||||
|         return static_cast<const any_holder<T>*>(this)->get(); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     constexpr any_base() = default; | ||||
|     ~any_base()          = default; | ||||
|  | ||||
|     template <typename T> | ||||
|     friend class any_holder; | ||||
| }; | ||||
|  | ||||
| using any_ref  = any_base*; | ||||
| using any_cref = const any_base*; | ||||
|  | ||||
| // Need to store the object in here. | ||||
| template <typename T> | ||||
| class any_holder : public any_base | ||||
| { | ||||
| public: | ||||
|     constexpr explicit any_holder(T&& obj) : _obj(LEXY_MOV(obj)) {} | ||||
|  | ||||
|     constexpr T& get() noexcept | ||||
|     { | ||||
|         return _obj; | ||||
|     } | ||||
|     constexpr const T& get() const noexcept | ||||
|     { | ||||
|         return _obj; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     T _obj; | ||||
| }; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_ANY_REF_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										51
									
								
								dep/lexy/include/lexy/_detail/assert.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								dep/lexy/include/lexy/_detail/assert.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_ASSERT_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_ASSERT_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/config.hpp> | ||||
|  | ||||
| #ifndef LEXY_ENABLE_ASSERT | ||||
|  | ||||
| // By default, enable assertions if NDEBUG is not defined. | ||||
|  | ||||
| #    if NDEBUG | ||||
| #        define LEXY_ENABLE_ASSERT 0 | ||||
| #    else | ||||
| #        define LEXY_ENABLE_ASSERT 1 | ||||
| #    endif | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #if LEXY_ENABLE_ASSERT | ||||
|  | ||||
| // We want assertions: use assert() if that's available, otherwise abort. | ||||
| // We don't use assert() directly as that's not constexpr. | ||||
|  | ||||
| #    if NDEBUG | ||||
|  | ||||
| #        include <cstdlib> | ||||
| #        define LEXY_PRECONDITION(Expr) ((Expr) ? void(0) : std::abort()) | ||||
| #        define LEXY_ASSERT(Expr, Msg) ((Expr) ? void(0) : std::abort()) | ||||
|  | ||||
| #    else | ||||
|  | ||||
| #        include <cassert> | ||||
|  | ||||
| #        define LEXY_PRECONDITION(Expr) ((Expr) ? void(0) : assert(Expr)) | ||||
| #        define LEXY_ASSERT(Expr, Msg) ((Expr) ? void(0) : assert((Expr) && (Msg))) | ||||
|  | ||||
| #    endif | ||||
|  | ||||
| #else | ||||
|  | ||||
| // We don't want assertions. | ||||
|  | ||||
| #    define LEXY_PRECONDITION(Expr) static_cast<void>(sizeof(Expr)) | ||||
| #    define LEXY_ASSERT(Expr, Msg) static_cast<void>(sizeof(Expr)) | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #endif // LEXY_DETAIL_ASSERT_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										160
									
								
								dep/lexy/include/lexy/_detail/buffer_builder.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								dep/lexy/include/lexy/_detail/buffer_builder.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_BUFFER_BUILDER_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_BUFFER_BUILDER_HPP_INCLUDED | ||||
|  | ||||
| #include <cstring> | ||||
| #include <lexy/_detail/assert.hpp> | ||||
| #include <lexy/_detail/config.hpp> | ||||
| #include <lexy/_detail/iterator.hpp> | ||||
| #include <new> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| // Builds a buffer: it has a read are and a write area. | ||||
| // The characters in the read area are already valid and can be read. | ||||
| // The characters in the write area are not valid, but can be written too. | ||||
| template <typename T> | ||||
| class buffer_builder | ||||
| { | ||||
|     static_assert(std::is_trivial_v<T>); | ||||
|  | ||||
|     static constexpr std::size_t total_size_bytes = 1024; | ||||
|     static constexpr std::size_t stack_buffer_size | ||||
|         = (total_size_bytes - 3 * sizeof(T*)) / sizeof(T); | ||||
|     static constexpr auto growth_factor = 2; | ||||
|  | ||||
| public: | ||||
|     buffer_builder() noexcept : _data(_stack_buffer), _read_size(0), _write_size(stack_buffer_size) | ||||
|     { | ||||
|         static_assert(sizeof(*this) == total_size_bytes, "invalid buffer size calculation"); | ||||
|     } | ||||
|  | ||||
|     ~buffer_builder() noexcept | ||||
|     { | ||||
|         // Free memory if we allocated any. | ||||
|         if (_data != _stack_buffer) | ||||
|             ::operator delete(_data); | ||||
|     } | ||||
|  | ||||
|     buffer_builder(const buffer_builder&)            = delete; | ||||
|     buffer_builder& operator=(const buffer_builder&) = delete; | ||||
|  | ||||
|     // The total capacity: read + write. | ||||
|     std::size_t capacity() const noexcept | ||||
|     { | ||||
|         return _read_size + _write_size; | ||||
|     } | ||||
|  | ||||
|     // The read area. | ||||
|     const T* read_data() const noexcept | ||||
|     { | ||||
|         return _data; | ||||
|     } | ||||
|     std::size_t read_size() const noexcept | ||||
|     { | ||||
|         return _read_size; | ||||
|     } | ||||
|  | ||||
|     // The write area. | ||||
|     T* write_data() noexcept | ||||
|     { | ||||
|         return _data + _read_size; | ||||
|     } | ||||
|     std::size_t write_size() const noexcept | ||||
|     { | ||||
|         return _write_size; | ||||
|     } | ||||
|  | ||||
|     // Clears the read area. | ||||
|     void clear() noexcept | ||||
|     { | ||||
|         _write_size += _read_size; | ||||
|         _read_size = 0; | ||||
|     } | ||||
|  | ||||
|     // Takes the first n characters of the write area and appends them to the read area. | ||||
|     void commit(std::size_t n) noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(n <= _write_size); | ||||
|         _read_size += n; | ||||
|         _write_size -= n; | ||||
|     } | ||||
|  | ||||
|     // Increases the write area, invalidates all pointers. | ||||
|     void grow() | ||||
|     { | ||||
|         const auto cur_cap = capacity(); | ||||
|         const auto new_cap = growth_factor * cur_cap; | ||||
|  | ||||
|         // Allocate new memory. | ||||
|         auto memory = static_cast<T*>(::operator new(new_cap * sizeof(T))); | ||||
|         // Copy the read area into the new memory. | ||||
|         std::memcpy(memory, _data, _read_size); | ||||
|  | ||||
|         // Release the old memory, if there was any. | ||||
|         if (_data != _stack_buffer) | ||||
|             ::operator delete(_data); | ||||
|  | ||||
|         // Update for the new area. | ||||
|         _data = memory; | ||||
|         // _read_size hasn't been changed | ||||
|         _write_size = new_cap - _read_size; | ||||
|     } | ||||
|  | ||||
|     //=== iterator ===// | ||||
|     // Stable iterator over the memory. | ||||
|     class stable_iterator : public forward_iterator_base<stable_iterator, const T> | ||||
|     { | ||||
|     public: | ||||
|         constexpr stable_iterator() = default; | ||||
|  | ||||
|         explicit constexpr stable_iterator(const _detail::buffer_builder<T>& buffer, | ||||
|                                            std::size_t                       idx) noexcept | ||||
|         : _buffer(&buffer), _idx(idx) | ||||
|         {} | ||||
|  | ||||
|         constexpr const T& deref() const noexcept | ||||
|         { | ||||
|             LEXY_PRECONDITION(_idx != _buffer->read_size()); | ||||
|             return _buffer->read_data()[_idx]; | ||||
|         } | ||||
|  | ||||
|         constexpr void increment() noexcept | ||||
|         { | ||||
|             LEXY_PRECONDITION(_idx != _buffer->read_size()); | ||||
|             ++_idx; | ||||
|         } | ||||
|  | ||||
|         constexpr bool equal(stable_iterator rhs) const noexcept | ||||
|         { | ||||
|             if (!_buffer || !rhs._buffer) | ||||
|                 return !_buffer && !rhs._buffer; | ||||
|             else | ||||
|             { | ||||
|                 LEXY_PRECONDITION(_buffer == rhs._buffer); | ||||
|                 return _idx == rhs._idx; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         constexpr std::size_t index() const noexcept | ||||
|         { | ||||
|             return _idx; | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         const _detail::buffer_builder<T>* _buffer = nullptr; | ||||
|         std::size_t                       _idx    = 0; | ||||
|     }; | ||||
|  | ||||
| private: | ||||
|     T*          _data; | ||||
|     std::size_t _read_size; | ||||
|     std::size_t _write_size; | ||||
|     T           _stack_buffer[stack_buffer_size]; | ||||
| }; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_BUFFER_BUILDER_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										368
									
								
								dep/lexy/include/lexy/_detail/code_point.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										368
									
								
								dep/lexy/include/lexy/_detail/code_point.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,368 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_CODE_POINT_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_CODE_POINT_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/input/base.hpp> | ||||
|  | ||||
| //=== encoding ===// | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename Encoding> | ||||
| constexpr std::size_t encode_code_point(char32_t cp, typename Encoding::char_type* buffer, | ||||
|                                         std::size_t size) | ||||
| { | ||||
|     if constexpr (std::is_same_v<Encoding, lexy::ascii_encoding>) | ||||
|     { | ||||
|         LEXY_PRECONDITION(size >= 1); | ||||
|  | ||||
|         *buffer = char(cp); | ||||
|         return 1; | ||||
|     } | ||||
|     else if constexpr (std::is_same_v<Encoding, | ||||
|                                       lexy::utf8_encoding> // | ||||
|                        || std::is_same_v<Encoding, lexy::utf8_char_encoding>) | ||||
|     { | ||||
|         using char_type = typename Encoding::char_type; | ||||
|         // Taken from http://www.herongyang.com/Unicode/UTF-8-UTF-8-Encoding-Algorithm.html. | ||||
|         if (cp <= 0x7F) | ||||
|         { | ||||
|             LEXY_PRECONDITION(size >= 1); | ||||
|  | ||||
|             buffer[0] = char_type(cp); | ||||
|             return 1; | ||||
|         } | ||||
|         else if (cp <= 0x07'FF) | ||||
|         { | ||||
|             LEXY_PRECONDITION(size >= 2); | ||||
|  | ||||
|             auto first  = (cp >> 6) & 0x1F; | ||||
|             auto second = (cp >> 0) & 0x3F; | ||||
|  | ||||
|             buffer[0] = char_type(0xC0 | first); | ||||
|             buffer[1] = char_type(0x80 | second); | ||||
|             return 2; | ||||
|         } | ||||
|         else if (cp <= 0xFF'FF) | ||||
|         { | ||||
|             LEXY_PRECONDITION(size >= 3); | ||||
|  | ||||
|             auto first  = (cp >> 12) & 0x0F; | ||||
|             auto second = (cp >> 6) & 0x3F; | ||||
|             auto third  = (cp >> 0) & 0x3F; | ||||
|  | ||||
|             buffer[0] = char_type(0xE0 | first); | ||||
|             buffer[1] = char_type(0x80 | second); | ||||
|             buffer[2] = char_type(0x80 | third); | ||||
|             return 3; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             LEXY_PRECONDITION(size >= 4); | ||||
|  | ||||
|             auto first  = (cp >> 18) & 0x07; | ||||
|             auto second = (cp >> 12) & 0x3F; | ||||
|             auto third  = (cp >> 6) & 0x3F; | ||||
|             auto fourth = (cp >> 0) & 0x3F; | ||||
|  | ||||
|             buffer[0] = char_type(0xF0 | first); | ||||
|             buffer[1] = char_type(0x80 | second); | ||||
|             buffer[2] = char_type(0x80 | third); | ||||
|             buffer[3] = char_type(0x80 | fourth); | ||||
|             return 4; | ||||
|         } | ||||
|     } | ||||
|     else if constexpr (std::is_same_v<Encoding, lexy::utf16_encoding>) | ||||
|     { | ||||
|         if (cp <= 0xFF'FF) | ||||
|         { | ||||
|             LEXY_PRECONDITION(size >= 1); | ||||
|  | ||||
|             buffer[0] = char16_t(cp); | ||||
|             return 1; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Algorithm implemented from | ||||
|             // https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF. | ||||
|             LEXY_PRECONDITION(size >= 2); | ||||
|  | ||||
|             auto u_prime       = cp - 0x1'0000; | ||||
|             auto high_ten_bits = u_prime >> 10; | ||||
|             auto low_ten_bits  = u_prime & 0b0000'0011'1111'1111; | ||||
|  | ||||
|             buffer[0] = char16_t(0xD800 + high_ten_bits); | ||||
|             buffer[1] = char16_t(0xDC00 + low_ten_bits); | ||||
|             return 2; | ||||
|         } | ||||
|     } | ||||
|     else if constexpr (std::is_same_v<Encoding, lexy::utf32_encoding>) | ||||
|     { | ||||
|         LEXY_PRECONDITION(size >= 1); | ||||
|  | ||||
|         *buffer = cp; | ||||
|         return 1; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         static_assert(lexy::_detail::error<Encoding>, | ||||
|                       "cannot encode a code point in this encoding"); | ||||
|         (void)cp; | ||||
|         (void)buffer; | ||||
|         (void)size; | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| //=== parsing ===// | ||||
| namespace lexy::_detail | ||||
| { | ||||
| enum class cp_error | ||||
| { | ||||
|     success, | ||||
|     eof, | ||||
|     leads_with_trailing, | ||||
|     missing_trailing, | ||||
|     surrogate, | ||||
|     overlong_sequence, | ||||
|     out_of_range, | ||||
| }; | ||||
|  | ||||
| template <typename Reader> | ||||
| struct cp_result | ||||
| { | ||||
|     char32_t                cp; | ||||
|     cp_error                error; | ||||
|     typename Reader::marker end; | ||||
| }; | ||||
|  | ||||
| template <typename Reader> | ||||
| constexpr cp_result<Reader> parse_code_point(Reader reader) | ||||
| { | ||||
|     if constexpr (std::is_same_v<typename Reader::encoding, lexy::ascii_encoding>) | ||||
|     { | ||||
|         if (reader.peek() == Reader::encoding::eof()) | ||||
|             return {{}, cp_error::eof, reader.current()}; | ||||
|  | ||||
|         auto cur = reader.peek(); | ||||
|         reader.bump(); | ||||
|  | ||||
|         auto cp = static_cast<char32_t>(cur); | ||||
|         if (cp <= 0x7F) | ||||
|             return {cp, cp_error::success, reader.current()}; | ||||
|         else | ||||
|             return {cp, cp_error::out_of_range, reader.current()}; | ||||
|     } | ||||
|     else if constexpr (std::is_same_v<typename Reader::encoding, lexy::utf8_encoding> // | ||||
|                        || std::is_same_v<typename Reader::encoding, lexy::utf8_char_encoding>) | ||||
|     { | ||||
|         using uchar_t                = unsigned char; | ||||
|         constexpr auto payload_lead1 = 0b0111'1111; | ||||
|         constexpr auto payload_lead2 = 0b0001'1111; | ||||
|         constexpr auto payload_lead3 = 0b0000'1111; | ||||
|         constexpr auto payload_lead4 = 0b0000'0111; | ||||
|         constexpr auto payload_cont  = 0b0011'1111; | ||||
|  | ||||
|         constexpr auto pattern_lead1 = 0b0 << 7; | ||||
|         constexpr auto pattern_lead2 = 0b110 << 5; | ||||
|         constexpr auto pattern_lead3 = 0b1110 << 4; | ||||
|         constexpr auto pattern_lead4 = 0b11110 << 3; | ||||
|         constexpr auto pattern_cont  = 0b10 << 6; | ||||
|  | ||||
|         auto first = uchar_t(reader.peek()); | ||||
|         if ((first & ~payload_lead1) == pattern_lead1) | ||||
|         { | ||||
|             // ASCII character. | ||||
|             reader.bump(); | ||||
|             return {first, cp_error::success, reader.current()}; | ||||
|         } | ||||
|         else if ((first & ~payload_cont) == pattern_cont) | ||||
|         { | ||||
|             return {{}, cp_error::leads_with_trailing, reader.current()}; | ||||
|         } | ||||
|         else if ((first & ~payload_lead2) == pattern_lead2) | ||||
|         { | ||||
|             reader.bump(); | ||||
|  | ||||
|             auto second = uchar_t(reader.peek()); | ||||
|             if ((second & ~payload_cont) != pattern_cont) | ||||
|                 return {{}, cp_error::missing_trailing, reader.current()}; | ||||
|             reader.bump(); | ||||
|  | ||||
|             auto result = char32_t(first & payload_lead2); | ||||
|             result <<= 6; | ||||
|             result |= char32_t(second & payload_cont); | ||||
|  | ||||
|             // C0 and C1 are overlong ASCII. | ||||
|             if (first == 0xC0 || first == 0xC1) | ||||
|                 return {result, cp_error::overlong_sequence, reader.current()}; | ||||
|             else | ||||
|                 return {result, cp_error::success, reader.current()}; | ||||
|         } | ||||
|         else if ((first & ~payload_lead3) == pattern_lead3) | ||||
|         { | ||||
|             reader.bump(); | ||||
|  | ||||
|             auto second = uchar_t(reader.peek()); | ||||
|             if ((second & ~payload_cont) != pattern_cont) | ||||
|                 return {{}, cp_error::missing_trailing, reader.current()}; | ||||
|             reader.bump(); | ||||
|  | ||||
|             auto third = uchar_t(reader.peek()); | ||||
|             if ((third & ~payload_cont) != pattern_cont) | ||||
|                 return {{}, cp_error::missing_trailing, reader.current()}; | ||||
|             reader.bump(); | ||||
|  | ||||
|             auto result = char32_t(first & payload_lead3); | ||||
|             result <<= 6; | ||||
|             result |= char32_t(second & payload_cont); | ||||
|             result <<= 6; | ||||
|             result |= char32_t(third & payload_cont); | ||||
|  | ||||
|             auto cp = result; | ||||
|             if (0xD800 <= cp && cp <= 0xDFFF) | ||||
|                 return {cp, cp_error::surrogate, reader.current()}; | ||||
|             else if (first == 0xE0 && second < 0xA0) | ||||
|                 return {cp, cp_error::overlong_sequence, reader.current()}; | ||||
|             else | ||||
|                 return {cp, cp_error::success, reader.current()}; | ||||
|         } | ||||
|         else if ((first & ~payload_lead4) == pattern_lead4) | ||||
|         { | ||||
|             reader.bump(); | ||||
|  | ||||
|             auto second = uchar_t(reader.peek()); | ||||
|             if ((second & ~payload_cont) != pattern_cont) | ||||
|                 return {{}, cp_error::missing_trailing, reader.current()}; | ||||
|             reader.bump(); | ||||
|  | ||||
|             auto third = uchar_t(reader.peek()); | ||||
|             if ((third & ~payload_cont) != pattern_cont) | ||||
|                 return {{}, cp_error::missing_trailing, reader.current()}; | ||||
|             reader.bump(); | ||||
|  | ||||
|             auto fourth = uchar_t(reader.peek()); | ||||
|             if ((fourth & ~payload_cont) != pattern_cont) | ||||
|                 return {{}, cp_error::missing_trailing, reader.current()}; | ||||
|             reader.bump(); | ||||
|  | ||||
|             auto result = char32_t(first & payload_lead4); | ||||
|             result <<= 6; | ||||
|             result |= char32_t(second & payload_cont); | ||||
|             result <<= 6; | ||||
|             result |= char32_t(third & payload_cont); | ||||
|             result <<= 6; | ||||
|             result |= char32_t(fourth & payload_cont); | ||||
|  | ||||
|             auto cp = result; | ||||
|             if (cp > 0x10'FFFF) | ||||
|                 return {cp, cp_error::out_of_range, reader.current()}; | ||||
|             else if (first == 0xF0 && second < 0x90) | ||||
|                 return {cp, cp_error::overlong_sequence, reader.current()}; | ||||
|             else | ||||
|                 return {cp, cp_error::success, reader.current()}; | ||||
|         } | ||||
|         else // FE or FF | ||||
|         { | ||||
|             return {{}, cp_error::eof, reader.current()}; | ||||
|         } | ||||
|     } | ||||
|     else if constexpr (std::is_same_v<typename Reader::encoding, lexy::utf16_encoding>) | ||||
|     { | ||||
|         constexpr auto payload1 = 0b0000'0011'1111'1111; | ||||
|         constexpr auto payload2 = payload1; | ||||
|  | ||||
|         constexpr auto pattern1 = 0b110110 << 10; | ||||
|         constexpr auto pattern2 = 0b110111 << 10; | ||||
|  | ||||
|         if (reader.peek() == Reader::encoding::eof()) | ||||
|             return {{}, cp_error::eof, reader.current()}; | ||||
|  | ||||
|         auto first = char16_t(reader.peek()); | ||||
|         if ((first & ~payload1) == pattern1) | ||||
|         { | ||||
|             reader.bump(); | ||||
|             if (reader.peek() == Reader::encoding::eof()) | ||||
|                 return {{}, cp_error::missing_trailing, reader.current()}; | ||||
|  | ||||
|             auto second = char16_t(reader.peek()); | ||||
|             if ((second & ~payload2) != pattern2) | ||||
|                 return {{}, cp_error::missing_trailing, reader.current()}; | ||||
|             reader.bump(); | ||||
|  | ||||
|             // We've got a valid code point. | ||||
|             auto result = char32_t(first & payload1); | ||||
|             result <<= 10; | ||||
|             result |= char32_t(second & payload2); | ||||
|             result |= 0x10000; | ||||
|             return {result, cp_error::success, reader.current()}; | ||||
|         } | ||||
|         else if ((first & ~payload2) == pattern2) | ||||
|         { | ||||
|             return {{}, cp_error::leads_with_trailing, reader.current()}; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Single code unit code point; always valid. | ||||
|             reader.bump(); | ||||
|             return {first, cp_error::success, reader.current()}; | ||||
|         } | ||||
|     } | ||||
|     else if constexpr (std::is_same_v<typename Reader::encoding, lexy::utf32_encoding>) | ||||
|     { | ||||
|         if (reader.peek() == Reader::encoding::eof()) | ||||
|             return {{}, cp_error::eof, reader.current()}; | ||||
|  | ||||
|         auto cur = reader.peek(); | ||||
|         reader.bump(); | ||||
|  | ||||
|         auto cp = cur; | ||||
|         if (cp > 0x10'FFFF) | ||||
|             return {cp, cp_error::out_of_range, reader.current()}; | ||||
|         else if (0xD800 <= cp && cp <= 0xDFFF) | ||||
|             return {cp, cp_error::surrogate, reader.current()}; | ||||
|         else | ||||
|             return {cp, cp_error::success, reader.current()}; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         static_assert(lexy::_detail::error<typename Reader::encoding>, | ||||
|                       "no known code point for this encoding"); | ||||
|         return {}; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename Reader> | ||||
| constexpr void recover_code_point(Reader& reader, cp_result<Reader> result) | ||||
| { | ||||
|     switch (result.error) | ||||
|     { | ||||
|     case cp_error::success: | ||||
|         // Consume the entire code point. | ||||
|         reader.reset(result.end); | ||||
|         break; | ||||
|     case cp_error::eof: | ||||
|         // We don't need to do anything to "recover" from EOF. | ||||
|         break; | ||||
|  | ||||
|     case cp_error::leads_with_trailing: | ||||
|         // Invalid code unit, consume to recover. | ||||
|         LEXY_PRECONDITION(result.end.position() == reader.position()); | ||||
|         reader.bump(); | ||||
|         break; | ||||
|  | ||||
|     case cp_error::missing_trailing: | ||||
|     case cp_error::surrogate: | ||||
|     case cp_error::out_of_range: | ||||
|     case cp_error::overlong_sequence: | ||||
|         // Consume all the invalid code units to recover. | ||||
|         reader.reset(result.end); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_CODE_POINT_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										199
									
								
								dep/lexy/include/lexy/_detail/config.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								dep/lexy/include/lexy/_detail/config.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_CONFIG_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_CONFIG_HPP_INCLUDED | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <type_traits> | ||||
|  | ||||
| #if defined(LEXY_USER_CONFIG_HEADER) | ||||
| #    include LEXY_USER_CONFIG_HEADER | ||||
| #elif defined(__has_include) | ||||
| #    if __has_include(<lexy_user_config.hpp>) | ||||
| #        include <lexy_user_config.hpp> | ||||
| #    elif __has_include("lexy_user_config.hpp") | ||||
| #        include "lexy_user_config.hpp" | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| #ifndef LEXY_HAS_UNICODE_DATABASE | ||||
| #    define LEXY_HAS_UNICODE_DATABASE 0 | ||||
| #endif | ||||
|  | ||||
| #ifndef LEXY_EXPERIMENTAL | ||||
| #    define LEXY_EXPERIMENTAL 0 | ||||
| #endif | ||||
|  | ||||
| //=== utility traits===// | ||||
| #define LEXY_MOV(...) static_cast<std::remove_reference_t<decltype(__VA_ARGS__)>&&>(__VA_ARGS__) | ||||
| #define LEXY_FWD(...) static_cast<decltype(__VA_ARGS__)>(__VA_ARGS__) | ||||
|  | ||||
| #define LEXY_DECLVAL(...) lexy::_detail::declval<__VA_ARGS__>() | ||||
|  | ||||
| #define LEXY_DECAY_DECLTYPE(...) std::decay_t<decltype(__VA_ARGS__)> | ||||
|  | ||||
| /// Creates a new type from the instantiation of a template. | ||||
| /// This is used to shorten type names. | ||||
| #define LEXY_INSTANTIATION_NEWTYPE(Name, Templ, ...)                                               \ | ||||
|     struct Name : Templ<__VA_ARGS__>                                                               \ | ||||
|     {                                                                                              \ | ||||
|         using Templ<__VA_ARGS__>::Templ;                                                           \ | ||||
|     } | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename... T> | ||||
| constexpr bool error = false; | ||||
|  | ||||
| template <typename T> | ||||
| std::add_rvalue_reference_t<T> declval(); | ||||
|  | ||||
| template <typename T> | ||||
| constexpr void swap(T& lhs, T& rhs) noexcept | ||||
| { | ||||
|     T tmp = LEXY_MOV(lhs); | ||||
|     lhs   = LEXY_MOV(rhs); | ||||
|     rhs   = LEXY_MOV(tmp); | ||||
| } | ||||
|  | ||||
| template <typename T, typename U> | ||||
| constexpr bool is_decayed_same = std::is_same_v<std::decay_t<T>, std::decay_t<U>>; | ||||
|  | ||||
| template <typename T, typename Fallback> | ||||
| using type_or = std::conditional_t<std::is_void_v<T>, Fallback, T>; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| //=== NTTP ===// | ||||
| #ifndef LEXY_HAS_NTTP | ||||
| //   See https://github.com/foonathan/lexy/issues/15. | ||||
| #    if __cpp_nontype_template_parameter_class >= 201806 || __cpp_nontype_template_args >= 201911 | ||||
| #        define LEXY_HAS_NTTP 1 | ||||
| #    else | ||||
| #        define LEXY_HAS_NTTP 0 | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| #if LEXY_HAS_NTTP | ||||
| #    define LEXY_NTTP_PARAM auto | ||||
| #else | ||||
| #    define LEXY_NTTP_PARAM const auto& | ||||
| #endif | ||||
|  | ||||
| //=== consteval ===// | ||||
| #ifndef LEXY_HAS_CONSTEVAL | ||||
| #    if defined(_MSC_VER) && !defined(__clang__) | ||||
| //       Currently can't handle returning strings from consteval, check back later. | ||||
| #        define LEXY_HAS_CONSTEVAL 0 | ||||
| #    elif __cpp_consteval | ||||
| #        define LEXY_HAS_CONSTEVAL 1 | ||||
| #    else | ||||
| #        define LEXY_HAS_CONSTEVAL 0 | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| #if LEXY_HAS_CONSTEVAL | ||||
| #    define LEXY_CONSTEVAL consteval | ||||
| #else | ||||
| #    define LEXY_CONSTEVAL constexpr | ||||
| #endif | ||||
|  | ||||
| //=== constexpr ===// | ||||
| #ifndef LEXY_HAS_CONSTEXPR_DTOR | ||||
| #    if __cpp_constexpr_dynamic_alloc | ||||
| #        define LEXY_HAS_CONSTEXPR_DTOR 1 | ||||
| #    else | ||||
| #        define LEXY_HAS_CONSTEXPR_DTOR 0 | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| #if LEXY_HAS_CONSTEXPR_DTOR | ||||
| #    define LEXY_CONSTEXPR_DTOR constexpr | ||||
| #else | ||||
| #    define LEXY_CONSTEXPR_DTOR | ||||
| #endif | ||||
|  | ||||
| //=== char8_t ===// | ||||
| #ifndef LEXY_HAS_CHAR8_T | ||||
| #    if __cpp_char8_t | ||||
| #        define LEXY_HAS_CHAR8_T 1 | ||||
| #    else | ||||
| #        define LEXY_HAS_CHAR8_T 0 | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| #if LEXY_HAS_CHAR8_T | ||||
|  | ||||
| #    define LEXY_CHAR_OF_u8 char8_t | ||||
| #    define LEXY_CHAR8_T char8_t | ||||
| #    define LEXY_CHAR8_STR(Str) u8##Str | ||||
|  | ||||
| #else | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| using _char8_t = unsigned char; | ||||
| } // namespace lexy | ||||
|  | ||||
| #    define LEXY_CHAR_OF_u8 char | ||||
| #    define LEXY_CHAR8_T ::lexy::_char8_t | ||||
| #    define LEXY_CHAR8_STR(Str)                                                                    \ | ||||
|         LEXY_NTTP_STRING(::lexy::_detail::type_string, u8##Str)::c_str<LEXY_CHAR8_T> | ||||
|  | ||||
| #endif | ||||
|  | ||||
| //=== endianness ===// | ||||
| #ifndef LEXY_IS_LITTLE_ENDIAN | ||||
| #    if defined(__BYTE_ORDER__) | ||||
| #        if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | ||||
| #            define LEXY_IS_LITTLE_ENDIAN 1 | ||||
| #        elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | ||||
| #            define LEXY_IS_LITTLE_ENDIAN 0 | ||||
| #        else | ||||
| #            error "unsupported byte order" | ||||
| #        endif | ||||
| #    elif defined(_MSC_VER) | ||||
| #        define LEXY_IS_LITTLE_ENDIAN 1 | ||||
| #    else | ||||
| #        error "unknown endianness" | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| //=== force inline ===// | ||||
| #ifndef LEXY_FORCE_INLINE | ||||
| #    if defined(__has_cpp_attribute) | ||||
| #        if __has_cpp_attribute(gnu::always_inline) | ||||
| #            define LEXY_FORCE_INLINE [[gnu::always_inline]] | ||||
| #        endif | ||||
| #    endif | ||||
| # | ||||
| #    ifndef LEXY_FORCE_INLINE | ||||
| #        define LEXY_FORCE_INLINE inline | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| //=== empty_member ===// | ||||
| #ifndef LEXY_EMPTY_MEMBER | ||||
|  | ||||
| #    if defined(__has_cpp_attribute) | ||||
| #        if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 11 | ||||
| //           GCC <= 11 has buggy support, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101040 | ||||
| #            define LEXY_HAS_EMPTY_MEMBER 0 | ||||
| #        elif __has_cpp_attribute(no_unique_address) | ||||
| #            define LEXY_HAS_EMPTY_MEMBER 1 | ||||
| #        endif | ||||
| #    endif | ||||
| #    ifndef LEXY_HAS_EMPTY_MEMBER | ||||
| #        define LEXY_HAS_EMPTY_MEMBER 0 | ||||
| #    endif | ||||
|  | ||||
| #    if LEXY_HAS_EMPTY_MEMBER | ||||
| #        define LEXY_EMPTY_MEMBER [[no_unique_address]] | ||||
| #    else | ||||
| #        define LEXY_EMPTY_MEMBER | ||||
| #    endif | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #endif // LEXY_DETAIL_CONFIG_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										35
									
								
								dep/lexy/include/lexy/_detail/detect.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								dep/lexy/include/lexy/_detail/detect.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_DETECT_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_DETECT_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/config.hpp> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename... Args> | ||||
| using void_t = void; | ||||
|  | ||||
| template <template <typename...> typename Op, typename Void, typename... Args> | ||||
| struct _detector : std::false_type | ||||
| { | ||||
|     template <typename Fallback> | ||||
|     using type_or = Fallback; | ||||
| }; | ||||
| template <template <typename...> typename Op, typename... Args> | ||||
| struct _detector<Op, void_t<Op<Args...>>, Args...> : std::true_type | ||||
| { | ||||
|     template <typename Fallback> | ||||
|     using type_or = Op<Args...>; | ||||
| }; | ||||
|  | ||||
| template <template <typename...> typename Op, typename... Args> | ||||
| constexpr bool is_detected = _detector<Op, void, Args...>::value; | ||||
|  | ||||
| template <typename Fallback, template <typename...> typename Op, typename... Args> | ||||
| using detected_or = typename _detector<Op, void, Args...>::template type_or<Fallback>; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_DETECT_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										64
									
								
								dep/lexy/include/lexy/_detail/integer_sequence.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								dep/lexy/include/lexy/_detail/integer_sequence.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_INTEGER_SEQUENCE_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_INTEGER_SEQUENCE_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/config.hpp> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename T, T... Indices> | ||||
| struct integer_sequence | ||||
| { | ||||
|     using type = integer_sequence<T, Indices...>; | ||||
| }; | ||||
| template <std::size_t... Indices> | ||||
| using index_sequence = integer_sequence<std::size_t, Indices...>; | ||||
|  | ||||
| #if defined(__clang__) | ||||
| template <std::size_t Size> | ||||
| using make_index_sequence = __make_integer_seq<integer_sequence, std::size_t, Size>; | ||||
| #elif defined(__GNUC__) && __GNUC__ >= 8 | ||||
| template <std::size_t Size> | ||||
| using make_index_sequence = index_sequence<__integer_pack(Size)...>; | ||||
| #elif defined(_MSC_VER) | ||||
| template <std::size_t Size> | ||||
| using make_index_sequence = __make_integer_seq<integer_sequence, std::size_t, Size>; | ||||
| #else | ||||
|  | ||||
| // Adapted from https://stackoverflow.com/a/32223343. | ||||
| template <class Sequence1, class Sequence2> | ||||
| struct concat_seq; | ||||
| template <std::size_t... I1, std::size_t... I2> | ||||
| struct concat_seq<index_sequence<I1...>, index_sequence<I2...>> | ||||
| { | ||||
|     using type = index_sequence<I1..., (sizeof...(I1) + I2)...>; | ||||
| }; | ||||
|  | ||||
| template <size_t N> | ||||
| struct _make_index_sequence : concat_seq<typename _make_index_sequence<N / 2>::type, | ||||
|                                          typename _make_index_sequence<N - N / 2>::type> | ||||
| {}; | ||||
| template <> | ||||
| struct _make_index_sequence<0> | ||||
| { | ||||
|     using type = index_sequence<>; | ||||
| }; | ||||
| template <> | ||||
| struct _make_index_sequence<1> | ||||
| { | ||||
|     using type = index_sequence<0>; | ||||
| }; | ||||
|  | ||||
| template <std::size_t Size> | ||||
| using make_index_sequence = typename _make_index_sequence<Size>::type; | ||||
|  | ||||
| #endif | ||||
|  | ||||
| template <typename... T> | ||||
| using index_sequence_for = make_index_sequence<sizeof...(T)>; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_INTEGER_SEQUENCE_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										70
									
								
								dep/lexy/include/lexy/_detail/invoke.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								dep/lexy/include/lexy/_detail/invoke.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_INVOKE_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_INVOKE_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/config.hpp> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename MemberPtr, bool = std::is_member_object_pointer_v<MemberPtr>> | ||||
| struct _mem_invoker; | ||||
| template <typename R, typename ClassT> | ||||
| struct _mem_invoker<R ClassT::*, true> | ||||
| { | ||||
|     static constexpr decltype(auto) invoke(R ClassT::*f, ClassT& object) | ||||
|     { | ||||
|         return object.*f; | ||||
|     } | ||||
|     static constexpr decltype(auto) invoke(R ClassT::*f, const ClassT& object) | ||||
|     { | ||||
|         return object.*f; | ||||
|     } | ||||
|  | ||||
|     template <typename Ptr> | ||||
|     static constexpr auto invoke(R ClassT::*f, Ptr&& ptr) -> decltype((*LEXY_FWD(ptr)).*f) | ||||
|     { | ||||
|         return (*LEXY_FWD(ptr)).*f; | ||||
|     } | ||||
| }; | ||||
| template <typename F, typename ClassT> | ||||
| struct _mem_invoker<F ClassT::*, false> | ||||
| { | ||||
|     template <typename ObjectT, typename... Args> | ||||
|     static constexpr auto _invoke(int, F ClassT::*f, ObjectT&& object, Args&&... args) | ||||
|         -> decltype((LEXY_FWD(object).*f)(LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return (LEXY_FWD(object).*f)(LEXY_FWD(args)...); | ||||
|     } | ||||
|     template <typename PtrT, typename... Args> | ||||
|     static constexpr auto _invoke(short, F ClassT::*f, PtrT&& ptr, Args&&... args) | ||||
|         -> decltype(((*LEXY_FWD(ptr)).*f)(LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return ((*LEXY_FWD(ptr)).*f)(LEXY_FWD(args)...); | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     static constexpr auto invoke(F ClassT::*f, | ||||
|                                  Args&&... args) -> decltype(_invoke(0, f, LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return _invoke(0, f, LEXY_FWD(args)...); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename ClassT, typename F, typename... Args> | ||||
| constexpr auto invoke(F ClassT::*f, Args&&... args) | ||||
|     -> decltype(_mem_invoker<F ClassT::*>::invoke(f, LEXY_FWD(args)...)) | ||||
| { | ||||
|     return _mem_invoker<F ClassT::*>::invoke(f, LEXY_FWD(args)...); | ||||
| } | ||||
|  | ||||
| template <typename F, typename... Args> | ||||
| constexpr auto invoke(F&& f, Args&&... args) -> decltype(LEXY_FWD(f)(LEXY_FWD(args)...)) | ||||
| { | ||||
|     return LEXY_FWD(f)(LEXY_FWD(args)...); | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_INVOKE_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										244
									
								
								dep/lexy/include/lexy/_detail/iterator.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								dep/lexy/include/lexy/_detail/iterator.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,244 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_ITERATOR_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_ITERATOR_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/assert.hpp> | ||||
| #include <lexy/_detail/config.hpp> | ||||
| #include <lexy/_detail/detect.hpp> | ||||
| #include <lexy/_detail/std.hpp> | ||||
|  | ||||
| //=== iterator algorithms ===// | ||||
| namespace lexy::_detail | ||||
| { | ||||
| // Can't use std::is_base_of_v<std::random_access_iterator_tag, ...> without including <iterator>. | ||||
| template <typename Iterator> | ||||
| using _detect_random_access = decltype(LEXY_DECLVAL(Iterator) - LEXY_DECLVAL(Iterator)); | ||||
| template <typename Iterator> | ||||
| constexpr auto is_random_access_iterator = is_detected<_detect_random_access, Iterator>; | ||||
|  | ||||
| template <typename Iterator, typename Sentinel> | ||||
| constexpr std::size_t range_size(Iterator begin, Sentinel end) | ||||
| { | ||||
|     if constexpr (std::is_same_v<Iterator, Sentinel> && is_random_access_iterator<Iterator>) | ||||
|     { | ||||
|         return static_cast<std::size_t>(end - begin); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         std::size_t result = 0; | ||||
|         for (auto cur = begin; cur != end; ++cur) | ||||
|             ++result; | ||||
|         return result; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename Iterator> | ||||
| constexpr Iterator next(Iterator iter) | ||||
| { | ||||
|     return ++iter; | ||||
| } | ||||
| template <typename Iterator> | ||||
| constexpr Iterator next(Iterator iter, std::size_t n) | ||||
| { | ||||
|     if constexpr (is_random_access_iterator<Iterator>) | ||||
|     { | ||||
|         return iter + n; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         for (auto i = 0u; i != n; ++i) | ||||
|             ++iter; | ||||
|         return iter; | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename Iterator, typename Sentinel> | ||||
| constexpr Iterator next_clamped(Iterator iter, std::size_t n, Sentinel end) | ||||
| { | ||||
|     if constexpr (is_random_access_iterator<Iterator> && std::is_same_v<Iterator, Sentinel>) | ||||
|     { | ||||
|         auto remaining = std::size_t(end - iter); | ||||
|         if (remaining < n) | ||||
|             return end; | ||||
|         else | ||||
|             return iter + n; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         for (auto i = 0u; i != n; ++i) | ||||
|         { | ||||
|             if (iter == end) | ||||
|                 break; | ||||
|             ++iter; | ||||
|         } | ||||
|         return iter; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Used for assertions. | ||||
| template <typename Iterator, typename Sentinel> | ||||
| constexpr bool precedes([[maybe_unused]] Iterator first, [[maybe_unused]] Sentinel after) | ||||
| { | ||||
|     if constexpr (is_random_access_iterator<Iterator> && std::is_same_v<Iterator, Sentinel>) | ||||
|         return first <= after; | ||||
|     else | ||||
|         return true; | ||||
| } | ||||
|  | ||||
| // Requires: begin <= end_a && begin <= end_b. | ||||
| // Returns min(end_a, end_b). | ||||
| template <typename Iterator> | ||||
| constexpr Iterator min_range_end(Iterator begin, Iterator end_a, Iterator end_b) | ||||
| { | ||||
|     if constexpr (is_random_access_iterator<Iterator>) | ||||
|     { | ||||
|         LEXY_PRECONDITION(begin <= end_a && begin <= end_b); | ||||
|         if (end_a <= end_b) | ||||
|             return end_a; | ||||
|         else | ||||
|             return end_b; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         auto cur = begin; | ||||
|         while (cur != end_a && cur != end_b) | ||||
|             ++cur; | ||||
|         return cur; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Requires: begin <= end_a && begin <= end_b. | ||||
| // Returns max(end_a, end_b). | ||||
| template <typename Iterator> | ||||
| constexpr Iterator max_range_end(Iterator begin, Iterator end_a, Iterator end_b) | ||||
| { | ||||
|     if constexpr (is_random_access_iterator<Iterator>) | ||||
|     { | ||||
|         LEXY_PRECONDITION(begin <= end_a && begin <= end_b); | ||||
|         if (end_a <= end_b) | ||||
|             return end_b; | ||||
|         else | ||||
|             return end_a; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         auto cur = begin; | ||||
|         while (true) | ||||
|         { | ||||
|             if (cur == end_a) | ||||
|                 return end_b; | ||||
|             else if (cur == end_b) | ||||
|                 return end_a; | ||||
|  | ||||
|             ++cur; | ||||
|         } | ||||
|         return begin; // unreachable | ||||
|     } | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| //=== facade classes ===// | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename T> | ||||
| struct _proxy_pointer | ||||
| { | ||||
|     T value; | ||||
|  | ||||
|     constexpr T* operator->() noexcept | ||||
|     { | ||||
|         return &value; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Derived, typename T, typename Reference = T&, typename Pointer = const T*> | ||||
| struct forward_iterator_base | ||||
| { | ||||
|     using value_type        = std::remove_cv_t<T>; | ||||
|     using reference         = Reference; | ||||
|     using pointer           = lexy::_detail::type_or<Pointer, _proxy_pointer<value_type>>; | ||||
|     using difference_type   = std::ptrdiff_t; | ||||
|     using iterator_category = std::forward_iterator_tag; | ||||
|  | ||||
|     constexpr reference operator*() const noexcept | ||||
|     { | ||||
|         return static_cast<const Derived&>(*this).deref(); | ||||
|     } | ||||
|     constexpr pointer operator->() const noexcept | ||||
|     { | ||||
|         if constexpr (std::is_void_v<Pointer>) | ||||
|             return pointer{**this}; | ||||
|         else | ||||
|             return &**this; | ||||
|     } | ||||
|  | ||||
|     constexpr Derived& operator++() noexcept | ||||
|     { | ||||
|         auto& derived = static_cast<Derived&>(*this); | ||||
|         derived.increment(); | ||||
|         return derived; | ||||
|     } | ||||
|     constexpr Derived operator++(int) noexcept | ||||
|     { | ||||
|         auto& derived = static_cast<Derived&>(*this); | ||||
|         auto  copy    = derived; | ||||
|         derived.increment(); | ||||
|         return copy; | ||||
|     } | ||||
|  | ||||
|     friend constexpr bool operator==(const Derived& lhs, const Derived& rhs) | ||||
|     { | ||||
|         return lhs.equal(rhs); | ||||
|     } | ||||
|     friend constexpr bool operator!=(const Derived& lhs, const Derived& rhs) | ||||
|     { | ||||
|         return !lhs.equal(rhs); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Derived, typename T, typename Reference = T&, typename Pointer = const T*> | ||||
| struct bidirectional_iterator_base : forward_iterator_base<Derived, T, Reference, Pointer> | ||||
| { | ||||
|     using iterator_category = std::bidirectional_iterator_tag; | ||||
|  | ||||
|     constexpr Derived& operator--() noexcept | ||||
|     { | ||||
|         auto& derived = static_cast<Derived&>(*this); | ||||
|         derived.decrement(); | ||||
|         return derived; | ||||
|     } | ||||
|     constexpr Derived operator--(int) noexcept | ||||
|     { | ||||
|         auto& derived = static_cast<Derived&>(*this); | ||||
|         auto  copy    = derived; | ||||
|         derived.decrement(); | ||||
|         return copy; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Derived, typename Iterator> | ||||
| struct sentinel_base | ||||
| { | ||||
|     friend constexpr bool operator==(const Iterator& lhs, Derived) noexcept | ||||
|     { | ||||
|         return lhs.is_end(); | ||||
|     } | ||||
|     friend constexpr bool operator!=(const Iterator& lhs, Derived) noexcept | ||||
|     { | ||||
|         return !(lhs == Derived{}); | ||||
|     } | ||||
|     friend constexpr bool operator==(Derived, const Iterator& rhs) noexcept | ||||
|     { | ||||
|         return rhs == Derived{}; | ||||
|     } | ||||
|     friend constexpr bool operator!=(Derived, const Iterator& rhs) noexcept | ||||
|     { | ||||
|         return !(rhs == Derived{}); | ||||
|     } | ||||
| }; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_ITERATOR_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										246
									
								
								dep/lexy/include/lexy/_detail/lazy_init.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								dep/lexy/include/lexy/_detail/lazy_init.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,246 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_LAZY_INIT_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_LAZY_INIT_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/assert.hpp> | ||||
| #include <lexy/_detail/config.hpp> | ||||
| #include <lexy/_detail/std.hpp> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename T> | ||||
| struct _lazy_init_storage_trivial | ||||
| { | ||||
|     bool _init; | ||||
|     union | ||||
|     { | ||||
|         char _empty; | ||||
|         T    _value; | ||||
|     }; | ||||
|  | ||||
|     constexpr _lazy_init_storage_trivial() noexcept : _init(false), _empty() {} | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr _lazy_init_storage_trivial(int, Args&&... args) | ||||
|     : _init(true), _value(LEXY_FWD(args)...) | ||||
|     {} | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr void _construct(Args&&... args) | ||||
|     { | ||||
|         *this = _lazy_init_storage_trivial(0, LEXY_FWD(args)...); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename T> | ||||
| struct _lazy_init_storage_non_trivial | ||||
| { | ||||
|     bool _init; | ||||
|     union | ||||
|     { | ||||
|         char _empty; | ||||
|         T    _value; | ||||
|     }; | ||||
|  | ||||
|     constexpr _lazy_init_storage_non_trivial() noexcept : _init(false), _empty() {} | ||||
|  | ||||
|     template <typename... Args> | ||||
|     LEXY_CONSTEXPR_DTOR void _construct(Args&&... args) | ||||
|     { | ||||
|         _detail::construct_at(&_value, LEXY_FWD(args)...); | ||||
|         _init = true; | ||||
|     } | ||||
|  | ||||
|     // Cannot add noexcept due to https://github.com/llvm/llvm-project/issues/59854. | ||||
|     LEXY_CONSTEXPR_DTOR ~_lazy_init_storage_non_trivial() /* noexcept */ | ||||
|     { | ||||
|         if (_init) | ||||
|             _value.~T(); | ||||
|     } | ||||
|  | ||||
|     LEXY_CONSTEXPR_DTOR _lazy_init_storage_non_trivial( | ||||
|         _lazy_init_storage_non_trivial&& other) noexcept | ||||
|     : _init(other._init), _empty() | ||||
|     { | ||||
|         if (_init) | ||||
|             _detail::construct_at(&_value, LEXY_MOV(other._value)); | ||||
|     } | ||||
|  | ||||
|     LEXY_CONSTEXPR_DTOR _lazy_init_storage_non_trivial& operator=( | ||||
|         _lazy_init_storage_non_trivial&& other) noexcept | ||||
|     { | ||||
|         if (_init && other._init) | ||||
|             _value = LEXY_MOV(other._value); | ||||
|         else if (_init && !other._init) | ||||
|         { | ||||
|             _value.~T(); | ||||
|             _init = false; | ||||
|         } | ||||
|         else if (!_init && other._init) | ||||
|         { | ||||
|             _detail::construct_at(&_value, LEXY_MOV(other._value)); | ||||
|             _init = true; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Both not initialized, nothing to do. | ||||
|         } | ||||
|  | ||||
|         return *this; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename T> | ||||
| constexpr auto _lazy_init_trivial = [] { | ||||
|     // https://www.foonathan.net/2021/03/trivially-copyable/ | ||||
|     return std::is_trivially_destructible_v<T>          // | ||||
|            && std::is_trivially_copy_constructible_v<T> // | ||||
|            && std::is_trivially_copy_assignable_v<T>    // | ||||
|            && std::is_trivially_move_constructible_v<T> // | ||||
|            && std::is_trivially_move_assignable_v<T>; | ||||
| }(); | ||||
| template <typename T> | ||||
| using _lazy_init_storage = std::conditional_t<_lazy_init_trivial<T>, _lazy_init_storage_trivial<T>, | ||||
|                                               _lazy_init_storage_non_trivial<T>>; | ||||
|  | ||||
| template <typename T> | ||||
| class lazy_init : _lazy_init_storage<T> | ||||
| { | ||||
| public: | ||||
|     using value_type = T; | ||||
|  | ||||
|     constexpr lazy_init() noexcept = default; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr T& emplace(Args&&... args) | ||||
|     { | ||||
|         if (*this) | ||||
|             this->_value = T(LEXY_FWD(args)...); | ||||
|         else | ||||
|             this->_construct(LEXY_FWD(args)...); | ||||
|  | ||||
|         return this->_value; | ||||
|     } | ||||
|  | ||||
|     template <typename Fn, typename... Args> | ||||
|     constexpr T& emplace_result(Fn&& fn, Args&&... args) | ||||
|     { | ||||
|         return emplace(LEXY_FWD(fn)(LEXY_FWD(args)...)); | ||||
|     } | ||||
|  | ||||
|     constexpr explicit operator bool() const noexcept | ||||
|     { | ||||
|         return this->_init; | ||||
|     } | ||||
|  | ||||
|     constexpr T& operator*() & noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(*this); | ||||
|         return this->_value; | ||||
|     } | ||||
|     constexpr const T& operator*() const& noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(*this); | ||||
|         return this->_value; | ||||
|     } | ||||
|     constexpr T&& operator*() && noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(*this); | ||||
|         return LEXY_MOV(this->_value); | ||||
|     } | ||||
|     constexpr const T&& operator*() const&& noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(*this); | ||||
|         return LEXY_MOV(this->_value); | ||||
|     } | ||||
|  | ||||
|     constexpr T* operator->() noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(*this); | ||||
|         return &this->_value; | ||||
|     } | ||||
|     constexpr const T* operator->() const noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(*this); | ||||
|         return &this->_value; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     template <typename... Args> | ||||
|     constexpr explicit lazy_init(int, Args&&... args) noexcept | ||||
|     : _lazy_init_storage<T>(0, LEXY_FWD(args)...) | ||||
|     {} | ||||
| }; | ||||
| template <typename T> | ||||
| class lazy_init<T&> | ||||
| { | ||||
| public: | ||||
|     using value_type = T&; | ||||
|  | ||||
|     constexpr lazy_init() noexcept : _ptr(nullptr) {} | ||||
|  | ||||
|     constexpr T& emplace(T& ref) | ||||
|     { | ||||
|         _ptr = &ref; | ||||
|         return ref; | ||||
|     } | ||||
|  | ||||
|     template <typename Fn, typename... Args> | ||||
|     constexpr T& emplace_result(Fn&& fn, Args&&... args) | ||||
|     { | ||||
|         return emplace(LEXY_FWD(fn)(LEXY_FWD(args)...)); | ||||
|     } | ||||
|  | ||||
|     constexpr explicit operator bool() const noexcept | ||||
|     { | ||||
|         return _ptr != nullptr; | ||||
|     } | ||||
|  | ||||
|     constexpr T& operator*() const noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(*this); | ||||
|         return *_ptr; | ||||
|     } | ||||
|  | ||||
|     constexpr T* operator->() const noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(*this); | ||||
|         return _ptr; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     T* _ptr; | ||||
| }; | ||||
| template <> | ||||
| class lazy_init<void> | ||||
| { | ||||
| public: | ||||
|     using value_type = void; | ||||
|  | ||||
|     constexpr lazy_init() noexcept : _init(false) {} | ||||
|  | ||||
|     constexpr void emplace() | ||||
|     { | ||||
|         _init = true; | ||||
|     } | ||||
|     template <typename Fn, typename... Args> | ||||
|     constexpr void emplace_result(Fn&& fn, Args&&... args) | ||||
|     { | ||||
|         LEXY_FWD(fn)(LEXY_FWD(args)...); | ||||
|         _init = true; | ||||
|     } | ||||
|  | ||||
|     constexpr explicit operator bool() const noexcept | ||||
|     { | ||||
|         return _init; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     bool _init; | ||||
| }; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_LAZY_INIT_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										152
									
								
								dep/lexy/include/lexy/_detail/memory_resource.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								dep/lexy/include/lexy/_detail/memory_resource.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_MEMORY_RESOURCE_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_MEMORY_RESOURCE_HPP_INCLUDED | ||||
|  | ||||
| #include <cstring> | ||||
| #include <lexy/_detail/assert.hpp> | ||||
| #include <lexy/_detail/config.hpp> | ||||
| #include <new> | ||||
|  | ||||
| #if 0 // NOLINT | ||||
| // Subset of the interface of std::pmr::memory_resource. | ||||
| class MemoryResource | ||||
| { | ||||
| public: | ||||
|     void* allocate(std::size_t bytes, std::size_t alignment); | ||||
|     void deallocate(void* ptr, std::size_t bytes, std::size_t alignment); | ||||
|  | ||||
|     friend bool operator==(const MemoryResource& lhs, const MemoryResource& rhs); | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| class default_memory_resource | ||||
| { | ||||
| public: | ||||
|     static void* allocate(std::size_t bytes, std::size_t alignment) | ||||
|     { | ||||
|         if (alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__) | ||||
|             return ::operator new(bytes, std::align_val_t{alignment}); | ||||
|         else | ||||
|             return ::operator new(bytes); | ||||
|     } | ||||
|  | ||||
|     static void deallocate(void* ptr, std::size_t bytes, std::size_t alignment) noexcept | ||||
|     { | ||||
| #if LEXY_ENABLE_ASSERT | ||||
|         // In debug mode, we fill freed memory with 0xFF to detect dangling lexemes. | ||||
|         // For default, ASCII, bytes, this is just a noticable value. | ||||
|         // For UTF-8, this is the EOF integer value as its an invalid code unit. | ||||
|         // For UTF-16, this is the code point 0xFFFF, which is the replacement character. | ||||
|         // For UTF-32, this is an out of range code point. | ||||
|         std::memset(ptr, 0xFF, bytes); | ||||
| #endif | ||||
|  | ||||
| #ifdef __cpp_sized_deallocation | ||||
|         if (alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__) | ||||
|             ::operator delete(ptr, bytes, std::align_val_t{alignment}); | ||||
|         else | ||||
|             ::operator delete(ptr, bytes); | ||||
| #else | ||||
|         (void)bytes; | ||||
|  | ||||
|         if (alignment > __STDCPP_DEFAULT_NEW_ALIGNMENT__) | ||||
|             ::operator delete(ptr, std::align_val_t{alignment}); | ||||
|         else | ||||
|             ::operator delete(ptr); | ||||
| #endif | ||||
|     } | ||||
|  | ||||
|     friend constexpr bool operator==(default_memory_resource, default_memory_resource) noexcept | ||||
|     { | ||||
|         return true; | ||||
|     } | ||||
| }; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename MemoryResource> | ||||
| class _memory_resource_ptr_empty | ||||
| { | ||||
| public: | ||||
|     constexpr explicit _memory_resource_ptr_empty(MemoryResource*) noexcept {} | ||||
|     constexpr explicit _memory_resource_ptr_empty(void*) noexcept {} | ||||
|  | ||||
|     constexpr auto operator*() const noexcept | ||||
|     { | ||||
|         return MemoryResource{}; | ||||
|     } | ||||
|  | ||||
|     constexpr auto operator->() const noexcept | ||||
|     { | ||||
|         struct proxy | ||||
|         { | ||||
|             MemoryResource _resource; | ||||
|  | ||||
|             constexpr MemoryResource* operator->() noexcept | ||||
|             { | ||||
|                 return &_resource; | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         return proxy{}; | ||||
|     } | ||||
|  | ||||
|     constexpr MemoryResource* get() const noexcept | ||||
|     { | ||||
|         return nullptr; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename MemoryResource> | ||||
| class _memory_resource_ptr | ||||
| { | ||||
| public: | ||||
|     constexpr explicit _memory_resource_ptr(MemoryResource* resource) noexcept : _resource(resource) | ||||
|     { | ||||
|         LEXY_PRECONDITION(resource); | ||||
|     } | ||||
|  | ||||
|     constexpr MemoryResource& operator*() const noexcept | ||||
|     { | ||||
|         return *_resource; | ||||
|     } | ||||
|  | ||||
|     constexpr MemoryResource* operator->() const noexcept | ||||
|     { | ||||
|         return _resource; | ||||
|     } | ||||
|  | ||||
|     constexpr MemoryResource* get() const noexcept | ||||
|     { | ||||
|         return _resource; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     MemoryResource* _resource; | ||||
| }; | ||||
|  | ||||
| // clang-format off | ||||
| template <typename MemoryResource> | ||||
| using memory_resource_ptr | ||||
|     = std::conditional_t<std::is_void_v<MemoryResource>, | ||||
|             _memory_resource_ptr_empty<default_memory_resource>, | ||||
|             std::conditional_t<std::is_empty_v<MemoryResource>, | ||||
|                 _memory_resource_ptr_empty<MemoryResource>, | ||||
|                 _memory_resource_ptr<MemoryResource>>>; | ||||
| // clang-format on | ||||
|  | ||||
| template <typename MemoryResource, typename = std::enable_if_t<std::is_void_v<MemoryResource> | ||||
|                                                                || std::is_empty_v<MemoryResource>>> | ||||
| constexpr MemoryResource* get_memory_resource() | ||||
| { | ||||
|     return nullptr; | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_MEMORY_RESOURCE_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										147
									
								
								dep/lexy/include/lexy/_detail/nttp_string.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								dep/lexy/include/lexy/_detail/nttp_string.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_NTTP_STRING_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_NTTP_STRING_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/assert.hpp> | ||||
| #include <lexy/_detail/config.hpp> | ||||
| #include <lexy/encoding.hpp> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| // Note: we can't use type_string<auto...>, it doesn't work on older GCC. | ||||
| template <typename CharT, CharT... Cs> | ||||
| struct type_string | ||||
| { | ||||
|     using char_type = CharT; | ||||
|  | ||||
|     template <template <typename C, C...> typename T> | ||||
|     using rename = T<CharT, Cs...>; | ||||
|  | ||||
|     static constexpr auto size = sizeof...(Cs); | ||||
|  | ||||
|     template <typename T = char_type> | ||||
|     static constexpr T c_str[sizeof...(Cs) + 1] = {transcode_char<T>(Cs)..., T()}; | ||||
| }; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #if LEXY_HAS_NTTP // string NTTP implementation | ||||
|  | ||||
| #    include <lexy/_detail/integer_sequence.hpp> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <std::size_t N, typename CharT> | ||||
| struct string_literal | ||||
| { | ||||
|     CharT data[N]; | ||||
|  | ||||
|     using char_type = CharT; | ||||
|  | ||||
|     LEXY_CONSTEVAL string_literal(const CharT* str) : data{} | ||||
|     { | ||||
|         for (auto i = 0u; i != N; ++i) | ||||
|             data[i] = str[i]; | ||||
|     } | ||||
|     LEXY_CONSTEVAL string_literal(CharT c) : data{} | ||||
|     { | ||||
|         data[0] = c; | ||||
|     } | ||||
|  | ||||
|     static LEXY_CONSTEVAL auto size() | ||||
|     { | ||||
|         return N; | ||||
|     } | ||||
| }; | ||||
| template <std::size_t N, typename CharT> | ||||
| string_literal(const CharT (&)[N]) -> string_literal<N - 1, CharT>; | ||||
| template <typename CharT> | ||||
| string_literal(CharT) -> string_literal<1, CharT>; | ||||
|  | ||||
| template <template <typename C, C... Cs> typename T, string_literal Str, std::size_t... Idx> | ||||
| auto _to_type_string(index_sequence<Idx...>) | ||||
| { | ||||
|     return T<typename decltype(Str)::char_type, Str.data[Idx]...>{}; | ||||
| } | ||||
| template <template <typename C, C... Cs> typename T, string_literal Str> | ||||
| using to_type_string | ||||
|     = decltype(_to_type_string<T, Str>(make_index_sequence<decltype(Str)::size()>{})); | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #    define LEXY_NTTP_STRING(T, Str)                                                               \ | ||||
|         ::lexy::_detail::to_type_string<T, ::lexy::_detail::string_literal(Str)> | ||||
|  | ||||
| #elif defined(__GNUC__) // literal implementation | ||||
|  | ||||
| #    pragma GCC diagnostic push | ||||
| #    pragma GCC diagnostic ignored "-Wpedantic" | ||||
| #    ifdef __clang__ | ||||
| #        pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template" | ||||
| #    endif | ||||
|  | ||||
| template <typename CharT, CharT... Cs> | ||||
| constexpr ::lexy::_detail::type_string<CharT, Cs...> operator""_lexy_string_udl() | ||||
| { | ||||
|     return {}; | ||||
| } | ||||
|  | ||||
| #    define LEXY_NTTP_STRING(T, Str) decltype(Str##_lexy_string_udl)::rename<T> | ||||
|  | ||||
| #    pragma GCC diagnostic pop | ||||
|  | ||||
| #else // string<Cs...> macro implementation | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename A, typename B> | ||||
| struct cat_; | ||||
| template <typename CharT, CharT... C1, CharT... C2> | ||||
| struct cat_<type_string<CharT, C1...>, type_string<CharT, C2...>> | ||||
| { | ||||
|     using type = type_string<CharT, C1..., C2...>; | ||||
| }; | ||||
| template <typename A, typename B> | ||||
| using cat = typename cat_<A, B>::type; | ||||
|  | ||||
| template <template <typename CharT, CharT...> typename T, typename TypeString, std::size_t Size, | ||||
|           std::size_t MaxSize> | ||||
| struct macro_type_string | ||||
| { | ||||
|     static_assert(Size <= MaxSize, "string out of range"); | ||||
|     using type = typename TypeString::template rename<T>; | ||||
| }; | ||||
|  | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #    define LEXY_NTTP_STRING_LENGTH(Str) (sizeof(Str) / sizeof(Str[0]) - 1) | ||||
|  | ||||
| // extract Ith character if not out of bounds | ||||
| #    define LEXY_NTTP_STRING1(Str, I)                                                              \ | ||||
|         ::std::conditional_t<                                                                      \ | ||||
|             (I < LEXY_NTTP_STRING_LENGTH(Str)),                                                    \ | ||||
|             ::lexy::_detail::type_string<::LEXY_DECAY_DECLTYPE(Str[0]),                            \ | ||||
|                                          (I >= LEXY_NTTP_STRING_LENGTH(Str) ? Str[0] : Str[I])>,   \ | ||||
|             ::lexy::_detail::type_string<::LEXY_DECAY_DECLTYPE(Str[0])>> | ||||
|  | ||||
| // recursively split the string in two | ||||
| #    define LEXY_NTTP_STRING2(Str, I)                                                              \ | ||||
|         ::lexy::_detail::cat<LEXY_NTTP_STRING1(Str, I), LEXY_NTTP_STRING1(Str, I + 1)> | ||||
| #    define LEXY_NTTP_STRING4(Str, I)                                                              \ | ||||
|         ::lexy::_detail::cat<LEXY_NTTP_STRING2(Str, I), LEXY_NTTP_STRING2(Str, I + 2)> | ||||
| #    define LEXY_NTTP_STRING8(Str, I)                                                              \ | ||||
|         ::lexy::_detail::cat<LEXY_NTTP_STRING4(Str, I), LEXY_NTTP_STRING4(Str, I + 4)> | ||||
| #    define LEXY_NTTP_STRING16(Str, I)                                                             \ | ||||
|         ::lexy::_detail::cat<LEXY_NTTP_STRING8(Str, I), LEXY_NTTP_STRING8(Str, I + 8)> | ||||
| #    define LEXY_NTTP_STRING32(Str, I)                                                             \ | ||||
|         ::lexy::_detail::cat<LEXY_NTTP_STRING16(Str, I), LEXY_NTTP_STRING16(Str, I + 16)> | ||||
|  | ||||
| // instantiate with overflow check | ||||
| #    define LEXY_NTTP_STRING(T, Str)                                                               \ | ||||
|         ::lexy::_detail::macro_type_string<T, LEXY_NTTP_STRING32(Str, 0),                          \ | ||||
|                                            LEXY_NTTP_STRING_LENGTH(Str), 32>::type | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #endif // LEXY_DETAIL_NTTP_STRING_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										72
									
								
								dep/lexy/include/lexy/_detail/stateless_lambda.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								dep/lexy/include/lexy/_detail/stateless_lambda.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_STATELESS_LAMBDA_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_STATELESS_LAMBDA_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/config.hpp> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename Lambda> | ||||
| struct stateless_lambda | ||||
| { | ||||
|     static_assert(std::is_class_v<Lambda>); | ||||
|     static_assert(std::is_empty_v<Lambda>); | ||||
|  | ||||
|     static constexpr Lambda get() | ||||
|     { | ||||
|         if constexpr (std::is_default_constructible_v<Lambda>) | ||||
|         { | ||||
|             // We're using C++20, lambdas are default constructible. | ||||
|             return Lambda(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // We're not having C++20; use a sequence of weird workarounds to legally construct a | ||||
|             // Lambda object without invoking any constructors. | ||||
|             // This works and is well-defined, but sadly not constexpr. | ||||
|             // Taken from: https://www.youtube.com/watch?v=yTb6xz_FSkY | ||||
|  | ||||
|             // We're defining two standard layout types that have a char as a common initial | ||||
|             // sequence (as the Lambda is empty, it doesn't add anymore members to B). | ||||
|             struct A | ||||
|             { | ||||
|                 char member; | ||||
|             }; | ||||
|             struct B : Lambda | ||||
|             { | ||||
|                 char member; | ||||
|             }; | ||||
|             static_assert(std::is_standard_layout_v<A> && std::is_standard_layout_v<B>); | ||||
|  | ||||
|             // We put the two types in a union and initialize the a member, which we can do. | ||||
|             union storage_t | ||||
|             { | ||||
|                 A a; | ||||
|                 B b; | ||||
|             } storage{}; | ||||
|  | ||||
|             // We can now take the address of member via b, as it is in the common initial sequence. | ||||
|             auto char_ptr = &storage.b.member; | ||||
|             // char_ptr is a pointer to the first member of B, so we can reinterpret_cast it to a | ||||
|             // pointer to B. | ||||
|             auto b_ptr = reinterpret_cast<B*>(char_ptr); | ||||
|             // Now we're having a pointer to a B object, which can we can cast to the base class | ||||
|             // Lambda. | ||||
|             auto lambda_ptr = static_cast<Lambda*>(b_ptr); | ||||
|             // Dereference the pointer to get the lambda object. | ||||
|             return *lambda_ptr; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr decltype(auto) operator()(Args&&... args) const | ||||
|     { | ||||
|         return get()(LEXY_FWD(args)...); | ||||
|     } | ||||
| }; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_STATELESS_LAMBDA_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										98
									
								
								dep/lexy/include/lexy/_detail/std.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								dep/lexy/include/lexy/_detail/std.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_STD_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_STD_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/config.hpp> | ||||
|  | ||||
| //=== iterator tags ===// | ||||
| #if defined(__GLIBCXX__) | ||||
|  | ||||
| namespace std | ||||
| { | ||||
| _GLIBCXX_BEGIN_NAMESPACE_VERSION | ||||
| struct forward_iterator_tag; | ||||
| struct bidirectional_iterator_tag; | ||||
| _GLIBCXX_END_NAMESPACE_VERSION | ||||
| } // namespace std | ||||
|  | ||||
| #elif defined(_LIBCPP_VERSION) | ||||
|  | ||||
| _LIBCPP_BEGIN_NAMESPACE_STD | ||||
| struct forward_iterator_tag; | ||||
| struct bidirectional_iterator_tag; | ||||
| _LIBCPP_END_NAMESPACE_STD | ||||
|  | ||||
| #else | ||||
|  | ||||
| // Forward declaring things in std is not allowed, but I'm willing to take the risk. | ||||
|  | ||||
| namespace std | ||||
| { | ||||
| struct forward_iterator_tag; | ||||
| struct bidirectional_iterator_tag; | ||||
| } // namespace std | ||||
|  | ||||
| #endif | ||||
|  | ||||
| //=== (constexpr) construct_at ===// | ||||
| #if !LEXY_HAS_CONSTEXPR_DTOR | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| // We don't have constexpr dtor's, so this is just a regular function. | ||||
| template <typename T, typename... Args> | ||||
| T* construct_at(T* ptr, Args&&... args) | ||||
| { | ||||
|     return ::new ((void*)ptr) T(LEXY_FWD(args)...); | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #elif defined(_MSC_VER) | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| // MSVC can make it constexpr if marked with an attribute given by a macro. | ||||
| template <typename T, typename... Args> | ||||
| constexpr T* construct_at(T* ptr, Args&&... args) | ||||
| { | ||||
| #    if defined(_MSVC_CONSTEXPR) | ||||
|     _MSVC_CONSTEXPR | ||||
| #    endif | ||||
|     return ::new ((void*)ptr) T(LEXY_FWD(args)...); | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #else | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| struct _construct_at_tag | ||||
| {}; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| namespace std | ||||
| { | ||||
| // GCC only allows constexpr placement new inside a function called `std::construct_at`. | ||||
| // So we write our own. | ||||
| template <typename T, typename... Args> | ||||
| constexpr T* construct_at(lexy::_detail::_construct_at_tag, T* ptr, Args&&... args) | ||||
| { | ||||
|     return ::new ((void*)ptr) T(LEXY_FWD(args)...); | ||||
| } | ||||
| } // namespace std | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename T, typename... Args> | ||||
| constexpr T* construct_at(T* ptr, Args&&... args) | ||||
| { | ||||
|     return std::construct_at(lexy::_detail::_construct_at_tag{}, ptr, LEXY_FWD(args)...); | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #endif // LEXY_DETAIL_STD_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										212
									
								
								dep/lexy/include/lexy/_detail/string_view.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								dep/lexy/include/lexy/_detail/string_view.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,212 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_STRING_VIEW_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_STRING_VIEW_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/assert.hpp> | ||||
| #include <lexy/_detail/config.hpp> | ||||
| #include <lexy/_detail/integer_sequence.hpp> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| struct null_terminated | ||||
| {}; | ||||
|  | ||||
| template <typename CharT> | ||||
| class basic_string_view | ||||
| { | ||||
|     static constexpr CharT empty_string[] = {CharT()}; | ||||
|  | ||||
| public: | ||||
|     using char_type = CharT; | ||||
|  | ||||
|     //=== constructor ===// | ||||
|     constexpr basic_string_view() noexcept : _ptr(empty_string), _size(0u), _null_terminated(true) | ||||
|     {} | ||||
|  | ||||
|     constexpr basic_string_view(const char_type* str) noexcept | ||||
|     : _ptr(str), _size(0u), _null_terminated(true) | ||||
|     { | ||||
|         while (*str++) | ||||
|             ++_size; | ||||
|     } | ||||
|  | ||||
|     constexpr basic_string_view(const char_type* ptr, std::size_t size) noexcept | ||||
|     : _ptr(ptr), _size(size), _null_terminated(false) | ||||
|     {} | ||||
|     constexpr basic_string_view(null_terminated, const char_type* ptr, std::size_t size) noexcept | ||||
|     : _ptr(ptr), _size(size), _null_terminated(true) | ||||
|     { | ||||
|         LEXY_PRECONDITION(_ptr[_size] == CharT()); | ||||
|     } | ||||
|  | ||||
|     constexpr basic_string_view(const char_type* begin, const char_type* end) noexcept | ||||
|     : _ptr(begin), _size(std::size_t(end - begin)), _null_terminated(false) | ||||
|     { | ||||
|         LEXY_PRECONDITION(begin <= end); | ||||
|     } | ||||
|  | ||||
|     //=== access ===// | ||||
|     using iterator = const char_type*; | ||||
|  | ||||
|     constexpr iterator begin() const noexcept | ||||
|     { | ||||
|         return _ptr; | ||||
|     } | ||||
|     constexpr iterator end() const noexcept | ||||
|     { | ||||
|         return _ptr + _size; | ||||
|     } | ||||
|  | ||||
|     constexpr bool empty() const noexcept | ||||
|     { | ||||
|         return _size == 0u; | ||||
|     } | ||||
|     constexpr std::size_t size() const noexcept | ||||
|     { | ||||
|         return _size; | ||||
|     } | ||||
|     constexpr std::size_t length() const noexcept | ||||
|     { | ||||
|         return _size; | ||||
|     } | ||||
|  | ||||
|     constexpr char_type operator[](std::size_t i) const noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(i <= _size); | ||||
|         return _ptr[i]; | ||||
|     } | ||||
|     constexpr char_type front() const noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(!empty()); | ||||
|         return *_ptr; | ||||
|     } | ||||
|     constexpr char_type back() const noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(!empty()); | ||||
|         return _ptr[_size - 1]; | ||||
|     } | ||||
|  | ||||
|     constexpr const char_type* data() const noexcept | ||||
|     { | ||||
|         return _ptr; | ||||
|     } | ||||
|  | ||||
|     constexpr bool is_null_terminated() const noexcept | ||||
|     { | ||||
|         return _null_terminated; | ||||
|     } | ||||
|  | ||||
|     constexpr const char_type* c_str() const noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(is_null_terminated()); | ||||
|         return _ptr; | ||||
|     } | ||||
|  | ||||
|     //=== operations ===// | ||||
|     static constexpr std::size_t npos = std::size_t(-1); | ||||
|  | ||||
|     constexpr void remove_prefix(std::size_t n) noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(n <= _size); | ||||
|         _ptr += n; | ||||
|         _size -= n; | ||||
|     } | ||||
|     constexpr void remove_suffix(std::size_t n) noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(n <= _size); | ||||
|         _size -= n; | ||||
|         _null_terminated = false; | ||||
|     } | ||||
|  | ||||
|     constexpr basic_string_view substr(std::size_t pos, std::size_t length = npos) const noexcept | ||||
|     { | ||||
|         LEXY_PRECONDITION(pos < _size); | ||||
|         if (length >= _size - pos) | ||||
|         { | ||||
|             auto result             = basic_string_view(_ptr + pos, end()); | ||||
|             result._null_terminated = _null_terminated; | ||||
|             return result; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Note that we're loosing null-terminated-ness. | ||||
|             return basic_string_view(_ptr + pos, length); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     constexpr bool starts_with(basic_string_view prefix) const noexcept | ||||
|     { | ||||
|         return substr(0, prefix.size()) == prefix; | ||||
|     } | ||||
|     constexpr bool try_remove_prefix(basic_string_view prefix) noexcept | ||||
|     { | ||||
|         if (!starts_with(prefix)) | ||||
|             return false; | ||||
|  | ||||
|         remove_prefix(prefix.length()); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     constexpr std::size_t find(basic_string_view str, std::size_t pos = 0) const noexcept | ||||
|     { | ||||
|         for (auto i = pos; i < length(); ++i) | ||||
|         { | ||||
|             if (substr(i, str.length()) == str) | ||||
|                 return i; | ||||
|         } | ||||
|  | ||||
|         return npos; | ||||
|     } | ||||
|     constexpr std::size_t find(CharT c, std::size_t pos = 0) const noexcept | ||||
|     { | ||||
|         return find(basic_string_view(&c, 1), pos); | ||||
|     } | ||||
|  | ||||
|     //=== comparison ===// | ||||
|     friend constexpr bool operator==(basic_string_view<CharT> lhs, | ||||
|                                      basic_string_view<CharT> rhs) noexcept | ||||
|     { | ||||
|         if (lhs.size() != rhs.size()) | ||||
|             return false; | ||||
|  | ||||
|         for (auto a = lhs.begin(), b = rhs.begin(); a != lhs.end(); ++a, ++b) | ||||
|             if (*a != *b) | ||||
|                 return false; | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     friend constexpr bool operator!=(basic_string_view<CharT> lhs, | ||||
|                                      basic_string_view<CharT> rhs) noexcept | ||||
|     { | ||||
|         return !(lhs == rhs); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const CharT* _ptr; | ||||
|     std::size_t  _size; | ||||
|     bool         _null_terminated; | ||||
| }; | ||||
| using string_view = basic_string_view<char>; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <auto FnPtr, typename Indices = make_index_sequence<FnPtr().size()>> | ||||
| struct _string_view_holder; | ||||
| template <auto FnPtr, std::size_t... Indices> | ||||
| struct _string_view_holder<FnPtr, index_sequence<Indices...>> | ||||
| { | ||||
|     static constexpr auto view = FnPtr(); | ||||
|  | ||||
|     static constexpr typename decltype(view)::char_type value[] = {view[Indices]..., {}}; | ||||
| }; | ||||
|  | ||||
| template <auto FnPtr> | ||||
| inline constexpr const auto* make_cstr = _string_view_holder<FnPtr>::value; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_STRING_VIEW_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										251
									
								
								dep/lexy/include/lexy/_detail/swar.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								dep/lexy/include/lexy/_detail/swar.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,251 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_SWAR_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_SWAR_HPP_INCLUDED | ||||
|  | ||||
| #include <climits> | ||||
| #include <cstdint> | ||||
| #include <cstring> | ||||
| #include <lexy/_detail/config.hpp> | ||||
| #include <lexy/input/base.hpp> | ||||
|  | ||||
| #if defined(_MSC_VER) | ||||
| #    include <intrin.h> | ||||
| #endif | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| // Contains the chars in little endian order; rightmost bits are first char. | ||||
| using swar_int = std::uintmax_t; | ||||
|  | ||||
| // The number of chars that can fit into one SWAR. | ||||
| template <typename CharT> | ||||
| constexpr auto swar_length = [] { | ||||
|     static_assert(sizeof(CharT) < sizeof(swar_int) && sizeof(swar_int) % sizeof(CharT) == 0); | ||||
|     return sizeof(swar_int) / sizeof(CharT); | ||||
| }(); | ||||
|  | ||||
| template <typename CharT> | ||||
| constexpr auto char_bit_size = sizeof(CharT) * CHAR_BIT; | ||||
|  | ||||
| template <typename CharT> | ||||
| constexpr auto make_uchar(CharT c) | ||||
| { | ||||
|     if constexpr (std::is_same_v<CharT, LEXY_CHAR8_T>) | ||||
|         // Not all libstdc++ support char8_t and std::make_unsigned_t. | ||||
|         return c; | ||||
|     else | ||||
|         return std::make_unsigned_t<CharT>(c); | ||||
| } | ||||
| template <typename CharT> | ||||
| using uchar_t = decltype(make_uchar(CharT())); | ||||
|  | ||||
| // Returns a swar_int filled with the specific char. | ||||
| template <typename CharT> | ||||
| constexpr swar_int swar_fill(CharT _c) | ||||
| { | ||||
|     auto c = make_uchar(_c); | ||||
|  | ||||
|     auto result = swar_int(0); | ||||
|     for (auto i = 0u; i != swar_length<CharT>; ++i) | ||||
|     { | ||||
|         result <<= char_bit_size<CharT>; | ||||
|         result |= c; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| // Returns a swar_int filled with the complement of the specific char. | ||||
| template <typename CharT> | ||||
| constexpr swar_int swar_fill_compl(CharT _c) | ||||
| { | ||||
|     auto c = uchar_t<CharT>(~uchar_t<CharT>(_c)); | ||||
|  | ||||
|     auto result = swar_int(0); | ||||
|     for (auto i = 0u; i != swar_length<CharT>; ++i) | ||||
|     { | ||||
|         result <<= char_bit_size<CharT>; | ||||
|         result |= c; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| constexpr void _swar_pack(swar_int&, int) {} | ||||
| template <typename H, typename... T> | ||||
| constexpr void _swar_pack(swar_int& result, int index, H h, T... t) | ||||
| { | ||||
|     if (std::size_t(index) == char_bit_size<swar_int>) | ||||
|         return; | ||||
|  | ||||
|     if (index >= 0) | ||||
|         result |= swar_int(make_uchar(h)) << index; | ||||
|  | ||||
|     _swar_pack(result, index + int(char_bit_size<H>), t...); | ||||
| } | ||||
|  | ||||
| template <typename CharT> | ||||
| struct swar_pack_result | ||||
| { | ||||
|     swar_int    value; | ||||
|     swar_int    mask; | ||||
|     std::size_t count; | ||||
|  | ||||
|     constexpr CharT operator[](std::size_t idx) const | ||||
|     { | ||||
|         constexpr auto mask = (swar_int(1) << char_bit_size<CharT>)-1; | ||||
|         return (value >> idx * char_bit_size<CharT>)&mask; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| // Returns a swar_int containing the specified characters. | ||||
| // If more are provided than fit, will only take the first couple ones. | ||||
| template <int SkipFirstNChars = 0, typename... CharT> | ||||
| constexpr auto swar_pack(CharT... cs) | ||||
| { | ||||
|     using char_type = std::common_type_t<CharT...>; | ||||
|     swar_pack_result<char_type> result{0, 0, 0}; | ||||
|  | ||||
|     _swar_pack(result.value, -SkipFirstNChars * int(char_bit_size<char_type>), cs...); | ||||
|  | ||||
|     auto count = int(sizeof...(CharT)) - SkipFirstNChars; | ||||
|     if (count <= 0) | ||||
|     { | ||||
|         result.mask  = 0; | ||||
|         result.count = 0; | ||||
|     } | ||||
|     else if (count >= int(swar_length<char_type>)) | ||||
|     { | ||||
|         result.mask  = swar_int(-1); | ||||
|         result.count = swar_length<char_type>; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         result.mask  = swar_int(swar_int(1) << count * int(char_bit_size<char_type>)) - 1; | ||||
|         result.count = std::size_t(count); | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| // Returns the index of the char that is different between lhs and rhs. | ||||
| template <typename CharT> | ||||
| constexpr std::size_t swar_find_difference(swar_int lhs, swar_int rhs) | ||||
| { | ||||
|     if (lhs == rhs) | ||||
|         return swar_length<CharT>; | ||||
|  | ||||
|     auto mask = lhs ^ rhs; | ||||
|  | ||||
| #if defined(__GNUC__) | ||||
|     auto bit_idx = __builtin_ctzll(mask); | ||||
| #elif defined(_MSC_VER) && defined(_WIN64) | ||||
|     unsigned long bit_idx; | ||||
|     _BitScanForward64(&bit_idx, mask); | ||||
| #elif defined(_MSC_VER) | ||||
|     unsigned long bit_idx = 0; | ||||
|     if (!_BitScanForward(&bit_idx, static_cast<std::uint32_t>(mask)) | ||||
|         && _BitScanForward(&bit_idx, mask >> 32)) | ||||
|         bit_idx += 32; | ||||
| #else | ||||
| #    error "unsupported compiler; please file an issue" | ||||
| #endif | ||||
|  | ||||
|     return std::size_t(bit_idx) / char_bit_size<CharT>; | ||||
| } | ||||
|  | ||||
| // Returns true if v has a char less than N. | ||||
| template <typename CharT, CharT N> | ||||
| constexpr bool swar_has_char_less(swar_int v) | ||||
| { | ||||
|     // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord | ||||
|  | ||||
|     constexpr auto offset      = swar_fill(CharT(N)); | ||||
|     auto           zero_or_msb = v - offset; | ||||
|  | ||||
|     constexpr auto msb_mask = swar_fill(CharT(1 << (char_bit_size<CharT> - 1))); | ||||
|     auto           not_msb  = ~v & msb_mask; | ||||
|  | ||||
|     return zero_or_msb & not_msb; | ||||
| } | ||||
|  | ||||
| // Returns true if v has a zero char. | ||||
| template <typename CharT> | ||||
| constexpr bool swar_has_zero(swar_int v) | ||||
| { | ||||
|     return swar_has_char_less<CharT, 1>(v); | ||||
| } | ||||
|  | ||||
| // Returns true if v contains the specified char. | ||||
| template <typename CharT, CharT C> | ||||
| constexpr bool swar_has_char(swar_int v) | ||||
| { | ||||
|     if constexpr (C == 0) | ||||
|     { | ||||
|         return swar_has_zero<CharT>(v); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         constexpr auto mask = swar_fill(C); | ||||
|         return swar_has_zero<CharT>(v ^ mask); | ||||
|     } | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| struct _swar_base | ||||
| {}; | ||||
| template <typename Reader> | ||||
| constexpr auto is_swar_reader = std::is_base_of_v<_swar_base, Reader>; | ||||
|  | ||||
| template <typename Derived> | ||||
| class swar_reader_base : _swar_base | ||||
| { | ||||
| public: | ||||
|     swar_int peek_swar() const | ||||
|     { | ||||
|         auto ptr = static_cast<const Derived&>(*this).position(); | ||||
|  | ||||
|         swar_int result; | ||||
| #if LEXY_IS_LITTLE_ENDIAN | ||||
|         std::memcpy(&result, ptr, sizeof(swar_int)); | ||||
| #else | ||||
|         using char_type = typename Derived::encoding::char_type; | ||||
|         auto dst        = reinterpret_cast<char*>(&result); | ||||
|         auto length     = sizeof(swar_int) / sizeof(char_type); | ||||
|         for (auto i = 0u; i != length; ++i) | ||||
|         { | ||||
|             std::memcpy(dst + i, ptr + length - i - 1, sizeof(char_type)); | ||||
|         } | ||||
| #endif | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     void bump_swar() | ||||
|     { | ||||
|         auto ptr = static_cast<Derived&>(*this).position(); | ||||
|         ptr += swar_length<typename Derived::encoding::char_type>; | ||||
|         static_cast<Derived&>(*this).reset({ptr}); | ||||
|     } | ||||
|     void bump_swar(std::size_t char_count) | ||||
|     { | ||||
|         auto ptr = static_cast<Derived&>(*this).position(); | ||||
|         ptr += char_count; | ||||
|         static_cast<Derived&>(*this).reset({ptr}); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| constexpr std::size_t round_size_for_swar(std::size_t size_in_bytes) | ||||
| { | ||||
|     // We round up to the next multiple. | ||||
|     if (auto remainder = size_in_bytes % sizeof(swar_int); remainder > 0) | ||||
|         size_in_bytes += sizeof(swar_int) - remainder; | ||||
|     // Then add one extra space of padding on top. | ||||
|     size_in_bytes += sizeof(swar_int); | ||||
|     return size_in_bytes; | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_SWAR_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										119
									
								
								dep/lexy/include/lexy/_detail/tuple.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								dep/lexy/include/lexy/_detail/tuple.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_TUPLE_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_TUPLE_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/config.hpp> | ||||
| #include <lexy/_detail/integer_sequence.hpp> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <std::size_t Idx, typename T> | ||||
| struct _tuple_holder | ||||
| { | ||||
| #if !defined(__GNUC__) || defined(__clang__) | ||||
|     // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105795 | ||||
|     LEXY_EMPTY_MEMBER | ||||
| #endif | ||||
|     T value; | ||||
| }; | ||||
|  | ||||
| template <std::size_t Idx, typename... T> | ||||
| struct _nth_type; | ||||
| template <std::size_t Idx, typename H, typename... T> | ||||
| struct _nth_type<Idx, H, T...> | ||||
| { | ||||
|     using type = typename _nth_type<Idx - 1, T...>::type; | ||||
| }; | ||||
| template <typename H, typename... T> | ||||
| struct _nth_type<0, H, T...> | ||||
| { | ||||
|     using type = H; | ||||
| }; | ||||
|  | ||||
| template <typename T> | ||||
| struct _tuple_get_type | ||||
| { | ||||
|     using type = T&; | ||||
| }; | ||||
| template <typename T> | ||||
| struct _tuple_get_type<T&&> | ||||
| { | ||||
|     using type = T&&; | ||||
| }; | ||||
|  | ||||
| template <typename Indices, typename... T> | ||||
| class _tuple; | ||||
| template <std::size_t... Idx, typename... T> | ||||
| class _tuple<index_sequence<Idx...>, T...> : public _tuple_holder<Idx, T>... | ||||
| { | ||||
| public: | ||||
|     constexpr _tuple() = default; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr _tuple(Args&&... args) : _tuple_holder<Idx, T>{LEXY_FWD(args)}... | ||||
|     {} | ||||
| }; | ||||
|  | ||||
| template <typename... T> | ||||
| struct tuple : _tuple<index_sequence_for<T...>, T...> | ||||
| { | ||||
|     constexpr tuple() = default; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr explicit tuple(Args&&... args) | ||||
|     : _tuple<index_sequence_for<T...>, T...>(LEXY_FWD(args)...) | ||||
|     {} | ||||
|  | ||||
|     template <std::size_t N> | ||||
|     using element_type = typename _nth_type<N, T...>::type; | ||||
|  | ||||
|     template <std::size_t N> | ||||
|     constexpr decltype(auto) get() noexcept | ||||
|     { | ||||
|         // NOLINTNEXTLINE: this is fine. | ||||
|         auto&& holder = static_cast<_tuple_holder<N, element_type<N>>&>(*this); | ||||
|         // NOLINTNEXTLINE | ||||
|         return static_cast<typename _tuple_get_type<element_type<N>>::type>(holder.value); | ||||
|     } | ||||
|     template <std::size_t N> | ||||
|     constexpr decltype(auto) get() const noexcept | ||||
|     { | ||||
|         // NOLINTNEXTLINE: this is fine. | ||||
|         auto&& holder = static_cast<const _tuple_holder<N, element_type<N>>&>(*this); | ||||
|         // NOLINTNEXTLINE | ||||
|         return static_cast<typename _tuple_get_type<const element_type<N>>::type>(holder.value); | ||||
|     } | ||||
|  | ||||
|     static constexpr auto index_sequence() | ||||
|     { | ||||
|         return index_sequence_for<T...>{}; | ||||
|     } | ||||
| }; | ||||
| template <> | ||||
| struct tuple<> | ||||
| { | ||||
|     constexpr tuple() = default; | ||||
|  | ||||
|     static constexpr auto index_sequence() | ||||
|     { | ||||
|         return index_sequence_for<>{}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename... Args> | ||||
| constexpr auto make_tuple(Args&&... args) | ||||
| { | ||||
|     return tuple<std::decay_t<Args>...>(LEXY_FWD(args)...); | ||||
| } | ||||
|  | ||||
| template <typename... Args> | ||||
| constexpr auto forward_as_tuple(Args&&... args) | ||||
| { | ||||
|     return tuple<Args&&...>(LEXY_FWD(args)...); | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_TUPLE_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										130
									
								
								dep/lexy/include/lexy/_detail/type_name.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								dep/lexy/include/lexy/_detail/type_name.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DETAIL_TYPE_NAME_HPP_INCLUDED | ||||
| #define LEXY_DETAIL_TYPE_NAME_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/config.hpp> | ||||
| #include <lexy/_detail/detect.hpp> | ||||
| #include <lexy/_detail/integer_sequence.hpp> | ||||
| #include <lexy/_detail/string_view.hpp> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename T> | ||||
| using _detect_name_f = std::enable_if_t<std::is_convertible_v<decltype(T::name()), string_view>>; | ||||
| template <typename T> | ||||
| using _detect_name_v = decltype(T::name); | ||||
|  | ||||
| template <typename T> | ||||
| constexpr auto _full_type_name() | ||||
| { | ||||
| #if defined(__clang__) | ||||
| #    define LEXY_HAS_AUTOMATIC_TYPE_NAME 1 | ||||
| #    define LEXY_HAS_CONSTEXPR_AUTOMATIC_TYPE_NAME 1 | ||||
|  | ||||
|     constexpr auto prefix = string_view("auto lexy::_detail::_full_type_name() [T = "); | ||||
|     constexpr auto suffix = string_view("]"); | ||||
|  | ||||
|     auto function = string_view(__PRETTY_FUNCTION__); | ||||
|     function.remove_prefix(prefix.length()); | ||||
|     function.remove_suffix(suffix.length()); | ||||
|     function.try_remove_prefix("(anonymous namespace)::"); | ||||
|     return function; | ||||
|  | ||||
| #elif defined(__GNUC__) | ||||
| #    define LEXY_HAS_AUTOMATIC_TYPE_NAME 1 | ||||
| #    if __GNUC__ > 8 | ||||
| #        define LEXY_HAS_CONSTEXPR_AUTOMATIC_TYPE_NAME 1 | ||||
| #    else | ||||
| #        define LEXY_HAS_CONSTEXPR_AUTOMATIC_TYPE_NAME 0 | ||||
| #    endif | ||||
|  | ||||
|     constexpr auto prefix | ||||
|         = string_view("constexpr auto lexy::_detail::_full_type_name() [with T = "); | ||||
|     constexpr auto suffix = string_view("]"); | ||||
|  | ||||
|     auto function = string_view(__PRETTY_FUNCTION__); | ||||
|     function.remove_prefix(prefix.length()); | ||||
|     function.remove_suffix(suffix.length()); | ||||
|     function.try_remove_prefix("{anonymous}::"); | ||||
|     return function; | ||||
|  | ||||
| #elif defined(_MSC_VER) | ||||
| #    define LEXY_HAS_AUTOMATIC_TYPE_NAME 1 | ||||
| #    define LEXY_HAS_CONSTEXPR_AUTOMATIC_TYPE_NAME 1 | ||||
|  | ||||
|     constexpr auto prefix = string_view("auto __cdecl lexy::_detail::_full_type_name<"); | ||||
|     constexpr auto suffix = string_view(">(void)"); | ||||
|  | ||||
|     auto function = string_view(__FUNCSIG__); | ||||
|     function.remove_prefix(prefix.length()); | ||||
|     function.remove_suffix(suffix.length()); | ||||
|     function.try_remove_prefix("struct ") || function.try_remove_prefix("class "); | ||||
|     function.try_remove_prefix("`anonymous-namespace'::"); | ||||
|     return function; | ||||
|  | ||||
| #else | ||||
| #    define LEXY_HAS_AUTOMATIC_TYPE_NAME 0 | ||||
| #    define LEXY_HAS_CONSTEXPR_AUTOMATIC_TYPE_NAME 0 | ||||
|  | ||||
|     return string_view("unknown-type"); | ||||
|  | ||||
| #endif | ||||
| } | ||||
|  | ||||
| template <typename T, int NsCount> | ||||
| constexpr string_view _type_name() | ||||
| { | ||||
|     auto name = _full_type_name<T>(); | ||||
|     if (name.find('<') != string_view::npos && NsCount != 0) | ||||
|         return name; | ||||
|  | ||||
|     for (auto namespace_count = NsCount; namespace_count > 0; --namespace_count) | ||||
|     { | ||||
|         auto pos = name.find("::"); | ||||
|         if (pos == string_view::npos) | ||||
|             break; | ||||
|         name.remove_prefix(pos + 2); | ||||
|     } | ||||
|     return name; | ||||
| } | ||||
|  | ||||
| template <typename T, int NsCount = 1> | ||||
| constexpr const char* type_name() | ||||
| { | ||||
|     if constexpr (_detail::is_detected<_detect_name_f, T>) | ||||
|         return T::name(); | ||||
|     else if constexpr (_detail::is_detected<_detect_name_v, T>) | ||||
|         return T::name; | ||||
|     else if constexpr (LEXY_HAS_CONSTEXPR_AUTOMATIC_TYPE_NAME) | ||||
|         return make_cstr<_type_name<T, NsCount>>; | ||||
|     else | ||||
|         return "unknown-type"; | ||||
| } | ||||
|  | ||||
| template <typename T, int NsCount> | ||||
| inline constexpr const char* _type_id_holder = type_name<T, NsCount>(); | ||||
|  | ||||
| // Returns a unique address for each type. | ||||
| // For implementation reasons, it also doubles as the pointer to the name. | ||||
| template <typename T, int NsCount = 1> | ||||
| constexpr const char* const* type_id() | ||||
| { | ||||
|     if constexpr (_detail::is_detected<_detect_name_v, T> // | ||||
|                   && !_detail::is_detected<_detect_name_f, T>) | ||||
|     { | ||||
|         // We can use the address of the static constexpr directly. | ||||
|         return &T::name; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // We instantiate a variable template with a function unique by type. | ||||
|         // As the variable is inline, there should be a single address only. | ||||
|         return &_type_id_holder<T, NsCount>; | ||||
|     } | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_DETAIL_TYPE_NAME_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										83
									
								
								dep/lexy/include/lexy/_detail/unicode_database.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								dep/lexy/include/lexy/_detail/unicode_database.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| // AUTOGENERATED FILE --- DO NOT EDIT! | ||||
| // Generated by `support/generate-unicode-db.py`. | ||||
|  | ||||
| #define LEXY_UNICODE_DATABASE_VERSION "15.0.0" | ||||
|  | ||||
| namespace lexy::_unicode_db | ||||
| { | ||||
| constexpr const char* block_starts = "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\021\025\026\027\030\031\032\033\034\035\036\037 !\"#$%&'(!)*+,-./0'\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\0211\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\0212\021\021\0213\021456789\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021:;;;;;;;;<<<<<<<<<<<<<<<<<<<<<<<<<\021=>?@ABCDEFGH\021IJKLMNOPQRSTUVWXYZ[\\]^_`a\021\021\021bcdeeeeeeeeef\021\021\021\021geeeeeeeeeeeeeee\021\021heeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\021\021ijeekl\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021m\021\021\021\021noeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep\021qreeeeeeeeeseeeeeeeeeeeeeeeeeetuvwxyz{|''}eeee~\177\200\201e\202ee\203\204\205ee\206\207\210e\211\212\213\214''\215\216\217'\220\221eeee\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\222\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\223\224\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\225\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\226eeeeeeeeeeee\021\021\227eeeee\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\230\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\231eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" | ||||
|     "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" | ||||
|     "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" | ||||
|     "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\232\233eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\234" | ||||
|     "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\234"; | ||||
| constexpr const char* blocks = "\000\000\000\000\000\000\000\000\000\001\001\001\001\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\003\003\003\004\003\003\003\005\006\003\007\003\010\003\003\011\011\011\011\011\011\011\011\011\011\003\003\007\007\007\003\003\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\005\003\006\013\014\013\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\005\007\006\007\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\003\004\004\004\004\016\003\013\016\017\020\007\021\016\013\016\007\022\022\013\023\003\024\013\022\017\025\022\022\022\003\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\007\012\012\012\012\012\012\012\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\007\015\015\015\015\015\015\015\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\027\015\026\015\026\015\026\015\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\030\026\015\026\015\026\015\031\015\032\026\015\026\015\033\026\015\034\034\026\015\015\035\036\037\026\015\034 \015!\"\026\015\015\015!#\015$\026\015\026\015\026\015%\026\015%\015\015\026\015%\026\015&&\026\015\026\015'\026\015\015(\026\015\015\015(((()*\015)*\015)*\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\015)*\015\026\015+,\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015-\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\015\015\015\015\015\015.\026\015/0\015\015\026\015123\026\015\026\015\026\015\026\015\026\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015(\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015444444444555555544\013\013\013\013555555555555\013\013\013\013\013\013\013\013\013\013\013\013\013\01344444\013\013\013\013\013\013\0135\0135\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\0136666666666666666666666666666666666666666666666666666666666666666666667666666666666666666666666666666666666666666\026\015\026\0155\013\026\015889\015\015\015\003:8888\013\013;\024<<<8=8>>\015\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\0128\012\012\012\012\012\012\012\012\012\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015?\015\015\015\015\015\015\015\015\015\015\015\015@AB\027\027\027CD\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015EF\015\015GH\007\026\015I\026\015\015---" | ||||
|     "JJJJJJJJJJJJJJJJ\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\01666666KK\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015L\026\015\026\015\026\015\026\015\026\015\026\015\026\015\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\0158MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM885\003\003\003\003\003\003\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\003\01088\016\016\00486666666666666666666666666666666NNNNNNNNNNNNNN\010N\003NN\003NN\003N88888888(((((((((((((((((((((((((((8888((((\003\00388888888888\021\021\021\021\021\021\007\007\007\003\003\004\003\003\016\016NNNNNNNNNNN\003\021\003\003\003((((((((((((((((((((((((((((((((5((((((((((NNNNNNNNNNNNN6NNNNNNN\011\011\011\011\011\011\011\011\011\011\003\003\003\003((N(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\003(NNNNNNN\021\01666NNNN55NN\016666N((\011\011\011\011\011\011\011\011\011\011(((\016\016(\003\003\003\003\003\003\003\003\003\003\003\003\003\0038\021(N((((((((((((((((((((((((((((((NNNNNNNNNNNNNNNN6666666666688(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((NNNNNNNNNNN(88888888888888\011\011\011\011\011\011\011\011\011\011(((((((((((((((((((((((((((((((((66666666655\016\003\003\0035886\004\004" | ||||
|     "((((((((((((((((((((((NN665NNNNNNNNN5NNN5NNNN688\003\003\003\003\003\003\003\003\003\003\003\003\003\003\0038(((((((((((((((((((((((((66688\0038(((((((((((88888((((((((((((((((((((((((\013((((((8\021\02188888866666666(((((((((((((((((((((((((((((((((((((((((56666666666NNNNNNNNNNNN66\021NNNNNNN666666NNNNNNNNNNNNNNNNNNNO((((((((((((((((((((((((((((((((((((((((((((((((((((((NO6(OOONNNNNNNNOOOO6OO(6666NNN((((((((((NN\003\003\011\011\011\011\011\011\011\011\011\011\0035(((((((((((((((NOO8((((((((88((88((((((((((((((((((((((8(((((((8(888((((886(OOONNNN88OO88OO6(88888888O8888((8(((NN88\011\011\011\011\011\011\011\011\011\011((\004\004\022\022\022\022\022\022\016\004(\003688NNO8((((((8888((88((((((((((((((((((((((8(((((((8((8((8((8868OOONN8888NN88NN6888N8888888((((8(8888888\011\011\011\011\011\011\011\011\011\011NN(((N\0038888888888NNO8(((((((((8(((8((((((((((((((((((((((8(((((((8((8(((((886(OOONNNNN8NNO8OO688(888888888888888((NN88\011\011\011\011\011\011\011\011\011\011\003\0048888888(NNN6668NOO8((((((((88((88((((((((((((((((((((((8(((((((8((8(((((886(ONONNNN88OO88OO688888886NO8888((8(((NN88\011\011\011\011\011\011\011\011\011\011\016(\022\022\022\022\022\0228888888888N(8((((((888(((8((((888((8(8((888((888(((888((((((((((((8888OONOO888OOO8OOO688(888888O88888888888888\011\011\011\011\011\011\011\011\011\011\022\022\022\016\016\016\016\016\016\004\01688888" | ||||
|     "NOOON((((((((8(((8(((((((((((((((((((((((8((((((((((((((((886(NNNOOOO8NNN8NNN68888888NN8(((88(88((NN88\011\011\011\011\011\011\011\011\011\0118888888\003\022\022\022\022\022\022\022\016(NOO\003((((((((8(((8(((((((((((((((((((((((8((((((((((8(((((886(ONOOOOO8NOO8OON68888888OO888888((8((NN88\011\011\011\011\011\011\011\011\011\0118((O888888888888NNOO(((((((((8(((8(((((((((((((((((((((((((((((((((((((((((66(OOONNNN8OOO8OOO6(\0168888(((O\022\022\022\022\022\022\022(((NN88\011\011\011\011\011\011\011\011\011\011\022\022\022\022\022\022\022\022\022\016((((((8NOO8((((((((((((((((((888((((((((((((((((((((((((8(((((((((8(88(((((((88868888OOONNN8N8OOOOOOOO888888\011\011\011\011\011\011\011\011\011\01188OO\003888888888888((((((((((((((((((((((((((((((((((((((((((((((((N(PNNNNNNN8888\004((((((5666666N6\003\011\011\011\011\011\011\011\011\011\011\003\0038888888888888888888888888888888888888((8(8(((((8((((((((((((((((((((((((8(8((((((((((N(PNNNNNN6NN(88(((((85866666N68\011\011\011\011\011\011\011\011\011\01188((((88888888888888888888888888888888(\016\016\016\003\003\003\003\003\003\003\003\003\003\003\003\003\003\003\016\003\016\016\01666\016\016\016\016\016\016\011\011\011\011\011\011\011\011\011\011\022\022\022\022\022\022\022\022\022\022\0166\0166\0166\005\006\005\006QQ((((((((8((((((((((((((((((((((((((((((((((((8888NNNNNNNNNNNNNNONNNN6\00366(((((NNNNNNNNNNN8NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN8\016\016\016\016\016\016\016\0166\016\016\016\016\016\0168\016\016\003\003\003\003\003\016\016\016\016\003\0038888888888888888888888888888888888888" | ||||
|     "(((((((((((((((((((((((((((((((((((((((((((OONNNNONNNNN6O66OONN(\011\011\011\011\011\011\011\011\011\011\003\003\003\003\003\003((((((OONN((((NNN(OOO((OOOOOOO(((NNNN(((((((((((((NOONNOOOOOON(O\011\011\011\011\011\011\011\011\011\011OOON\016\016RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR8R88888R88\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\0034\015\015\015(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((8((((88(((((((8(8((((88(((((((((((((((((((((((((((((((((((((((((8((((88(((((((((((((((((((((((((((((((((8((((88(((((((8(8((((88(((((((((((((((8(((((((((((((((((((((((((((((((((((((((((((((((((((((((((8((((88(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88666\003\003\003\003\003\003\003\003\003SSSSSSSSS\022\022\022\022\022\022\022\022\022\022\022888((((((((((((((((\016\016\016\016\016\016\016\016\016\016888888\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\02788TTTTTT88" | ||||
|     "\010((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\016\003(((((((((((((((((\002((((((((((((((((((((((((((\005\006888(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\003\003\003UUU((((((((8888888((((((((((((((((((NN6Q888888888(((((((((((((((((((NNQ\003\003888888888((((((((((((((((((NN888888888888(((((((((((((8(((8NN888888888888((((((((((((((((((((((((((((((((((((((((((((((((((((66ONNNNNNNOOOOOOOONOO66666666666\003\003\0035\003\003\003\004(688\011\011\011\011\011\011\011\011\011\011888888\022\022\022\022\022\022\022\022\022\022888888\003\003\003\003\003\003\010\003\003\003\003666\0216\011\011\011\011\011\011\011\011\011\011888888(((((((((((((((((((((((((((((((((((5(((((((((((((((((((((((((((((((((((((((((((((((((((((8888888(((((VV((((((((((((((((((((((((((((((((((N(88888((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((8888888888" | ||||
|     "(((((((((((((((((((((((((((((((8NNNOOOONNOOO8888OONOOOOOO6668888\016888\003\003\011\011\011\011\011\011\011\011\011\011((((((((((((((((((((((((((((((88(((((88888888888((((((((((((((((((((((((((((((((((((((((((((8888((((((((((((((((((((((((((888888\011\011\011\011\011\011\011\011\011\011S888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016(((((((((((((((((((((((NNOON88\003\003(((((((((((((((((((((((((((((((((((((((((((((((((((((ONONNNNNNN86ONOONNNNNNNNOOOOOONN66666666886\011\011\011\011\011\011\011\011\011\011888888\011\011\011\011\011\011\011\011\011\011888888\003\003\003\003\003\003\0035\003\003\003\003\003\0038866666666666666KNN66666666666NNN8888888888888888888888888888888888888888888888888NNNNO(((((((((((((((((((((((((((((((((((((((((((((((6ONNNNNONOOOOONOQ((((((((888\011\011\011\011\011\011\011\011\011\011\003\003\003\003\003\003\003\016\016\016\016\016\016\016\016\016\016666666666\016\016\016\016\016\016\016\016\016\003\0038NNO((((((((((((((((((((((((((((((ONNNNOONNQ6NN((\011\011\011\011\011\011\011\011\011\011((((((((((((((((((((((((((((((((((((((((((((6ONNOOONONNNQQ88888888\003\003\003\003((((((((((((((((((((((((((((((((((((OOOOOOOONNNNNNNNOON6888\003\003\003\003\003\011\011\011\011\011\011\011\011\011\011888(((\011\011\011\011\011\011\011\011\011\011((((((((((((((((((((((((((((((555555\003\003WXYZZ[\\]^8888888___________________________________________88___\003\003\003\003\003\003\003\00388888888666\0036666666666666Q6666666((((6((((((6((Q66(88888" | ||||
|     "\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015444444444444444444444444444444444444444444444444444444444444444\015\015\015\015\015\015\015\015\015\015\015\015\0154\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\0154444444444444444444444444444444444444666666666666666666666666666666666666666NNNNNNNNNNNNNN66666666666\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\015\015\015\015\015`\015\015a\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\015\015\015\015\015\015\015\015bbbbbbbb\015\015\015\015\015\01588bbbbbb88\015\015\015\015\015\015\015\015bbbbbbbb\015\015\015\015\015\015\015\015bbbbbbbb\015\015\015\015\015\01588bbbbbb88\015\015\015\015\015\015\015\0158b8b8b8b\015\015\015\015\015\015\015\015bbbbbbbb\015\015\015\015\015\015\015\015\015\015\015\015\015\01588\015\015\015\015\015\015\015\015cccccccc\015\015\015\015\015\015\015\015cccccccc\015\015\015\015\015\015\015\015cccccccc\015\015\015\015\0158\015\015bbdde\013f\013\013\013\015\015\0158\015\015gggge\013\013\013\015\015\015\01588\015\015bbhh8\013\013\013\015\015\015\015\015\015\015\015bbiiI\013\013\01388\015\015\0158\015\015jjkke\013\0138\002\002\002\002\002\002\002\002\002\002\002\021ll\021\021\010\010\010\010\010\010\003\003\020\025\005\020\020\025\005\020\003\003\003\003\003\003\003\003mn\021\021\021\021\021\002\003\003\003\003\003\003\003\003\003\020\025\003\003\003\003\014\014\003\003\003\007\005\006\003\003\003\003\003\003\003\003\003\003\003\007\003\014\003\003\003\003\003\003\003\003\003\003\002\021\021\021\021\0218\021\021\021\021\021\021\021\021\021\021\022488\022\022\022\022\022\022\007\007\007\005\0064\022\022\022\022\022\022\022\022\022\022\007\007\007\005\00684444444444444888\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\004\0048888888888888886666666666666KKKK6KKK666666666666888888888888888" | ||||
|     "\016\016\027\016\016\016\016\027\016\016\015\027\027\027\015\015\027\027\027\015\016\027\016\016o\027\027\027\027\027\016\016\016\016\016\016\027\016p\016\027\016qr\027\027s\015\027\027t\027\015((((\015\016\016\015\015\027\027\007\007\007\007\007\027\015\015\015\015\016\007\016\016\015\016\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022uuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvUUU\026\015UUUU\022\016\0168888\007\007\007\007\007\016\016\016\016\016\007\007\016\016\016\016\007\016\016\007\016\016\007\016\016\016\016\016\016\016\007\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\007\007\016\016\007\016\007\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\016\016\016\016\016\016\016\016\005\006\005\006\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\007\007\016\016\016\016\016\016\016\005\006\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\007\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\007\007\007\007\007\007\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168888888888888888888888888\016\016\016\016\016\016\016\016\016\016\016888888888888888888888\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016wwwwwwwwwwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxxxxxxx\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022" | ||||
|     "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\007\016\016\016\016\016\016\016\016\016\007\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\007\007\007\007\007\007\007\007\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\007\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\005\006\005\006\005\006\005\006\005\006\005\006\005\006\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\007\007\007\007\007\005\006\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\005\006\005\006\005\006\005\006\005\006\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016" | ||||
|     "\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\005\006\005\006\005\006\005\006\005\006\005\006\005\006\005\006\005\006\005\006\005\006\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\005\006\005\006\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\005\006\007\007\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\016\016\007\007\007\007\007\007\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\01688\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\026\015yz{\015\015\026\015\026\015\026\015|}~\177\015\026\015\015\026\015\015\015\015\015\01544\200\200\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\015\016\016\016\016\016\016\026\015\026\015666\026\01588888\003\003\003\003\022\003\003\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\0158\01588888\01588((((((((((((((((((((((((((((((((((((((((((((((((((((((((88888885\003888888888888886(((((((((((((((((((((((888888888(((((((8(((((((8(((((((8(((((((8(((((((8(((((((8(((((((8(((((((8NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN" | ||||
|     "\003\003\020\025\020\025\003\003\003\020\025\003\020\025\003\003\003\003\003\003\003\003\003\010\003\003\010\003\020\025\003\003\020\025\005\006\005\006\005\006\005\006\003\003\003\003\003\201\003\003\003\003\003\003\003\003\003\003\010\010\003\003\003\003\010\003\005\003\003\003\003\003\003\003\003\003\003\003\003\003\016\016\003\003\003\005\006\005\006\005\006\005\006\0108888888888888888888888888888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016888888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\01688888888888888888888888888\016\016\016\016\016\016\016\016\016\016\016\0168888\002\003\003\003\0165(U\005\006\005\006\005\006\005\006\005\006\016\016\005\006\005\006\005\006\005\006\010\005\006\006\016UUUUUUUUU6666QQ\01055555\016\016UUU5(\003\016\0168((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((8866\013\01355(\010((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\003555(88888(((((((((((((((((((((((((((((((((((((((((((8((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((8\016\016\022\022\022\022\016\016\016\016\016\016\016\016\016\016((((((((((((((((((((((((((((((((\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016888888888888((((((((((((((((" | ||||
|     "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168\022\022\022\022\022\022\022\022\022\022\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\022\022\022\022\022\022\022\022\016\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\022\022\022\022\022\022\022\022\022\022\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016(((((((((((((((((((((5(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016888888888((((((((((((((((((((((((((((((((((((((((555555\003\003" | ||||
|     "((((((((((((5\003\003\003((((((((((((((((\011\011\011\011\011\011\011\011\011\011((88888888888888888888\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015(6KKK\003NNNNNNNN66\0035\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\01544NN((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((UUUUUUUUUU66\003\003\003\003\003\00388888888\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013555555555\013\013\026\015\026\015\026\015\026\015\026\015\026\015\026\015\015\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\0154\015\015\015\015\015\015\015\015\026\015\026\015\202\026\015\026\015\026\015\026\015\026\0155\013\013\026\015\203\015(\026\015\026\015\015\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\204\205\206\207\204\015\210\211\212\213\026\015\026\015\026\015\026\015\026\015\026\015\026\015\026\015\214\215\216\026\015\026\01588888\026\0158\0158\015\026\015\026\015888888888888888888888888444\026\015(44\015(((((((N(((6((((N(((((((((((((((((((((((OONNO\016\016\016\0166888\022\022\022\022\022\022\016\016\004\016888888((((((((((((((((((((((((((((((((((((((((((((((((((((\003\003\003\00388888888OO((((((((((((((((((((((((((((((((((((((((((((((((((OOOOOOOOOOOOOOOO6N88888888\003\003\011\011\011\011\011\011\011\011\011\011888888666666666666666666((((((\003\003\003(\003((N\011\011\011\011\011\011\011\011\011\011((((((((((((((((((((((((((((NNNNN666\003\003(((((((((((((((((((((((NNNNNNNNNNNOQ88888888888\003(((((((((((((((((((((((((((((888NNNO(((((((((((((((((((((((((((((((((((((((((((((((6OONNNNOONNOOQ\003\003\003\003\003\003\003\003\003\003\003\003\00385\011\011\011\011\011\011\011\011\011\0118888\003\003(((((N5(((((((((\011\011\011\011\011\011\011\011\011\011(((((8" | ||||
|     "(((((((((((((((((((((((((((((((((((((((((NNNNNNOONNOONN888888888(((N((((((((NO88\011\011\011\011\011\011\011\011\011\01188\003\003\003\003((((((((((((((((5((((((\016\016\016(ONO((((((((((((((((((((((((((((((((((((((((((((((((((N(NNN((NN(((((N6(6(888888888888888888888888((5\003\003(((((((((((ONNOO\003\003(55O68888888888((((((88((((((88((((((888888888(((((((8(((((((8\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\0134444\015\015\015\015\015\015\015\015\0154\013\0138888\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217\217(((((((((((((((((((((((((((((((((((OONOONOO\003Q688\011\011\011\011\011\011\011\011\011\011888888((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((888888888888(((((((((((((((((((((((8888(((((((((((((((((((((((((((((((((((((((((((((((((8888\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220\220" | ||||
|     "\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88888888888888888888888888888888888888\015\015\015\015\015\015\015888888888888\015\015\015\015\01588888(N((((((((((\007(((((((((((((8(((((8(8((8((8((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\013\0138888888888888888(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\222\222\222\222\222\222((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" | ||||
|     "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\006\005\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88((((((((((((((((((((((((((((((((((((((((((((((((((((((8888888\01688888888888888888888888888888888((((((((((\222\222\004\016\016\0166666666666666666\003\003\003\003\003\003\003\005\006\0038888886666666666666666\003\010\010\014\014\005\006\005\006\005\006\005\006\005\006\005\006\005\006\005\006\003\003\005\006\003\003\003\003\014\014\014\003\003\0038\003\003\003\003\010\005\006\005\006\005\006\003\003\003\007\010\007\007\0078\003\004\003\0038888\222(\222(\2228\222(\222(\222(\222(\222((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88\0218\003\003\003\004\003\003\003\005\006\003\007\003\010\003\003\011\011\011\011\011\011\011\011\011\011\003\003\007\007\007\003\003\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\005\003\006\013\014\013\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\005\007\006\007\005\006\003\005\006\003\003((((((((((5(((((((((((((((((((((((((((((((((((((((((((((\223\223(((((((((((((((((((((((((((((((888((((((88((((((88((((((88(((888\004\004\007\013\016\004\0048\016\007\007\007\007\016\0168888888888\021\021\021\016\01688((((((((((((8((((((((((((((((((((((((((8(((((((((((((((((((8((8(((((((((((((((88((((((((((((((8888888888888888888888888888888888(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88888" | ||||
|     "\003\003\0038888\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022888\016\016\016\016\016\016\016\016\016UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU\022\022\022\022\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\022\022\016\016\0168\016\016\016\016\016\016\016\016\016\016\016\016\016888\01688888888888888888888888888888888888888888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\01668888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888(((((((((((((((((((((((((((((888(((((((((((((((((((((((((((((((((((((((((((((((((8888888888888886\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\0228888((((((((((((((((((((((((((((((((\022\022\022\022888888888((((((((((((((((((((U((((((((U88888((((((((((((((((((((((((((((((((((((((NNNNN88888((((((((((((((((((((((((((((((8\003((((((((((((((((((((((((((((((((((((8888((((((((\003UUUUU888888888888888888888888888888888888888888\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88\011\011\011\011\011\011\011\011\011\011888888\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\224\2248888\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\0158888" | ||||
|     "((((((((((((((((((((((((((((((((((((((((88888888((((((((((((((((((((((((((((((((((((((((((((((((((((88888888888\003\225\225\225\225\225\225\225\225\225\225\2258\225\225\225\225\225\225\225\225\225\225\225\225\225\225\2258\225\225\225\225\225\225\2258\225\2258\015\015\015\015\015\015\015\015\015\015\0158\015\015\015\015\015\015\015\015\015\015\015\015\015\015\0158\015\015\015\015\015\015\0158\015\0158888888888888888888888888888888888888888888888888888888888888888888(((((((((((((((((((((((((((((((((((((((((((((((((((((((888888888((((((((((((((((((((((8888888888((((((((88888888888888888888888845544484444444444444444444444444444444444444444448444444444888888888888888888888888888888888888888888888888888888888888888888888((((((88(8((((((((((((((((((((((((((((((((((((((((((((8((888(88(((((((((((((((((((((((8\003\022\022\022\022\022\022\022\022(((((((((((((((((((((((\016\016\022\022\022\022\022\022\022(((((((((((((((((((((((((((((((88888888\022\022\022\022\022\022\022\022\022888888888888888888888888888888888888888888888888(((((((((((((((((((8((88888\022\022\022\022\022((((((((((((((((((((((\022\022\022\022\022\022888\003((((((((((((((((((((((((((88888\0038888888888888888888888888888888888888888888888888888888888888888((((((((((((((((((((((((((((((((((((((((((((((((((((((((8888\022\022((\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\02288\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022" | ||||
|     "(NNN8NN88888NNNN((((8(((8(((((((((((((((((((((((((((((8866688886\022\022\022\022\022\022\022\022\0228888888\003\003\003\003\003\003\003\003\0038888888(((((((((((((((((((((((((((((\022\022\003(((((((((((((((((((((((((((((\022\022\02288888888888888888888888888888888((((((((\016((((((((((((((((((((((((((((668888\022\022\022\022\022\003\003\003\003\003\003\003888888888((((((((((((((((((((((((((((((((((((((((((((((((((((((888\003\003\003\003\003\003\003((((((((((((((((((((((88\022\022\022\022\022\022\022\022(((((((((((((((((((88888\022\022\022\022\022\022\022\022((((((((((((((((((8888888\003\003\003\003888888888888\022\022\022\022\022\022\02288888888888888888888888888888888888888888888888888888888888888888888888888888888(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((8888888888888888888888888888888888888888888888888888888===================================================8888888888888\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\0158888888\022\022\022\022\022\022((((((((((((((((((((((((((((((((((((NNNN88888888\011\011\011\011\011\011\011\011\011\011888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888" | ||||
|     "888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\0228((((((((((((((((((((((((((((((((((((((((((8NN\01088((888888888888888888888888888888888888888888888888888888888888888888888888888666(((((((((((((((((((((((((((((\022\022\022\022\022\022\022\022\022\022(88888888((((((((((((((((((((((66666666666\022\022\022\022\003\003\003\003\0038888888888888888888888((((((((((((((((((6666\003\003\003\00388888888888888888888888888888888888888(((((((((((((((((((((\022\022\022\022\022\022\02288888888888888888888(((((((((((((((((((((((888888888ONO(((((((((((((((((((((((((((((((((((((((((((((((((((((NNNNNNNNNNNNNN6\003\003\003\003\003\003\0038888\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\011\011\011\011\011\011\011\011\011\0116((NN(8888888886NNO(((((((((((((((((((((((((((((((((((((((((((((OOONNNNOO66\003\003\021\003\003\003\003N8888888888\02188(((((((((((((((((((((((((8888888\011\011\011\011\011\011\011\011\011\011888888NNN((((((((((((((((((((((((((((((((((((NNNNNONNNNNN668\011\011\011\011\011\011\011\011\011\011\003\003\003\003(OO(88888888(((((((((((((((((((((((((((((((((((6\003\003(888888888NNO((((((((((((((((((((((((((((((((((((((((((((((((OOONNNNNNNNNOQ((((\003\003\003\0036666\003ON\011\011\011\011\011\011\011\011\011\011(\003(\003\003\0038\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\02288888888888" | ||||
|     "((((((((((((((((((8(((((((((((((((((((((((((OOONNNOONQ6N\003\003\003\003\003\003N((N88888888888888888888888888888888888888888888888888888888888888(((((((8(8((((8(((((((((((((((8((((((((((\003888888(((((((((((((((((((((((((((((((((((((((((((((((NOOONNNNNN6688888\011\011\011\011\011\011\011\011\011\011888888NNOO8((((((((88((88((((((((((((((((((((((8(((((((8((8(((((866(OONOOOO88OO88OOQ88(888888O88888(((((OO886666666888666668888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888(((((((((((((((((((((((((((((((((((((((((((((((((((((OOONNNNNNNNOO6NNO6((((\003\003\003\003\003\011\011\011\011\011\011\011\011\011\011\003\0038\0036(((888888888888888888888888888888((((((((((((((((((((((((((((((((((((((((((((((((OOONNNNNNONOOOONNO66((\003(88888888\011\011\011\011\011\011\011\011\011\0118888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888(((((((((((((((((((((((((((((((((((((((((((((((OOONNNN88OOOONNO66\003\003\003\003\003\003\003\003\003\003\003\003\003\003\003\003\003\003\003\003\003\003\003((((NN8888888888888888888888888888888888" | ||||
|     "((((((((((((((((((((((((((((((((((((((((((((((((OOONNNNNNNNOONO6N\003\003\003(88888888888\011\011\011\011\011\011\011\011\011\011888888\003\003\003\003\003\003\003\003\003\003\003\003\0038888888888888888888(((((((((((((((((((((((((((((((((((((((((((NONOONNNNNNQ6(\003888888\011\011\011\011\011\011\011\011\011\011888888888888888888888888888888888888888888888888888888(((((((((((((((((((((((((((88NNNOONNNNONNNN68888\011\011\011\011\011\011\011\011\011\011\022\022\003\003\003\016(((((((88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888((((((((((((((((((((((((((((((((((((((((((((OOONNNNNNNNNO66\0038888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\011\011\011\011\011\011\011\011\011\011\022\022\022\022\022\022\022\022\022888888888888((((((((88(88((((((((8((8((((((((((((((((((((((((OOOOOO8OO88NNQ6(O(O6\003\003\003888888888\011\011\011\011\011\011\011\011\011\0118888888888888888888888888888888888888888888888888888888888888888888888((((((((88(((((((((((((((((((((((((((((((((((((((OOONNNN88NNOOOO6(\003(O888888888888888888888888888" | ||||
|     "(NNNNNNNNNN((((((((((((((((((((((((((((((((((((((((66NNNNO(NNNN\003\003\003\003\003\003\003\003688888888(NNNNNNOONNN((((((((((((((((((((((((((((((((((((((((((((((NNNNNNNNNNNNNO66\003\003\003(\003\003\003\003\0038888888888888(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((8888888\003\003\003\003\003\003\003\003\003\003888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888(((((((((8(((((((((((((((((((((((((((((((((((((ONNNNNNN8NNNNNNO6(\003\003\003\003\0038888888888\011\011\011\011\011\011\011\011\011\011\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022888\003\003((((((((((((((((((((((((((((((88NNNNNNNNNNNNNNNNNNNNNN8ONNNNNNNONNONN8888888888888888888888888888888888888888888888888888888888888888888888888(((((((8((8((((((((((((((((((((((((((((((((((((((NNNNNN888N8NN8NNN6N66(N88888888\011\011\011\011\011\011\011\011\011\011888888((((((8((8((((((((((((((((((((((((((((((((OOOOO8NN8OONO6(8888888\011\011\011\011\011\011\011\011\011\01188888888888888888888888888888888888888888888888888888888888888888888888888888888888888" | ||||
|     "88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888(((((((((((((((((((NNOO\003\0038888888NN(O(((((((((((((8((((((((((((((((((((((((((((((((((OONNNNN888OONQ6\003\003\003\003\003\003\003\003\003\003\003\003\003\011\011\011\011\011\011\011\011\011\01188888888888888888888888888888888888888888888888888888888888888888888888888888888888888(888888888888888\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\016\016\016\016\016\016\016\016\004\004\004\004\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168888888888888\003((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU8\003\003\003\003\00388888888888((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" | ||||
|     "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((\003\0038888888888888((((((((((((((((((((((((((((((((((((((((((((((((\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\0216((((((66666666666666688888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888" | ||||
|     "(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888(((((((((((((((((((((((((((((((((((((((((((((((((((((((((8888888(((((((((((((((((((((((((((((((8\011\011\011\011\011\011\011\011\011\0118888\003\003(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((8\011\011\011\011\011\011\011\011\011\011888888((((((((((((((((((((((((((((((8866666\0038888888888((((((((((((((((((((((((((((((((((((((((((((((((6666666\003\003\003\003\003\016\016\016\0165555\003\0168888888888\011\011\011\011\011\011\011\011\011\0118\022\022\022\022\022\022\0228(((((((((((((((((((((88888(((((((((((((((((((88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\003\003\003\00388888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888" | ||||
|     "(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((8888N(OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO8888888NNNN5555555555555888888888888888888888888888888888888888888888888888888888888888855\0035688888888888OO88888888888888((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88888888((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((888888888888888888888888888888888888888888(((((((((8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888" | ||||
|     "8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888885555855555558558(((((((((((((((((((((((((((((((((((888888888888888(88888888888888888888888888888(((88(88888888888888((((88888888((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((8888(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88888(((((((((((((888(((((((((8888888((((((((((88\0166N\003\021\021\021\02188888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888" | ||||
|     "66666666666666666666666666666666666666666666668866666666666666666666666888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016888888888888888888888888888888888888888888888888888888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\01688\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016QQ666\016\016\016QQQQQQ\021\021\021\021\021\021\021\02166666666\016\0166666666\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0166666\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016888888888888888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016666\01688888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022888888888888\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022888888888888" | ||||
|     "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016888888888\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\015\015\015\015\015\015\0158\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\0278\027\02788\02788\027\02788\027\027\027\0278\027\027\027\027\027\027\027\027\015\015\015\0158\0158\015\015\015\015\015\015\0158\015\015\015\015\015\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\027\0278\027\027\027\02788\027\027\027\027\027\027\027\0278\027\027\027\027\027\027\0278\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\027\0278\027\027\027\0278\027\027\027\027\0278\027888\027\027\027\027\027\027\0278\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\01588\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\007\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\007\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\007\015\015\015\015" | ||||
|     "\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\007\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\007\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\007\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\007\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\007\015\015\015\015\015\015\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\027\007\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\007\015\015\015\015\015\015\027\01588\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\011\0116666666666666666666666666666666666666666666666666666666\016\016\016\01666666666666666666666666666666666666666666666666666\016\016\016\016\016\016\016\0166\016\016\016\016\016\016\016\016\016\016\016\016\016\0166\016\016\003\003\003\003\00388888888888888866666866666666666666688888888888888888888888888888888888888888888888888888888888888888888888888888888\015\015\015\015\015\015\015\015\015\015(\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015888888\015\015\015\015\015\015888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888NNNNNNN8NNNNNNNNNNNNNNNNN88NNNNNNN8NN8NNNNN8888844444444444444444444444444444444444444444444444444444444444444888888888888888888888888888888888N8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888" | ||||
|     "(((((((((((((((((((((((((((((((((((((((((((((8886666666555555588\011\011\011\011\011\011\011\011\011\0118888(\01688888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888((((((((((((((((((((((((((((((688888888888888888((((((((((((((((((((((((((((((((((((((((((((6666\011\011\011\011\011\011\011\011\011\01188888\0048888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888(((((((((((((((((((((((((((56666\011\011\011\011\011\011\011\011\011\01188888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888(((((((8((((8((8(((((((((((((((8" | ||||
|     "(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88\022\022\022\022\022\022\022\022\022666666688888888888888888888888888888888888888888\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\226\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015666N66658888\011\011\011\011\011\011\011\011\011\0118888\003\003888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\016\022\022\022\004\022\022\022\0228888888888888888888888888888888888888888888888888888888888888888888888888888\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\022\016\022\022\022\022\022\022\022\022\022\022\022\022\022\022\02288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888" | ||||
|     "((((8(((((((((((((((((((((((((((8((8(88(8((((((((((8((((8(8(888888(8888(8(8(8(((8((8(88(8(8(8(8(8((8(88((((8(((((((8((((8((((8(8((((((((((8(((((((((((((((((88888(((8(((((8(((((((((((((((((8888888888888888888888888888888888888888888888888888\007\00788888888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016888888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\01688\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168888888888\022\022\022\022\022\022\022\022\022\022\022\022\022\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\016\016\016\016\016\016\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\016\016\016\016\016\016\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\227\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\01688888888888888888888888888888888888888888888888888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168888888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168888\016\016\016\016\016\016\016\016\0168888888\016\01688888888888888\016\016\016\016\016\0168888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888" | ||||
|     "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\013\013\013\013\013\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016888\016\016\016\016\016\016\016\016\016\016\016\016\016888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016888888\016\016\016\016\016\016\016\016\016\016\016\0168888\016888888888888888\016\016\016\016\016\016\016\016\016\016\016\0168888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\01688888888\016\016\016\016\016\016\016\016\016\016888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\01688888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\01688\016\016888888888888888888888888888888888888888888888888888888888888888888888888888888" | ||||
|     "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016888888888888\016\016\016\016\016\016\016\016\016\016\016\016\016\01688\016\016\016\016\016\016\016\016\016\016\016\016\016888\016\016\016\016\016\016\016\016\0168888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168\016\016\016\016\016\016\01688888888\016\016\016\016\016\016\016\016\016\016\016\016\016\0168888\016\016\016\016\016\016\016\016\0168888888\016\016\016\016\016\016\016\016\0168888888\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\0168888888888888888888888888888888888888\011\011\011\011\011\011\011\011\011\011888888((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88888888888888888888888888888888((((((((((((((((((((((((((((((((((((((((((((((((((((((((((888888((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((" | ||||
|     "((((((((((((((((((((((((((((((88((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88888888888888(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((8888888888888888888888888888888((((((((((((((((((((((((((((((8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888" | ||||
|     "(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((88888((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((888888888888888888888888888888888888888888888888888888888888888888888888888888888\021888888888888888888888888888888\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021\021888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888886666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666668888888888888888" | ||||
|     "\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\221\22188"; | ||||
|  | ||||
| constexpr std::size_t property_index(char32_t code_point) | ||||
| { | ||||
|     LEXY_PRECONDITION(code_point <= 0x10FFFF); | ||||
|     auto high = (code_point >> 8) & 0xFFFF; | ||||
|     auto low  = code_point & 0xFF; | ||||
|  | ||||
|     auto block_start = static_cast<unsigned char>(block_starts[high]); | ||||
|     auto block_index = block_start * 256u + low; | ||||
|     return static_cast<unsigned char>(blocks[block_index]); | ||||
| } | ||||
|  | ||||
| constexpr lexy::code_point::general_category_t category[] = {lexy::code_point::Cc,lexy::code_point::Cc,lexy::code_point::Zs,lexy::code_point::Po,lexy::code_point::Sc,lexy::code_point::Ps,lexy::code_point::Pe,lexy::code_point::Sm,lexy::code_point::Pd,lexy::code_point::Nd,lexy::code_point::Lu,lexy::code_point::Sk,lexy::code_point::Pc,lexy::code_point::Ll,lexy::code_point::So,lexy::code_point::Lo,lexy::code_point::Pi,lexy::code_point::Cf,lexy::code_point::No,lexy::code_point::Ll,lexy::code_point::Po,lexy::code_point::Pf,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Ll,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lo,lexy::code_point::Lu,lexy::code_point::Lt,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lm,lexy::code_point::Lm,lexy::code_point::Mn,lexy::code_point::Mn,lexy::code_point::Cn,lexy::code_point::Lm,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Ll,lexy::code_point::Lu,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Lu,lexy::code_point::Ll,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Me,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Mn,lexy::code_point::Mc,lexy::code_point::Lo,lexy::code_point::Mc,lexy::code_point::Lu,lexy::code_point::No,lexy::code_point::Ll,lexy::code_point::Nl,lexy::code_point::Mn,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Ll,lexy::code_point::Lu,lexy::code_point::Ll,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lt,lexy::code_point::Lu,lexy::code_point::Lt,lexy::code_point::Ll,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Cf,lexy::code_point::Zl,lexy::code_point::Zp,lexy::code_point::Sm,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::So,lexy::code_point::Lu,lexy::code_point::Nl,lexy::code_point::Nl,lexy::code_point::So,lexy::code_point::So,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lm,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Ll,lexy::code_point::Cs,lexy::code_point::Co,lexy::code_point::Lo,lexy::code_point::Lm,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::Lu,lexy::code_point::So,}; | ||||
|  | ||||
| enum binary_properties_t | ||||
| { | ||||
|     whitespace, | ||||
|     join_control, | ||||
|     alphabetic, | ||||
|     uppercase, | ||||
|     lowercase, | ||||
|     xid_start, | ||||
|     xid_continue, | ||||
|     _property_count, | ||||
| }; | ||||
| static_assert(static_cast<int>(_property_count) <= 8); | ||||
|  | ||||
| constexpr std::uint_least8_t binary_properties[] = {0,1,1,0,0,0,0,0,0,64,108,0,64,116,0,116,0,0,0,116,64,0,108,108,108,116,108,108,108,108,108,108,108,108,108,108,108,108,108,108,100,108,100,108,108,108,108,108,108,108,108,108,116,100,64,84,0,20,108,108,108,108,108,116,108,116,116,116,116,116,116,108,116,108,108,0,108,108,68,68,68,64,108,64,116,100,100,116,116,116,116,116,116,116,116,108,116,108,108,100,108,100,116,108,108,108,108,108,2,1,1,96,108,108,108,96,108,108,116,12,20,108,108,108,108,108,108,108,108,4,108,108,108,108,108,108,108,108,108,108,108,108,108,116,0,0,4,68,108,108,108,12,}; | ||||
|  | ||||
| constexpr std::int_least32_t case_folding_offset[] = {0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,775,0,0,1,0,-121,-268,210,206,205,79,202,203,207,211,209,213,214,218,217,219,0,2,1,-97,-56,-130,10795,-163,10792,-195,69,71,0,0,0,116,0,0,116,38,37,64,63,1,8,-30,-25,-15,-22,-54,-48,-60,-64,-7,80,0,15,48,0,0,0,0,7264,0,-8,0,0,-6222,-6221,-6212,-6210,-6211,-6204,-6180,35267,-3008,-58,-7615,-8,-8,-74,-9,-7173,-86,-100,-112,-128,-126,0,0,0,0,-7517,-8383,-8262,0,28,16,0,26,0,-10743,-3814,-10727,-10780,-10749,-10783,-10782,-10815,0,-35332,-42280,-42308,-42319,-42315,-42305,-42258,-42282,-42261,928,-48,-42307,-35384,-38864,0,0,0,0,40,39,34,0,}; | ||||
| } // namespace lexy::_unicode_db | ||||
							
								
								
									
										275
									
								
								dep/lexy/include/lexy/action/base.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								dep/lexy/include/lexy/action/base.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,275 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_ACTION_BASE_HPP_INCLUDED | ||||
| #define LEXY_ACTION_BASE_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/config.hpp> | ||||
| #include <lexy/_detail/lazy_init.hpp> | ||||
| #include <lexy/_detail/type_name.hpp> | ||||
| #include <lexy/callback/noop.hpp> | ||||
| #include <lexy/dsl/base.hpp> | ||||
| #include <lexy/grammar.hpp> | ||||
|  | ||||
| //=== parse_context ===// | ||||
| namespace lexy | ||||
| { | ||||
| namespace _detail | ||||
| { | ||||
|     struct parse_context_var_base | ||||
|     { | ||||
|         const void*             id; | ||||
|         parse_context_var_base* next; | ||||
|  | ||||
|         constexpr parse_context_var_base(const void* id) : id(id), next(nullptr) {} | ||||
|  | ||||
|         template <typename Context> | ||||
|         constexpr void link(Context& context) | ||||
|         { | ||||
|             auto cb  = context.control_block; | ||||
|             next     = cb->vars; | ||||
|             cb->vars = this; | ||||
|         } | ||||
|  | ||||
|         template <typename Context> | ||||
|         constexpr void unlink(Context& context) | ||||
|         { | ||||
|             auto cb  = context.control_block; | ||||
|             cb->vars = next; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     template <typename Id, typename T> | ||||
|     struct parse_context_var : parse_context_var_base | ||||
|     { | ||||
|         static constexpr auto type_id = lexy::_detail::type_id<Id>(); | ||||
|  | ||||
|         T value; | ||||
|  | ||||
|         explicit constexpr parse_context_var(T&& value) | ||||
|         : parse_context_var_base(static_cast<const void*>(&type_id) /* NOLINT */), | ||||
|           value(LEXY_MOV(value)) | ||||
|         {} | ||||
|  | ||||
|         template <typename ControlBlock> | ||||
|         static constexpr T& get(const ControlBlock* cb) | ||||
|         { | ||||
|             for (auto cur = cb->vars; cur; cur = cur->next) | ||||
|                 if (cur->id == static_cast<const void*>(&type_id) /* NOLINT */) | ||||
|                     return static_cast<parse_context_var*>(cur)->value; | ||||
|  | ||||
|             LEXY_ASSERT(false, "context variable hasn't been created"); | ||||
|             return static_cast<parse_context_var*>(cb->vars)->value; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     template <typename Handler, typename State = void> | ||||
|     struct parse_context_control_block | ||||
|     { | ||||
|         using handler_type = Handler; | ||||
|         using state_type   = State; | ||||
|  | ||||
|         LEXY_EMPTY_MEMBER Handler parse_handler; | ||||
|         State*                    parse_state; | ||||
|  | ||||
|         parse_context_var_base* vars; | ||||
|  | ||||
|         int  cur_depth, max_depth; | ||||
|         bool enable_whitespace_skipping; | ||||
|  | ||||
|         constexpr parse_context_control_block(Handler&& handler, State* state, | ||||
|                                               std::size_t max_depth) | ||||
|         : parse_handler(LEXY_MOV(handler)), parse_state(state), // | ||||
|           vars(nullptr),                                        // | ||||
|           cur_depth(0), max_depth(static_cast<int>(max_depth)), enable_whitespace_skipping(true) | ||||
|         {} | ||||
|  | ||||
|         template <typename OtherHandler> | ||||
|         constexpr parse_context_control_block(Handler&& handler, | ||||
|                                               parse_context_control_block<OtherHandler, State>* cb) | ||||
|         : parse_handler(LEXY_MOV(handler)), parse_state(cb->parse_state), // | ||||
|           vars(cb->vars), cur_depth(cb->cur_depth), max_depth(cb->max_depth), | ||||
|           enable_whitespace_skipping(cb->enable_whitespace_skipping) | ||||
|         {} | ||||
|  | ||||
|         template <typename OtherHandler> | ||||
|         constexpr void copy_vars_from(parse_context_control_block<OtherHandler, State>* cb) | ||||
|         { | ||||
|             vars                       = cb->vars; | ||||
|             cur_depth                  = cb->cur_depth; | ||||
|             max_depth                  = cb->max_depth; | ||||
|             enable_whitespace_skipping = cb->enable_whitespace_skipping; | ||||
|         } | ||||
|     }; | ||||
| } // namespace _detail | ||||
|  | ||||
| // If a production doesn't define whitespace, we don't need to pass it and can shorten the template | ||||
| // name. | ||||
| template <typename Production> | ||||
| using _whitespace_production_of | ||||
|     = std::conditional_t<_production_defines_whitespace<Production>, Production, void>; | ||||
|  | ||||
| template <typename Handler, typename State, typename Production> | ||||
| using _production_value_type = | ||||
|     typename Handler::template value_callback<Production, State>::return_type; | ||||
|  | ||||
| template <typename Handler, typename State, typename Production, | ||||
|           typename WhitespaceProduction = _whitespace_production_of<Production>> | ||||
| struct _pc | ||||
| { | ||||
|     using handler_type = Handler; | ||||
|     using state_type   = State; | ||||
|  | ||||
|     using production            = Production; | ||||
|     using whitespace_production = WhitespaceProduction; | ||||
|     using value_type            = _production_value_type<Handler, State, Production>; | ||||
|  | ||||
|     typename Handler::event_handler                       handler; | ||||
|     _detail::parse_context_control_block<Handler, State>* control_block; | ||||
|     _detail::lazy_init<value_type>                        value; | ||||
|  | ||||
|     constexpr explicit _pc(_detail::parse_context_control_block<Handler, State>* cb) | ||||
|     : handler(Production{}), control_block(cb) | ||||
|     {} | ||||
|  | ||||
|     template <typename ChildProduction> | ||||
|     constexpr auto sub_context(ChildProduction) | ||||
|     { | ||||
|         // Update the whitespace production if necessary. | ||||
|         // If the current production is a token or defines whitespace, | ||||
|         // we change it to the current production (or void), otherwise keep it. | ||||
|         using new_whitespace_production | ||||
|             = std::conditional_t<is_token_production<ChildProduction> // | ||||
|                                      || _production_defines_whitespace<ChildProduction>, | ||||
|                                  _whitespace_production_of<ChildProduction>, WhitespaceProduction>; | ||||
|         return _pc<Handler, State, ChildProduction, new_whitespace_production>(control_block); | ||||
|     } | ||||
|  | ||||
|     constexpr auto value_callback() | ||||
|     { | ||||
|         using callback = typename Handler::template value_callback<Production, State>; | ||||
|         return callback(control_block->parse_state); | ||||
|     } | ||||
|  | ||||
|     template <typename Event, typename... Args> | ||||
|     constexpr auto on(Event ev, Args&&... args) | ||||
|     { | ||||
|         return handler.on(control_block->parse_handler, ev, LEXY_FWD(args)...); | ||||
|     } | ||||
| }; | ||||
| } // namespace lexy | ||||
|  | ||||
| //=== do_action ===// | ||||
| namespace lexy::_detail | ||||
| { | ||||
| struct final_parser | ||||
| { | ||||
|     template <typename Context, typename Reader, typename... Args> | ||||
|     LEXY_PARSER_FUNC static bool parse(Context& context, Reader&, Args&&... args) | ||||
|     { | ||||
|         context.value.emplace_result(context.value_callback(), LEXY_FWD(args)...); | ||||
|         return true; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename NextParser> | ||||
| struct context_finish_parser | ||||
| { | ||||
|     template <typename Context, typename Reader, typename SubContext, typename... Args> | ||||
|     LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, SubContext& sub_context, | ||||
|                                        Args&&... args) | ||||
|     { | ||||
|         // Might need to skip whitespace, according to the original context. | ||||
|         using continuation | ||||
|             = std::conditional_t<lexy::is_token_production<typename SubContext::production>, | ||||
|                                  lexy::whitespace_parser<Context, NextParser>, NextParser>; | ||||
|  | ||||
|         // Pass the produced value to the next parser. | ||||
|         if constexpr (std::is_void_v<typename SubContext::value_type>) | ||||
|             return continuation::parse(context, reader, LEXY_FWD(args)...); | ||||
|         else | ||||
|             return continuation::parse(context, reader, LEXY_FWD(args)..., | ||||
|                                        LEXY_MOV(*sub_context.value)); | ||||
|     } | ||||
| }; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| constexpr void* no_parse_state = nullptr; | ||||
|  | ||||
| template <typename Handler, typename State, typename Production, typename Reader> | ||||
| constexpr auto _do_action(_pc<Handler, State, Production>& context, Reader& reader) | ||||
| { | ||||
|     context.on(parse_events::grammar_start{}, reader.position()); | ||||
|     context.on(parse_events::production_start{}, reader.position()); | ||||
|  | ||||
|     // We parse whitespace, theen the rule, then finish. | ||||
|     using parser = lexy::whitespace_parser< | ||||
|         LEXY_DECAY_DECLTYPE(context), | ||||
|         lexy::parser_for<lexy::production_rule<Production>, _detail::final_parser>>; | ||||
|     auto rule_result = parser::parse(context, reader); | ||||
|  | ||||
|     if (rule_result) | ||||
|     { | ||||
|         context.on(parse_events::production_finish{}, reader.position()); | ||||
|         context.on(parse_events::grammar_finish{}, reader); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         context.on(parse_events::production_cancel{}, reader.position()); | ||||
|         context.on(parse_events::grammar_cancel{}, reader); | ||||
|     } | ||||
|  | ||||
|     return rule_result; | ||||
| } | ||||
|  | ||||
| template <typename Production, template <typename> typename Result, typename Handler, | ||||
|           typename State, typename Reader> | ||||
| constexpr auto do_action(Handler&& handler, State* state, Reader& reader) | ||||
| { | ||||
|     static_assert(!std::is_reference_v<Handler>, "need to move handler in"); | ||||
|  | ||||
|     _detail::parse_context_control_block control_block(LEXY_MOV(handler), state, | ||||
|                                                        max_recursion_depth<Production>()); | ||||
|     _pc<Handler, State, Production>      context(&control_block); | ||||
|  | ||||
|     auto rule_result = _do_action(context, reader); | ||||
|  | ||||
|     using value_type = typename decltype(context)::value_type; | ||||
|     if constexpr (std::is_void_v<value_type>) | ||||
|         return LEXY_MOV(control_block.parse_handler).template get_result<Result<void>>(rule_result); | ||||
|     else if (context.value) | ||||
|         return LEXY_MOV(control_block.parse_handler) | ||||
|             .template get_result<Result<value_type>>(rule_result, LEXY_MOV(*context.value)); | ||||
|     else | ||||
|         return LEXY_MOV(control_block.parse_handler) | ||||
|             .template get_result<Result<value_type>>(rule_result); | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| //=== value callback ===// | ||||
| namespace lexy::_detail | ||||
| { | ||||
| struct void_value_callback | ||||
| { | ||||
|     constexpr void_value_callback() = default; | ||||
|     template <typename State> | ||||
|     constexpr explicit void_value_callback(State*) | ||||
|     {} | ||||
|  | ||||
|     using return_type = void; | ||||
|  | ||||
|     constexpr auto sink() const | ||||
|     { | ||||
|         return lexy::noop.sink(); | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr void operator()(Args&&...) const | ||||
|     {} | ||||
| }; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #endif // LEXY_ACTION_BASE_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										90
									
								
								dep/lexy/include/lexy/action/match.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								dep/lexy/include/lexy/action/match.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_ACTION_MATCH_HPP_INCLUDED | ||||
| #define LEXY_ACTION_MATCH_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/action/base.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| class _mh | ||||
| { | ||||
| public: | ||||
|     constexpr _mh() : _failed(false) {} | ||||
|  | ||||
|     class event_handler | ||||
|     { | ||||
|     public: | ||||
|         constexpr event_handler(production_info) {} | ||||
|  | ||||
|         template <typename Error> | ||||
|         constexpr void on(_mh& handler, parse_events::error, Error&&) | ||||
|         { | ||||
|             handler._failed = true; | ||||
|         } | ||||
|  | ||||
|         template <typename Event, typename... Args> | ||||
|         constexpr int on(_mh&, Event, const Args&...) | ||||
|         { | ||||
|             return 0; // operation_chain_start needs to return something | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     template <typename Production, typename State> | ||||
|     using value_callback = _detail::void_value_callback; | ||||
|  | ||||
|     template <typename> | ||||
|     constexpr bool get_result(bool rule_parse_result) && | ||||
|     { | ||||
|         return rule_parse_result && !_failed; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     bool _failed; | ||||
| }; | ||||
|  | ||||
| template <typename State, typename Input> | ||||
| struct match_action | ||||
| { | ||||
|     State* _state = nullptr; | ||||
|  | ||||
|     using handler = _mh; | ||||
|     using state   = State; | ||||
|     using input   = Input; | ||||
|  | ||||
|     template <typename> | ||||
|     using result_type = bool; | ||||
|  | ||||
|     constexpr match_action() = default; | ||||
|     template <typename U = State> | ||||
|     constexpr explicit match_action(U& state) : _state(&state) | ||||
|     {} | ||||
|  | ||||
|     template <typename Production> | ||||
|     constexpr auto operator()(Production, const Input& input) const | ||||
|     { | ||||
|         auto reader = input.reader(); | ||||
|         return lexy::do_action<Production, result_type>(handler(), _state, reader); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Production, typename Input> | ||||
| constexpr bool match(const Input& input) | ||||
| { | ||||
|     return match_action<void, Input>()(Production{}, input); | ||||
| } | ||||
| template <typename Production, typename Input, typename State> | ||||
| constexpr bool match(const Input& input, State& state) | ||||
| { | ||||
|     return match_action<State, Input>(state)(Production{}, input); | ||||
| } | ||||
| template <typename Production, typename Input, typename State> | ||||
| constexpr bool match(const Input& input, const State& state) | ||||
| { | ||||
|     return match_action<const State, Input>(state)(Production{}, input); | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_ACTION_MATCH_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										191
									
								
								dep/lexy/include/lexy/action/parse.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								dep/lexy/include/lexy/action/parse.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,191 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_ACTION_PARSE_HPP_INCLUDED | ||||
| #define LEXY_ACTION_PARSE_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/invoke.hpp> | ||||
| #include <lexy/action/base.hpp> | ||||
| #include <lexy/action/validate.hpp> | ||||
| #include <lexy/callback/base.hpp> | ||||
| #include <lexy/callback/bind.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename T, typename ErrorCallback> | ||||
| class parse_result | ||||
| { | ||||
|     using _impl_t = lexy::validate_result<ErrorCallback>; | ||||
|  | ||||
| public: | ||||
|     using value_type     = T; | ||||
|     using error_callback = ErrorCallback; | ||||
|     using error_type     = typename _impl_t::error_type; | ||||
|  | ||||
|     //=== status ===// | ||||
|     constexpr explicit operator bool() const noexcept | ||||
|     { | ||||
|         return _impl.is_success(); | ||||
|     } | ||||
|  | ||||
|     constexpr bool is_success() const noexcept | ||||
|     { | ||||
|         return _impl.is_success(); | ||||
|     } | ||||
|     constexpr bool is_error() const noexcept | ||||
|     { | ||||
|         return _impl.is_error(); | ||||
|     } | ||||
|     constexpr bool is_recovered_error() const noexcept | ||||
|     { | ||||
|         return _impl.is_recovered_error(); | ||||
|     } | ||||
|     constexpr bool is_fatal_error() const noexcept | ||||
|     { | ||||
|         return _impl.is_fatal_error(); | ||||
|     } | ||||
|  | ||||
|     //=== value ===// | ||||
|     constexpr bool has_value() const noexcept | ||||
|     { | ||||
|         return static_cast<bool>(_value); | ||||
|     } | ||||
|  | ||||
|     constexpr decltype(auto) value() const& noexcept | ||||
|     { | ||||
|         return *_value; | ||||
|     } | ||||
|     constexpr decltype(auto) value() && noexcept | ||||
|     { | ||||
|         return LEXY_MOV(*_value); | ||||
|     } | ||||
|  | ||||
|     //=== error ===// | ||||
|     constexpr std::size_t error_count() const noexcept | ||||
|     { | ||||
|         return _impl.error_count(); | ||||
|     } | ||||
|  | ||||
|     constexpr const auto& errors() const& noexcept | ||||
|     { | ||||
|         return _impl.errors(); | ||||
|     } | ||||
|     constexpr auto&& errors() && noexcept | ||||
|     { | ||||
|         return LEXY_MOV(_impl).errors(); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     constexpr explicit parse_result(_impl_t&& impl) noexcept : _impl(LEXY_MOV(impl)), _value() {} | ||||
|     template <typename U> | ||||
|     constexpr explicit parse_result(_impl_t&& impl, U&& v) noexcept : _impl(LEXY_MOV(impl)) | ||||
|     { | ||||
|         LEXY_PRECONDITION(impl.is_success() || impl.is_recovered_error()); | ||||
|         _value.emplace(LEXY_FWD(v)); | ||||
|     } | ||||
|  | ||||
|     // In principle we could do a space optimization, as we can reconstruct the impl's status from | ||||
|     // the state of _value and error. Feel free to implement it. | ||||
|     _impl_t                     _impl; | ||||
|     lexy::_detail::lazy_init<T> _value; | ||||
|  | ||||
|     template <typename Reader> | ||||
|     friend class _ph; | ||||
| }; | ||||
| } // namespace lexy | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename Reader> | ||||
| class _ph | ||||
| { | ||||
|     using iterator = typename Reader::iterator; | ||||
|  | ||||
| public: | ||||
|     template <typename Input, typename Sink> | ||||
|     constexpr explicit _ph(const _detail::any_holder<const Input*>& input, | ||||
|                            _detail::any_holder<Sink>&               sink) | ||||
|     : _validate(input, sink) | ||||
|     {} | ||||
|  | ||||
|     using event_handler = typename _vh<Reader>::event_handler; | ||||
|  | ||||
|     constexpr operator _vh<Reader>&() | ||||
|     { | ||||
|         return _validate; | ||||
|     } | ||||
|  | ||||
|     template <typename Production, typename State> | ||||
|     using value_callback = production_value_callback<Production, State>; | ||||
|  | ||||
|     template <typename Result, typename T> | ||||
|     constexpr auto get_result(bool rule_parse_result, T&& result) && | ||||
|     { | ||||
|         using validate_result = lexy::validate_result<typename Result::error_callback>; | ||||
|         return Result(LEXY_MOV(_validate).template get_result<validate_result>(rule_parse_result), | ||||
|                       LEXY_MOV(result)); | ||||
|     } | ||||
|     template <typename Result> | ||||
|     constexpr auto get_result(bool rule_parse_result) && | ||||
|     { | ||||
|         using validate_result = lexy::validate_result<typename Result::error_callback>; | ||||
|         return Result(LEXY_MOV(_validate).template get_result<validate_result>(rule_parse_result)); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     _vh<Reader> _validate; | ||||
| }; | ||||
|  | ||||
| template <typename State, typename Input, typename ErrorCallback> | ||||
| struct parse_action | ||||
| { | ||||
|     const ErrorCallback* _callback; | ||||
|     State*               _state = nullptr; | ||||
|  | ||||
|     using handler = _ph<lexy::input_reader<Input>>; | ||||
|     using state   = State; | ||||
|     using input   = Input; | ||||
|  | ||||
|     template <typename T> | ||||
|     using result_type = parse_result<T, ErrorCallback>; | ||||
|  | ||||
|     constexpr explicit parse_action(const ErrorCallback& callback) : _callback(&callback) {} | ||||
|     template <typename U = State> | ||||
|     constexpr explicit parse_action(U& state, const ErrorCallback& callback) | ||||
|     : _callback(&callback), _state(&state) | ||||
|     {} | ||||
|  | ||||
|     template <typename Production> | ||||
|     constexpr auto operator()(Production, const Input& input) const | ||||
|     { | ||||
|         _detail::any_holder input_holder(&input); | ||||
|         _detail::any_holder sink(_get_error_sink(*_callback)); | ||||
|         auto                reader = input.reader(); | ||||
|         return lexy::do_action<Production, result_type>(handler(input_holder, sink), _state, | ||||
|                                                         reader); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// Parses the production into a value, invoking the callback on error. | ||||
| template <typename Production, typename Input, typename ErrorCallback> | ||||
| constexpr auto parse(const Input& input, const ErrorCallback& callback) | ||||
| { | ||||
|     return parse_action<void, Input, ErrorCallback>(callback)(Production{}, input); | ||||
| } | ||||
|  | ||||
| /// Parses the production into a value, invoking the callback on error. | ||||
| /// All callbacks gain access to the specified parse state. | ||||
| template <typename Production, typename Input, typename State, typename ErrorCallback> | ||||
| constexpr auto parse(const Input& input, State& state, const ErrorCallback& callback) | ||||
| { | ||||
|     return parse_action<State, Input, ErrorCallback>(state, callback)(Production{}, input); | ||||
| } | ||||
| template <typename Production, typename Input, typename State, typename ErrorCallback> | ||||
| constexpr auto parse(const Input& input, const State& state, const ErrorCallback& callback) | ||||
| { | ||||
|     return parse_action<const State, Input, ErrorCallback>(state, callback)(Production{}, input); | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_ACTION_PARSE_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										217
									
								
								dep/lexy/include/lexy/action/parse_as_tree.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								dep/lexy/include/lexy/action/parse_as_tree.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,217 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_ACTION_PARSE_AS_TREE_HPP_INCLUDED | ||||
| #define LEXY_ACTION_PARSE_AS_TREE_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/action/base.hpp> | ||||
| #include <lexy/action/validate.hpp> | ||||
| #include <lexy/dsl/any.hpp> | ||||
| #include <lexy/parse_tree.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename Tree, typename Reader> | ||||
| class _pth | ||||
| { | ||||
| public: | ||||
|     template <typename Input, typename Sink> | ||||
|     explicit _pth(Tree& tree, const _detail::any_holder<const Input*>& input, | ||||
|                   _detail::any_holder<Sink>& sink) | ||||
|     : _tree(&tree), _depth(0), _validate(input, sink) | ||||
|     {} | ||||
|  | ||||
|     class event_handler | ||||
|     { | ||||
|         using iterator = typename Reader::iterator; | ||||
|  | ||||
|     public: | ||||
|         event_handler(production_info info) : _validate(info) {} | ||||
|  | ||||
|         void on(_pth& handler, parse_events::grammar_start, iterator) | ||||
|         { | ||||
|             LEXY_PRECONDITION(handler._depth == 0); | ||||
|  | ||||
|             handler._builder.emplace(LEXY_MOV(*handler._tree), _validate.get_info()); | ||||
|         } | ||||
|         void on(_pth& handler, parse_events::grammar_finish, Reader& reader) | ||||
|         { | ||||
|             LEXY_PRECONDITION(handler._depth == 0); | ||||
|  | ||||
|             auto begin = reader.position(); | ||||
|             lexy::try_match_token(dsl::any, reader); | ||||
|             auto end = reader.position(); | ||||
|  | ||||
|             *handler._tree = LEXY_MOV(*handler._builder).finish({begin, end}); | ||||
|         } | ||||
|         void on(_pth& handler, parse_events::grammar_cancel, Reader&) | ||||
|         { | ||||
|             LEXY_PRECONDITION(handler._depth == 0); | ||||
|  | ||||
|             handler._tree->clear(); | ||||
|         } | ||||
|  | ||||
|         void on(_pth& handler, parse_events::production_start ev, iterator pos) | ||||
|         { | ||||
|             if (handler._depth++ > 0) | ||||
|                 _marker = handler._builder->start_production(_validate.get_info()); | ||||
|  | ||||
|             _validate.on(handler._validate, ev, pos); | ||||
|         } | ||||
|  | ||||
|         void on(_pth& handler, parse_events::production_finish ev, iterator pos) | ||||
|         { | ||||
|             if (--handler._depth > 0) | ||||
|             { | ||||
|                 if (handler._builder->current_child_count() == 0) | ||||
|                     handler._builder->token(lexy::position_token_kind, _validate.production_begin(), | ||||
|                                             _validate.production_begin()); | ||||
|                 handler._builder->finish_production(LEXY_MOV(_marker)); | ||||
|             } | ||||
|  | ||||
|             _validate.on(handler._validate, ev, pos); | ||||
|         } | ||||
|  | ||||
|         void on(_pth& handler, parse_events::production_cancel ev, iterator pos) | ||||
|         { | ||||
|             if (--handler._depth > 0) | ||||
|             { | ||||
|                 // Cancelling the production removes all nodes from the tree. | ||||
|                 // To ensure that the parse tree remains lossless, we add everything consumed by it | ||||
|                 // as an error token. | ||||
|                 handler._builder->cancel_production(LEXY_MOV(_marker)); | ||||
|                 handler._builder->token(lexy::error_token_kind, _validate.production_begin(), pos); | ||||
|             } | ||||
|  | ||||
|             _validate.on(handler._validate, ev, pos); | ||||
|         } | ||||
|  | ||||
|         auto on(_pth& handler, lexy::parse_events::operation_chain_start, iterator) | ||||
|         { | ||||
|             // As we don't know the production yet (or whether it is actually an operation), | ||||
|             // we create a container node to decide later. | ||||
|             return handler._builder->start_container(); | ||||
|         } | ||||
|         template <typename Operation> | ||||
|         void on(_pth& handler, lexy::parse_events::operation_chain_op, Operation op, iterator) | ||||
|         { | ||||
|             // We set the production of the current container. | ||||
|             // This will do a "left rotation" on the parse tree, making a new container the parent. | ||||
|             handler._builder->set_container_production(op); | ||||
|         } | ||||
|         template <typename Marker> | ||||
|         void on(_pth& handler, lexy::parse_events::operation_chain_finish, Marker&& marker, | ||||
|                 iterator) | ||||
|         { | ||||
|             handler._builder->finish_container(LEXY_MOV(marker)); | ||||
|         } | ||||
|  | ||||
|         template <typename TokenKind> | ||||
|         void on(_pth& handler, parse_events::token, TokenKind kind, iterator begin, iterator end) | ||||
|         { | ||||
|             handler._builder->token(kind, begin, end); | ||||
|         } | ||||
|  | ||||
|         template <typename Error> | ||||
|         void on(_pth& handler, parse_events::error ev, Error&& error) | ||||
|         { | ||||
|             _validate.on(handler._validate, ev, LEXY_FWD(error)); | ||||
|         } | ||||
|  | ||||
|         template <typename Event, typename... Args> | ||||
|         auto on(_pth& handler, Event ev, Args&&... args) | ||||
|         { | ||||
|             return _validate.on(handler._validate, ev, LEXY_FWD(args)...); | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         typename Tree::builder::marker      _marker; | ||||
|         typename _vh<Reader>::event_handler _validate; | ||||
|     }; | ||||
|  | ||||
|     template <typename Production, typename State> | ||||
|     using value_callback = _detail::void_value_callback; | ||||
|  | ||||
|     template <typename T> | ||||
|     constexpr auto get_result(bool rule_parse_result) && | ||||
|     { | ||||
|         LEXY_PRECONDITION(_depth == 0); | ||||
|         return LEXY_MOV(_validate).template get_result<T>(rule_parse_result); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     lexy::_detail::lazy_init<typename Tree::builder> _builder; | ||||
|     Tree*                                            _tree; | ||||
|     int                                              _depth; | ||||
|  | ||||
|     _vh<Reader> _validate; | ||||
| }; | ||||
|  | ||||
| template <typename State, typename Input, typename ErrorCallback, typename TokenKind = void, | ||||
|           typename MemoryResource = void> | ||||
| struct parse_as_tree_action | ||||
| { | ||||
|     using tree_type = lexy::parse_tree_for<Input, TokenKind, MemoryResource>; | ||||
|  | ||||
|     tree_type*           _tree; | ||||
|     const ErrorCallback* _callback; | ||||
|     State*               _state = nullptr; | ||||
|  | ||||
|     using handler = _pth<tree_type, lexy::input_reader<Input>>; | ||||
|     using state   = State; | ||||
|     using input   = Input; | ||||
|  | ||||
|     template <typename> | ||||
|     using result_type = validate_result<ErrorCallback>; | ||||
|  | ||||
|     constexpr explicit parse_as_tree_action(tree_type& tree, const ErrorCallback& callback) | ||||
|     : _tree(&tree), _callback(&callback) | ||||
|     {} | ||||
|     template <typename U = State> | ||||
|     constexpr explicit parse_as_tree_action(U& state, tree_type& tree, | ||||
|                                             const ErrorCallback& callback) | ||||
|     : _tree(&tree), _callback(&callback), _state(&state) | ||||
|     {} | ||||
|  | ||||
|     template <typename Production> | ||||
|     constexpr auto operator()(Production, const Input& input) const | ||||
|     { | ||||
|         _detail::any_holder input_holder(&input); | ||||
|         _detail::any_holder sink(_get_error_sink(*_callback)); | ||||
|         auto                reader = input.reader(); | ||||
|         return lexy::do_action<Production, result_type>(handler(*_tree, input_holder, sink), _state, | ||||
|                                                         reader); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Production, typename TokenKind, typename MemoryResource, typename Input, | ||||
|           typename ErrorCallback> | ||||
| auto parse_as_tree(parse_tree<lexy::input_reader<Input>, TokenKind, MemoryResource>& tree, | ||||
|                    const Input&                                                      input, | ||||
|                    const ErrorCallback& callback) -> validate_result<ErrorCallback> | ||||
| { | ||||
|     return parse_as_tree_action<void, Input, ErrorCallback, TokenKind, | ||||
|                                 MemoryResource>(tree, callback)(Production{}, input); | ||||
| } | ||||
| template <typename Production, typename TokenKind, typename MemoryResource, typename Input, | ||||
|           typename State, typename ErrorCallback> | ||||
| auto parse_as_tree(parse_tree<lexy::input_reader<Input>, TokenKind, MemoryResource>& tree, | ||||
|                    const Input& input, State& state, | ||||
|                    const ErrorCallback& callback) -> validate_result<ErrorCallback> | ||||
| { | ||||
|     return parse_as_tree_action<State, Input, ErrorCallback, TokenKind, | ||||
|                                 MemoryResource>(state, tree, callback)(Production{}, input); | ||||
| } | ||||
| template <typename Production, typename TokenKind, typename MemoryResource, typename Input, | ||||
|           typename State, typename ErrorCallback> | ||||
| auto parse_as_tree(parse_tree<lexy::input_reader<Input>, TokenKind, MemoryResource>& tree, | ||||
|                    const Input& input, const State& state, | ||||
|                    const ErrorCallback& callback) -> validate_result<ErrorCallback> | ||||
| { | ||||
|     return parse_as_tree_action<const State, Input, ErrorCallback, TokenKind, | ||||
|                                 MemoryResource>(state, tree, callback)(Production{}, input); | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_ACTION_PARSE_AS_TREE_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										98
									
								
								dep/lexy/include/lexy/action/scan.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								dep/lexy/include/lexy/action/scan.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_ACTION_SCAN_HPP_INCLUDED | ||||
| #define LEXY_ACTION_SCAN_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/action/base.hpp> | ||||
| #include <lexy/action/validate.hpp> | ||||
| #include <lexy/dsl/scan.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename ControlProduction> | ||||
| struct _scp; | ||||
| template <> | ||||
| struct _scp<void> | ||||
| { | ||||
|     static LEXY_CONSTEVAL auto name() | ||||
|     { | ||||
|         return "scanner control production"; | ||||
|     } | ||||
|  | ||||
|     static constexpr auto rule  = dsl::scan; | ||||
|     static constexpr auto value = lexy::noop; | ||||
| }; | ||||
| template <typename ControlProduction> | ||||
| struct _scp : ControlProduction, _scp<void> | ||||
| {}; | ||||
|  | ||||
| template <typename ControlProduction, typename Input, typename State, typename ErrorCallback> | ||||
| class scanner : public _detail::scanner<scanner<ControlProduction, Input, State, ErrorCallback>, | ||||
|                                         lexy::input_reader<Input>> | ||||
| { | ||||
|     using _impl       = _detail::scanner<scanner<ControlProduction, Input, State, ErrorCallback>, | ||||
|                                          lexy::input_reader<Input>>; | ||||
|     using _handler    = lexy::_vh<lexy::input_reader<Input>>; | ||||
|     using _production = _scp<ControlProduction>; | ||||
|  | ||||
| public: | ||||
|     constexpr explicit scanner(const Input& input, State* state, const ErrorCallback& callback) | ||||
|     : _impl(input.reader()), _input(&input), _sink(_get_error_sink(callback)), | ||||
|       _cb(_handler(_input, _sink), state, max_recursion_depth<_production>()), _context(&_cb) | ||||
|     { | ||||
|         _context.on(parse_events::production_start{}, this->position()); | ||||
|     } | ||||
|  | ||||
|     constexpr const auto& parse_state() const | ||||
|     { | ||||
|         return *_context.control_block->parse_state; | ||||
|     } | ||||
|  | ||||
|     constexpr auto finish() && -> lexy::validate_result<ErrorCallback> | ||||
|     { | ||||
|         auto parse_result = static_cast<bool>(*this); | ||||
|  | ||||
|         if (parse_result) | ||||
|             _context.on(parse_events::production_finish{}, this->position()); | ||||
|         else | ||||
|             _context.on(parse_events::production_cancel{}, this->position()); | ||||
|  | ||||
|         return LEXY_MOV(_cb.parse_handler) | ||||
|             .template get_result<validate_result<ErrorCallback>>(parse_result); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     auto& context() noexcept | ||||
|     { | ||||
|         return _context; | ||||
|     } | ||||
|  | ||||
|     _detail::any_holder<const Input*>                     _input; | ||||
|     _detail::any_holder<_error_sink_t<ErrorCallback>>     _sink; | ||||
|     _detail::parse_context_control_block<_handler, State> _cb; | ||||
|     _pc<_handler, State, _production>                     _context; | ||||
|  | ||||
|     friend _impl; | ||||
| }; | ||||
|  | ||||
| template <typename ControlProduction = void, typename Input, typename ErrorCallback> | ||||
| constexpr auto scan(const Input& input, const ErrorCallback& callback) | ||||
| { | ||||
|     return scanner<ControlProduction, Input, void, ErrorCallback>(input, no_parse_state, callback); | ||||
| } | ||||
|  | ||||
| template <typename ControlProduction = void, typename Input, typename State, typename ErrorCallback> | ||||
| constexpr auto scan(const Input& input, State& state, const ErrorCallback& callback) | ||||
| { | ||||
|     return scanner<ControlProduction, Input, State, ErrorCallback>(input, &state, callback); | ||||
| } | ||||
| template <typename ControlProduction = void, typename Input, typename State, typename ErrorCallback> | ||||
| constexpr auto scan(const Input& input, const State& state, const ErrorCallback& callback) | ||||
| { | ||||
|     return scanner<ControlProduction, Input, const State, ErrorCallback>(input, &state, callback); | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_ACTION_SCAN_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										506
									
								
								dep/lexy/include/lexy/action/trace.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										506
									
								
								dep/lexy/include/lexy/action/trace.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,506 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_ACTION_TRACE_HPP_INCLUDED | ||||
| #define LEXY_ACTION_TRACE_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/nttp_string.hpp> | ||||
| #include <lexy/action/base.hpp> | ||||
| #include <lexy/input_location.hpp> | ||||
| #include <lexy/token.hpp> | ||||
| #include <lexy/visualize.hpp> | ||||
|  | ||||
| //=== debug event ===// | ||||
| namespace lexy::parse_events | ||||
| { | ||||
| /// Debug event was triggered. | ||||
| /// Arguments: pos, str | ||||
| struct debug | ||||
| {}; | ||||
| } // namespace lexy::parse_events | ||||
|  | ||||
| namespace lexyd | ||||
| { | ||||
| template <typename CharT, CharT... C> | ||||
| struct _debug : rule_base | ||||
| { | ||||
|     template <typename NextParser> | ||||
|     struct p | ||||
|     { | ||||
|         template <typename Context, typename Reader, typename... Args> | ||||
|         LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args) | ||||
|         { | ||||
|             constexpr auto str = lexy::_detail::type_string<CharT, C...>::template c_str<>; | ||||
|             context.on(_ev::debug{}, reader.position(), str); | ||||
|             return NextParser::parse(context, reader, LEXY_FWD(args)...); | ||||
|         } | ||||
|     }; | ||||
| }; | ||||
|  | ||||
| #if LEXY_HAS_NTTP | ||||
| template <lexy::_detail::string_literal Str> | ||||
| constexpr auto debug = lexy::_detail::to_type_string<_debug, Str>{}; | ||||
| #endif | ||||
|  | ||||
| #define LEXY_DEBUG(Str)                                                                            \ | ||||
|     LEXY_NTTP_STRING(::lexyd::_debug, Str) {} | ||||
| } // namespace lexyd | ||||
|  | ||||
| //=== trace ====// | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename OutputIt, typename TokenKind> | ||||
| class trace_writer | ||||
| { | ||||
| public: | ||||
|     explicit trace_writer(OutputIt out, visualization_options opts) | ||||
|     : _out(out), _opts(opts), _cur_depth(0) | ||||
|     {} | ||||
|  | ||||
|     template <typename Location> | ||||
|     void write_production_start(const Location& loc, const char* name) | ||||
|     { | ||||
|         if (_cur_depth <= _opts.max_tree_depth) | ||||
|         { | ||||
|             write_prefix(loc, prefix::event); | ||||
|  | ||||
|             _out = _detail::write_color<_detail::color::bold>(_out, _opts); | ||||
|             _out = _detail::write_str(_out, name); | ||||
|             _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|  | ||||
|             if (_cur_depth == _opts.max_tree_depth) | ||||
|             { | ||||
|                 // Print an ellipsis instead of children. | ||||
|                 _out = _detail::write_str(_out, ": "); | ||||
|                 _out = _detail::write_ellipsis(_out, _opts); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 // Prepare for children. | ||||
|                 _out = _detail::write_str(_out, ":"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ++_cur_depth; | ||||
|     } | ||||
|  | ||||
|     template <typename Location, typename Reader> | ||||
|     void write_token(const Location& loc, lexy::token_kind<TokenKind> kind, | ||||
|                      lexy::lexeme<Reader> lexeme) | ||||
|     { | ||||
|         if (_cur_depth > _opts.max_tree_depth || (kind.ignore_if_empty() && lexeme.empty())) | ||||
|             return; | ||||
|  | ||||
|         write_prefix(loc, prefix::event); | ||||
|  | ||||
|         _out = _detail::write_color<_detail::color::bold>(_out, _opts); | ||||
|         _out = _detail::write_str(_out, kind.name()); | ||||
|         _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|  | ||||
|         if (!lexeme.empty()) | ||||
|         { | ||||
|             _out = _detail::write_str(_out, ": "); | ||||
|             _out = visualize_to(_out, lexeme, _opts | visualize_space); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template <typename Location, typename Reader> | ||||
|     void write_backtrack(const Location& loc, lexy::lexeme<Reader> lexeme) | ||||
|     { | ||||
|         if (_cur_depth > _opts.max_tree_depth || lexeme.empty()) | ||||
|             return; | ||||
|  | ||||
|         write_prefix(loc, prefix::event); | ||||
|  | ||||
|         _out = _detail::write_color<_detail::color::yellow, _detail::color::bold>(_out, _opts); | ||||
|         _out = _detail::write_str(_out, "backtracked"); | ||||
|         _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|  | ||||
|         _out = _detail::write_str(_out, ": "); | ||||
|  | ||||
|         _out = _detail::write_color<_detail::color::yellow>(_out, _opts); | ||||
|         _out = visualize_to(_out, lexeme, _opts.reset(visualize_use_color) | visualize_space); | ||||
|         _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|     } | ||||
|  | ||||
|     template <typename Location, typename Reader, typename Tag> | ||||
|     void write_error(const Location& loc, const lexy::error<Reader, Tag>& error) | ||||
|     { | ||||
|         if (_cur_depth > _opts.max_tree_depth) | ||||
|             return; | ||||
|  | ||||
|         write_prefix(loc, prefix::event); | ||||
|  | ||||
|         _out = _detail::write_color<_detail::color::red, _detail::color::bold>(_out, _opts); | ||||
|         _out = _detail::write_str(_out, "error"); | ||||
|         _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|  | ||||
|         _out = _detail::write_color<_detail::color::red>(_out, _opts); | ||||
|         _out = _detail::write_str(_out, ": "); | ||||
|  | ||||
|         if constexpr (std::is_same_v<Tag, lexy::expected_literal>) | ||||
|         { | ||||
|             auto string = _detail::make_literal_lexeme<typename Reader::encoding>(error.string(), | ||||
|                                                                                   error.length()); | ||||
|  | ||||
|             _out = _detail::write_str(_out, "expected '"); | ||||
|             _out = visualize_to(_out, string, _opts); | ||||
|             _out = _detail::write_str(_out, "'"); | ||||
|         } | ||||
|         else if constexpr (std::is_same_v<Tag, lexy::expected_keyword>) | ||||
|         { | ||||
|             auto string = _detail::make_literal_lexeme<typename Reader::encoding>(error.string(), | ||||
|                                                                                   error.length()); | ||||
|  | ||||
|             _out = _detail::write_str(_out, "expected keyword '"); | ||||
|             _out = visualize_to(_out, string, _opts); | ||||
|             _out = _detail::write_str(_out, "'"); | ||||
|         } | ||||
|         else if constexpr (std::is_same_v<Tag, lexy::expected_char_class>) | ||||
|         { | ||||
|             _out = _detail::write_str(_out, "expected "); | ||||
|             _out = _detail::write_str(_out, error.name()); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             _out = _detail::write_str(_out, error.message()); | ||||
|         } | ||||
|  | ||||
|         _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|     } | ||||
|  | ||||
|     template <typename Location> | ||||
|     void write_recovery_start(const Location& loc) | ||||
|     { | ||||
|         if (_cur_depth <= _opts.max_tree_depth) | ||||
|         { | ||||
|             write_prefix(loc, prefix::event); | ||||
|  | ||||
|             _out = _detail::write_color<_detail::color::yellow, _detail::color::bold>(_out, _opts); | ||||
|             _out = _detail::write_str(_out, "error recovery"); | ||||
|             _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|  | ||||
|             _out = _detail::write_color<_detail::color::yellow>(_out, _opts); | ||||
|             _out = _detail::write_str(_out, ":"); | ||||
|             _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|  | ||||
|             if (_cur_depth == _opts.max_tree_depth) | ||||
|             { | ||||
|                 // Print an ellipsis instead of children. | ||||
|                 _out = _detail::write_str(_out, " "); | ||||
|                 _out = _detail::write_ellipsis(_out, _opts); | ||||
|             } | ||||
|         } | ||||
|         ++_cur_depth; | ||||
|     } | ||||
|  | ||||
|     template <typename Location> | ||||
|     void write_operation(const Location& loc, const char* name) | ||||
|     { | ||||
|         if (_cur_depth > _opts.max_tree_depth) | ||||
|             return; | ||||
|  | ||||
|         write_prefix(loc, prefix::event); | ||||
|  | ||||
|         _out = _detail::write_color<_detail::color::bold>(_out, _opts); | ||||
|         _out = _detail::write_str(_out, "operation"); | ||||
|         _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|  | ||||
|         _out = _detail::write_str(_out, ": "); | ||||
|         _out = _detail::write_str(_out, name); | ||||
|     } | ||||
|  | ||||
|     template <typename Location> | ||||
|     void write_debug(const Location& loc, const char* str) | ||||
|     { | ||||
|         if (_cur_depth > _opts.max_tree_depth) | ||||
|             return; | ||||
|  | ||||
|         write_prefix(loc, prefix::event); | ||||
|  | ||||
|         _out = _detail::write_color<_detail::color::blue, _detail::color::bold>(_out, _opts); | ||||
|         _out = _detail::write_str(_out, "debug"); | ||||
|         _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|  | ||||
|         _out = _detail::write_color<_detail::color::blue>(_out, _opts); | ||||
|         _out = _detail::write_str(_out, ": "); | ||||
|         _out = _detail::write_str(_out, str); | ||||
|         _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|     } | ||||
|  | ||||
|     template <typename Location> | ||||
|     void write_finish(const Location& loc) | ||||
|     { | ||||
|         if (_cur_depth <= _opts.max_tree_depth) | ||||
|             write_prefix(loc, prefix::finish); | ||||
|         --_cur_depth; | ||||
|     } | ||||
|     template <typename Location> | ||||
|     void write_cancel(const Location& loc) | ||||
|     { | ||||
|         if (_cur_depth <= _opts.max_tree_depth) | ||||
|             write_prefix(loc, prefix::cancel); | ||||
|         --_cur_depth; | ||||
|     } | ||||
|  | ||||
|     OutputIt finish() && | ||||
|     { | ||||
|         *_out++ = '\n'; | ||||
|         return _out; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     enum class prefix | ||||
|     { | ||||
|         event, | ||||
|         cancel, | ||||
|         finish, | ||||
|     }; | ||||
|  | ||||
|     template <typename Location> | ||||
|     void write_prefix(const Location& loc, prefix p) | ||||
|     { | ||||
|         const auto use_unicode = _opts.is_set(visualize_use_unicode); | ||||
|  | ||||
|         if (_cur_depth > 0) | ||||
|             *_out++ = '\n'; | ||||
|  | ||||
|         _out = _detail::write_color<_detail::color::faint>(_out, _opts); | ||||
|         _out = _detail::write_format(_out, "%2u:%3u", loc.line_nr(), loc.column_nr()); | ||||
|         _out = _detail::write_str(_out, ": "); | ||||
|         _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|  | ||||
|         if (_cur_depth > 0) | ||||
|         { | ||||
|             for (auto i = 0u; i != _cur_depth - 1; ++i) | ||||
|                 _out = _detail::write_str(_out, use_unicode ? u8"│  " : u8"  "); | ||||
|  | ||||
|             switch (p) | ||||
|             { | ||||
|             case prefix::event: | ||||
|                 _out = _detail::write_str(_out, use_unicode ? u8"├──" : u8"- "); | ||||
|                 break; | ||||
|             case prefix::cancel: | ||||
|                 _out = _detail::write_str(_out, use_unicode ? u8"└" : u8"-"); | ||||
|                 _out = _detail::write_color<_detail::color::yellow>(_out, _opts); | ||||
|                 _out = _detail::write_str(_out, use_unicode ? u8"╳" : u8"x"); | ||||
|                 _out = _detail::write_color<_detail::color::reset>(_out, _opts); | ||||
|                 break; | ||||
|             case prefix::finish: | ||||
|                 _out = _detail::write_str(_out, use_unicode ? u8"┴" : u8"- finish"); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     OutputIt              _out; | ||||
|     visualization_options _opts; | ||||
|  | ||||
|     std::size_t _cur_depth; | ||||
| }; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename OutputIt, typename Input, typename TokenKind = void> | ||||
| class _th | ||||
| { | ||||
| public: | ||||
|     explicit _th(OutputIt out, const Input& input, visualization_options opts = {}) noexcept | ||||
|     : _writer(out, opts), _input(&input), _anchor(input) | ||||
|     { | ||||
|         LEXY_PRECONDITION(opts.max_tree_depth <= visualization_options::max_tree_depth_limit); | ||||
|     } | ||||
|  | ||||
|     class event_handler | ||||
|     { | ||||
|         using iterator = typename lexy::input_reader<Input>::iterator; | ||||
|  | ||||
|     public: | ||||
|         constexpr event_handler(production_info info) : _info(info) {} | ||||
|  | ||||
|         void on(_th&, parse_events::grammar_start, iterator) {} | ||||
|         void on(_th&, parse_events::grammar_finish, lexy::input_reader<Input>&) {} | ||||
|         void on(_th&, parse_events::grammar_cancel, lexy::input_reader<Input>&) {} | ||||
|  | ||||
|         void on(_th& handler, parse_events::production_start, iterator pos) | ||||
|         { | ||||
|             auto loc = handler.get_location(pos); | ||||
|             handler._writer.write_production_start(loc, _info.name); | ||||
|  | ||||
|             // All events for the production are after the initial event. | ||||
|             _previous_anchor.emplace(handler._anchor); | ||||
|             handler._anchor = loc.anchor(); | ||||
|         } | ||||
|         void on(_th& handler, parse_events::production_finish, iterator pos) | ||||
|         { | ||||
|             auto loc = handler.get_location(pos); | ||||
|             handler._writer.write_finish(loc); | ||||
|         } | ||||
|         void on(_th& handler, parse_events::production_cancel, iterator pos) | ||||
|         { | ||||
|             auto loc = handler.get_location(pos); | ||||
|             handler._writer.write_cancel(loc); | ||||
|  | ||||
|             // We've backtracked, so we need to restore the anchor. | ||||
|             handler._anchor = *_previous_anchor; | ||||
|         } | ||||
|  | ||||
|         int on(_th& handler, parse_events::operation_chain_start, iterator pos) | ||||
|         { | ||||
|             auto loc = handler.get_location(pos); | ||||
|             handler._writer.write_production_start(loc, "operation chain"); | ||||
|             return 0; // need to return something | ||||
|         } | ||||
|         template <typename Operation> | ||||
|         void on(_th& handler, parse_events::operation_chain_op, Operation, iterator pos) | ||||
|         { | ||||
|             auto loc = handler.get_location(pos); | ||||
|             handler._writer.write_operation(loc, lexy::production_name<Operation>()); | ||||
|         } | ||||
|         void on(_th& handler, parse_events::operation_chain_finish, int, iterator pos) | ||||
|         { | ||||
|             auto loc = handler.get_location(pos); | ||||
|             handler._writer.write_finish(loc); | ||||
|         } | ||||
|  | ||||
|         template <typename TK> | ||||
|         void on(_th& handler, parse_events::token, TK kind, iterator begin, iterator end) | ||||
|         { | ||||
|             auto loc = handler.get_location(begin); | ||||
|             handler._writer.write_token(loc, token_kind<TokenKind>(kind), | ||||
|                                         lexeme_for<Input>(begin, end)); | ||||
|         } | ||||
|         void on(_th& handler, parse_events::backtracked, iterator begin, iterator end) | ||||
|         { | ||||
|             auto loc = handler.get_location(begin); | ||||
|             handler._writer.write_backtrack(loc, lexeme_for<Input>(begin, end)); | ||||
|         } | ||||
|  | ||||
|         template <typename Error> | ||||
|         void on(_th& handler, parse_events::error, const Error& error) | ||||
|         { | ||||
|             auto loc = handler.get_location(error.position()); | ||||
|             handler._writer.write_error(loc, error); | ||||
|         } | ||||
|  | ||||
|         void on(_th& handler, parse_events::recovery_start, iterator pos) | ||||
|         { | ||||
|             auto loc = handler.get_location(pos); | ||||
|             handler._writer.write_recovery_start(loc); | ||||
|         } | ||||
|         void on(_th& handler, parse_events::recovery_finish, iterator pos) | ||||
|         { | ||||
|             auto loc = handler.get_location(pos); | ||||
|             handler._writer.write_finish(loc); | ||||
|         } | ||||
|         void on(_th& handler, parse_events::recovery_cancel, iterator pos) | ||||
|         { | ||||
|             auto loc = handler.get_location(pos); | ||||
|             handler._writer.write_cancel(loc); | ||||
|         } | ||||
|  | ||||
|         void on(_th& handler, parse_events::debug, iterator pos, const char* str) | ||||
|         { | ||||
|             auto loc = handler.get_location(pos); | ||||
|             handler._writer.write_debug(loc, str); | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         production_info _info; | ||||
|         // The beginning of the previous production. | ||||
|         // If the current production gets canceled, it needs to be restored. | ||||
|         _detail::lazy_init<input_location_anchor<Input>> _previous_anchor; | ||||
|     }; | ||||
|  | ||||
|     template <typename Production, typename State> | ||||
|     using value_callback = _detail::void_value_callback; | ||||
|  | ||||
|     template <typename> | ||||
|     constexpr OutputIt get_result(bool) && | ||||
|     { | ||||
|         return LEXY_MOV(_writer).finish(); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     input_location<Input> get_location(typename lexy::input_reader<Input>::iterator pos) | ||||
|     { | ||||
|         return get_input_location(*_input, pos, _anchor); | ||||
|     } | ||||
|  | ||||
|     _detail::trace_writer<OutputIt, TokenKind> _writer; | ||||
|  | ||||
|     const Input*                 _input; | ||||
|     input_location_anchor<Input> _anchor; | ||||
| }; | ||||
|  | ||||
| template <typename State, typename Input, typename OutputIt, typename TokenKind = void> | ||||
| struct trace_action | ||||
| { | ||||
|     OutputIt              _out; | ||||
|     visualization_options _opts; | ||||
|     State*                _state = nullptr; | ||||
|  | ||||
|     using handler = _th<OutputIt, Input>; | ||||
|     using state   = State; | ||||
|     using input   = Input; | ||||
|  | ||||
|     template <typename> | ||||
|     using result_type = OutputIt; | ||||
|  | ||||
|     constexpr explicit trace_action(OutputIt out, visualization_options opts = {}) | ||||
|     : _out(out), _opts(opts) | ||||
|     {} | ||||
|     template <typename U = State> | ||||
|     constexpr explicit trace_action(U& state, OutputIt out, visualization_options opts = {}) | ||||
|     : _out(out), _opts(opts), _state(&state) | ||||
|     {} | ||||
|  | ||||
|     template <typename Production> | ||||
|     constexpr auto operator()(Production, const Input& input) const | ||||
|     { | ||||
|         auto reader = input.reader(); | ||||
|         return lexy::do_action<Production, result_type>(handler(_out, input, _opts), _state, | ||||
|                                                         reader); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Production, typename TokenKind = void, typename OutputIt, typename Input> | ||||
| OutputIt trace_to(OutputIt out, const Input& input, visualization_options opts = {}) | ||||
| { | ||||
|     return trace_action<void, Input, OutputIt, TokenKind>(out, opts)(Production{}, input); | ||||
| } | ||||
| template <typename Production, typename TokenKind = void, typename OutputIt, typename Input, | ||||
|           typename State> | ||||
| OutputIt trace_to(OutputIt out, const Input& input, State& state, visualization_options opts = {}) | ||||
| { | ||||
|     return trace_action<State, Input, OutputIt, TokenKind>(state, out, opts)(Production{}, input); | ||||
| } | ||||
| template <typename Production, typename TokenKind = void, typename OutputIt, typename Input, | ||||
|           typename State> | ||||
| OutputIt trace_to(OutputIt out, const Input& input, const State& state, | ||||
|                   visualization_options opts = {}) | ||||
| { | ||||
|     return trace_action<const State, Input, OutputIt, TokenKind>(state, out, opts)(Production{}, | ||||
|                                                                                    input); | ||||
| } | ||||
|  | ||||
| template <typename Production, typename TokenKind = void, typename Input> | ||||
| void trace(std::FILE* file, const Input& input, visualization_options opts = {}) | ||||
| { | ||||
|     trace_to<Production, TokenKind>(cfile_output_iterator{file}, input, opts); | ||||
| } | ||||
| template <typename Production, typename TokenKind = void, typename Input, typename State> | ||||
| void trace(std::FILE* file, const Input& input, State& state, visualization_options opts = {}) | ||||
| { | ||||
|     trace_to<Production, TokenKind>(cfile_output_iterator{file}, input, state, opts); | ||||
| } | ||||
| template <typename Production, typename TokenKind = void, typename Input, typename State> | ||||
| void trace(std::FILE* file, const Input& input, const State& state, visualization_options opts = {}) | ||||
| { | ||||
|     trace_to<Production, TokenKind>(cfile_output_iterator{file}, input, state, opts); | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_ACTION_TRACE_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										320
									
								
								dep/lexy/include/lexy/action/validate.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										320
									
								
								dep/lexy/include/lexy/action/validate.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,320 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_ACTION_VALIDATE_HPP_INCLUDED | ||||
| #define LEXY_ACTION_VALIDATE_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/any_ref.hpp> | ||||
| #include <lexy/_detail/lazy_init.hpp> | ||||
| #include <lexy/action/base.hpp> | ||||
| #include <lexy/callback/base.hpp> | ||||
| #include <lexy/callback/container.hpp> | ||||
| #include <lexy/callback/noop.hpp> | ||||
| #include <lexy/error.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| // Convert the callback into an appropriate sink. | ||||
| template <typename Callback> | ||||
| constexpr auto _get_error_sink(const Callback& callback) | ||||
| { | ||||
|     if constexpr (std::is_same_v<Callback, lexy::_noop>) | ||||
|     { | ||||
|         // We collect noop instead, which counts the errors. | ||||
|         return lexy::collect(callback).sink(); | ||||
|     } | ||||
|     else if constexpr (lexy::is_sink<Callback>) | ||||
|     { | ||||
|         // It already is a sink. | ||||
|         return callback.sink(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         static_assert( | ||||
|             std::is_void_v<typename Callback::return_type>, | ||||
|             "need to use `lexy::collect()` to create an error callback that can handle multiple errors"); | ||||
|  | ||||
|         // We need to collect the errors. | ||||
|         return lexy::collect(callback).sink(); | ||||
|     } | ||||
| } | ||||
| template <typename Callback> | ||||
| using _error_sink_t = decltype(_get_error_sink(LEXY_DECLVAL(Callback))); | ||||
|  | ||||
| template <typename ErrorCallback> | ||||
| class validate_result | ||||
| { | ||||
|     using _sink_t = _error_sink_t<ErrorCallback>; | ||||
|  | ||||
| public: | ||||
|     using error_callback = ErrorCallback; | ||||
|     using error_type     = typename _sink_t::return_type; | ||||
|     static_assert(!std::is_void_v<error_type>, "ErrorCallback must not be a void returning sink"); | ||||
|  | ||||
|     constexpr explicit operator bool() const noexcept | ||||
|     { | ||||
|         return is_success(); | ||||
|     } | ||||
|  | ||||
|     constexpr bool is_success() const noexcept | ||||
|     { | ||||
|         return _status == _status_success; | ||||
|     } | ||||
|     constexpr bool is_error() const noexcept | ||||
|     { | ||||
|         return !is_success(); | ||||
|     } | ||||
|     constexpr bool is_recovered_error() const noexcept | ||||
|     { | ||||
|         return _status == _status_recovered; | ||||
|     } | ||||
|     constexpr bool is_fatal_error() const noexcept | ||||
|     { | ||||
|         return _status == _status_fatal; | ||||
|     } | ||||
|  | ||||
|     constexpr std::size_t error_count() const noexcept | ||||
|     { | ||||
|         if constexpr (std::is_same_v<error_type, std::size_t>) | ||||
|             // void-returning callback yields the count only. | ||||
|             return _error; | ||||
|         else | ||||
|             // We assume it's some sort of container otherwise. | ||||
|             return _error.size(); | ||||
|     } | ||||
|  | ||||
|     constexpr const auto& errors() const& noexcept | ||||
|     { | ||||
|         return _error; | ||||
|     } | ||||
|     constexpr auto&& errors() && noexcept | ||||
|     { | ||||
|         return LEXY_MOV(_error); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     constexpr explicit validate_result(bool did_recover, error_type&& error) | ||||
|     : _error(LEXY_MOV(error)), _status() | ||||
|     { | ||||
|         if (error_count() == 0u) | ||||
|             _status = _status_success; | ||||
|         else if (did_recover) | ||||
|             _status = _status_recovered; | ||||
|         else | ||||
|             _status = _status_fatal; | ||||
|     } | ||||
|  | ||||
|     error_type _error; | ||||
|     enum | ||||
|     { | ||||
|         _status_success, | ||||
|         _status_recovered, | ||||
|         _status_fatal, | ||||
|     } _status; | ||||
|  | ||||
|     template <typename Reader> | ||||
|     friend class _vh; | ||||
| }; | ||||
| } // namespace lexy | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename Reader> | ||||
| struct _validate_callbacks | ||||
| { | ||||
|     _detail::any_ref  sink; | ||||
|     _detail::any_cref input; | ||||
|  | ||||
|     void (*generic)(_detail::any_ref sink, production_info info, _detail::any_cref input, | ||||
|                     typename Reader::iterator begin, const error<Reader, void>& error); | ||||
|     void (*literal)(_detail::any_ref sink, production_info info, _detail::any_cref input, | ||||
|                     typename Reader::iterator begin, const error<Reader, expected_literal>& error); | ||||
|     void (*keyword)(_detail::any_ref sink, production_info info, _detail::any_cref input, | ||||
|                     typename Reader::iterator begin, const error<Reader, expected_keyword>& error); | ||||
|     void (*char_class)(_detail::any_ref sink, production_info info, _detail::any_cref input, | ||||
|                        typename Reader::iterator                 begin, | ||||
|                        const error<Reader, expected_char_class>& error); | ||||
|  | ||||
|     template <typename Input, typename Sink> | ||||
|     constexpr _validate_callbacks(const _detail::any_holder<const Input*>& input, | ||||
|                                   _detail::any_holder<Sink>&               sink) | ||||
|     : sink(&sink), input(&input), | ||||
|       generic([](_detail::any_ref sink, production_info info, _detail::any_cref input, | ||||
|                  typename Reader::iterator begin, const error<Reader, void>& error) { | ||||
|           lexy::error_context err_ctx(info, *input->template get<const Input*>(), begin); | ||||
|           sink->template get<Sink>()(err_ctx, LEXY_FWD(error)); | ||||
|       }), | ||||
|       literal([](_detail::any_ref sink, production_info info, _detail::any_cref input, | ||||
|                  typename Reader::iterator begin, const error<Reader, expected_literal>& error) { | ||||
|           lexy::error_context err_ctx(info, *input->template get<const Input*>(), begin); | ||||
|           sink->template get<Sink>()(err_ctx, LEXY_FWD(error)); | ||||
|       }), | ||||
|       keyword([](_detail::any_ref sink, production_info info, _detail::any_cref input, | ||||
|                  typename Reader::iterator begin, const error<Reader, expected_keyword>& error) { | ||||
|           lexy::error_context err_ctx(info, *input->template get<const Input*>(), begin); | ||||
|           sink->template get<Sink>()(err_ctx, LEXY_FWD(error)); | ||||
|       }), | ||||
|       char_class([](_detail::any_ref sink, production_info info, _detail::any_cref input, | ||||
|                     typename Reader::iterator                 begin, | ||||
|                     const error<Reader, expected_char_class>& error) { | ||||
|           lexy::error_context err_ctx(info, *input->template get<const Input*>(), begin); | ||||
|           sink->template get<Sink>()(err_ctx, LEXY_FWD(error)); | ||||
|       }) | ||||
|     {} | ||||
| }; | ||||
|  | ||||
| template <typename Reader> | ||||
| class _vh | ||||
| { | ||||
| public: | ||||
|     template <typename Input, typename Sink> | ||||
|     constexpr explicit _vh(const _detail::any_holder<const Input*>& input, | ||||
|                            _detail::any_holder<Sink>&               sink) | ||||
|     : _cb(input, sink) | ||||
|     {} | ||||
|  | ||||
|     class event_handler | ||||
|     { | ||||
|         using iterator = typename Reader::iterator; | ||||
|  | ||||
|     public: | ||||
|         constexpr event_handler(production_info info) : _begin(), _info(info) {} | ||||
|  | ||||
|         constexpr void on(_vh& handler, parse_events::production_start, iterator pos) | ||||
|         { | ||||
|             _begin = pos; | ||||
|  | ||||
|             _prev        = handler._top; | ||||
|             handler._top = this; | ||||
|         } | ||||
|         constexpr void on(_vh& handler, parse_events::production_finish, iterator) | ||||
|         { | ||||
|             handler._top = _prev; | ||||
|         } | ||||
|         constexpr void on(_vh& handler, parse_events::production_cancel, iterator) | ||||
|         { | ||||
|             handler._top = _prev; | ||||
|         } | ||||
|  | ||||
|         template <typename R, typename Tag> | ||||
|         constexpr void on(_vh& handler, parse_events::error, const error<R, Tag>& error) | ||||
|         { | ||||
|             handler._cb.generic(handler._cb.sink, get_info(), handler._cb.input, _begin, error); | ||||
|         } | ||||
|         template <typename R> | ||||
|         constexpr void on(_vh& handler, parse_events::error, const error<R, void>& error) | ||||
|         { | ||||
|             handler._cb.generic(handler._cb.sink, get_info(), handler._cb.input, _begin, error); | ||||
|         } | ||||
|         template <typename R> | ||||
|         constexpr void on(_vh&                              handler, parse_events::error, | ||||
|                           const error<R, expected_literal>& error) | ||||
|         { | ||||
|             handler._cb.literal(handler._cb.sink, get_info(), handler._cb.input, _begin, error); | ||||
|         } | ||||
|         template <typename R> | ||||
|         constexpr void on(_vh&                              handler, parse_events::error, | ||||
|                           const error<R, expected_keyword>& error) | ||||
|         { | ||||
|             handler._cb.keyword(handler._cb.sink, get_info(), handler._cb.input, _begin, error); | ||||
|         } | ||||
|         template <typename R> | ||||
|         constexpr void on(_vh&                                 handler, parse_events::error, | ||||
|                           const error<R, expected_char_class>& error) | ||||
|         { | ||||
|             handler._cb.char_class(handler._cb.sink, get_info(), handler._cb.input, _begin, error); | ||||
|         } | ||||
|  | ||||
|         template <typename Event, typename... Args> | ||||
|         constexpr auto on(_vh&, Event, const Args&...) | ||||
|         { | ||||
|             return 0; // operation_chain_start must return something | ||||
|         } | ||||
|  | ||||
|         constexpr iterator production_begin() const | ||||
|         { | ||||
|             return _begin; | ||||
|         } | ||||
|  | ||||
|         constexpr production_info get_info() const | ||||
|         { | ||||
|             auto cur = this; | ||||
|             while (cur->_info.is_transparent && cur->_prev != nullptr) | ||||
|                 cur = cur->_prev; | ||||
|             return cur->_info; | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         iterator        _begin; | ||||
|         production_info _info; | ||||
|         event_handler*  _prev = nullptr; | ||||
|     }; | ||||
|  | ||||
|     template <typename Production, typename State> | ||||
|     using value_callback = _detail::void_value_callback; | ||||
|  | ||||
|     template <typename Result> | ||||
|     constexpr auto get_result(bool rule_parse_result) && | ||||
|     { | ||||
|         using sink_t = _error_sink_t<typename Result::error_callback>; | ||||
|         return Result(rule_parse_result, LEXY_MOV(_cb.sink->template get<sink_t>()).finish()); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     _validate_callbacks<Reader> _cb; | ||||
|     event_handler*              _top = nullptr; | ||||
| }; | ||||
|  | ||||
| template <typename State, typename Input, typename ErrorCallback> | ||||
| struct validate_action | ||||
| { | ||||
|     const ErrorCallback* _callback; | ||||
|     State*               _state = nullptr; | ||||
|  | ||||
|     using handler = _vh<lexy::input_reader<Input>>; | ||||
|     using state   = State; | ||||
|     using input   = Input; | ||||
|  | ||||
|     template <typename> | ||||
|     using result_type = validate_result<ErrorCallback>; | ||||
|  | ||||
|     constexpr explicit validate_action(const ErrorCallback& callback) : _callback(&callback) {} | ||||
|     template <typename U = State> | ||||
|     constexpr explicit validate_action(U& state, const ErrorCallback& callback) | ||||
|     : _callback(&callback), _state(&state) | ||||
|     {} | ||||
|  | ||||
|     template <typename Production> | ||||
|     constexpr auto operator()(Production, const Input& input) const | ||||
|     { | ||||
|         _detail::any_holder input_holder(&input); | ||||
|         _detail::any_holder sink(_get_error_sink(*_callback)); | ||||
|         auto                reader = input.reader(); | ||||
|         return lexy::do_action<Production, result_type>(handler(input_holder, sink), _state, | ||||
|                                                         reader); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Production, typename Input, typename ErrorCallback> | ||||
| constexpr auto validate(const Input&         input, | ||||
|                         const ErrorCallback& callback) -> validate_result<ErrorCallback> | ||||
| { | ||||
|     return validate_action<void, Input, ErrorCallback>(callback)(Production{}, input); | ||||
| } | ||||
|  | ||||
| template <typename Production, typename Input, typename State, typename ErrorCallback> | ||||
| constexpr auto validate(const Input& input, State& state, | ||||
|                         const ErrorCallback& callback) -> validate_result<ErrorCallback> | ||||
| { | ||||
|     return validate_action<State, Input, ErrorCallback>(state, callback)(Production{}, input); | ||||
| } | ||||
| template <typename Production, typename Input, typename State, typename ErrorCallback> | ||||
| constexpr auto validate(const Input& input, const State& state, | ||||
|                         const ErrorCallback& callback) -> validate_result<ErrorCallback> | ||||
| { | ||||
|     return validate_action<const State, Input, ErrorCallback>(state, callback)(Production{}, input); | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_ACTION_VALIDATE_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										23
									
								
								dep/lexy/include/lexy/callback.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								dep/lexy/include/lexy/callback.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/adapter.hpp> | ||||
| #include <lexy/callback/aggregate.hpp> | ||||
| #include <lexy/callback/base.hpp> | ||||
| #include <lexy/callback/bind.hpp> | ||||
| #include <lexy/callback/bit_cast.hpp> | ||||
| #include <lexy/callback/composition.hpp> | ||||
| #include <lexy/callback/constant.hpp> | ||||
| #include <lexy/callback/container.hpp> | ||||
| #include <lexy/callback/fold.hpp> | ||||
| #include <lexy/callback/forward.hpp> | ||||
| #include <lexy/callback/integer.hpp> | ||||
| #include <lexy/callback/noop.hpp> | ||||
| #include <lexy/callback/object.hpp> | ||||
| #include <lexy/callback/string.hpp> | ||||
|  | ||||
| #endif // LEXY_CALLBACK_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										168
									
								
								dep/lexy/include/lexy/callback/adapter.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								dep/lexy/include/lexy/callback/adapter.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,168 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_ADAPTER_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_ADAPTER_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/base.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename ReturnType, typename... Fns> | ||||
| struct _callback : _overloaded<Fns...> | ||||
| { | ||||
|     using return_type = ReturnType; | ||||
|  | ||||
|     constexpr explicit _callback(Fns... fns) : _overloaded<Fns...>(LEXY_MOV(fns)...) {} | ||||
| }; | ||||
|  | ||||
| template <typename ReturnType, typename... Fns> | ||||
| struct _callback_with_state : _overloaded<Fns...> | ||||
| { | ||||
|     using return_type = ReturnType; | ||||
|  | ||||
|     template <typename State> | ||||
|     struct _with_state | ||||
|     { | ||||
|         const _callback_with_state& _cb; | ||||
|         State&                      _state; | ||||
|  | ||||
|         template <typename... Args> | ||||
|         constexpr return_type operator()(Args&&... args) const&& | ||||
|         { | ||||
|             return _cb(_state, LEXY_FWD(args)...); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     constexpr explicit _callback_with_state(Fns... fns) : _overloaded<Fns...>(LEXY_MOV(fns)...) {} | ||||
|  | ||||
|     template <typename State> | ||||
|     constexpr auto operator[](State& state) const | ||||
|     { | ||||
|         return _with_state<State>{*this, state}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// Creates a callback. | ||||
| template <typename... Fns> | ||||
| constexpr auto callback(Fns&&... fns) | ||||
| { | ||||
|     if constexpr ((lexy::is_callback<std::decay_t<Fns>> && ...)) | ||||
|         return _callback<std::common_type_t<typename std::decay_t<Fns>::return_type...>, | ||||
|                          std::decay_t<Fns>...>(LEXY_FWD(fns)...); | ||||
|     else | ||||
|         return _callback<void, std::decay_t<Fns>...>(LEXY_FWD(fns)...); | ||||
| } | ||||
| template <typename ReturnType, typename... Fns> | ||||
| constexpr auto callback(Fns&&... fns) | ||||
| { | ||||
|     return _callback<ReturnType, std::decay_t<Fns>...>(LEXY_FWD(fns)...); | ||||
| } | ||||
|  | ||||
| /// Creates a callback that also receives the parse state. | ||||
| template <typename... Fns> | ||||
| constexpr auto callback_with_state(Fns&&... fns) | ||||
| { | ||||
|     if constexpr ((lexy::is_callback<std::decay_t<Fns>> && ...)) | ||||
|         return _callback_with_state<std::common_type_t<typename std::decay_t<Fns>::return_type...>, | ||||
|                                     std::decay_t<Fns>...>(LEXY_FWD(fns)...); | ||||
|     else | ||||
|         return _callback_with_state<void, std::decay_t<Fns>...>(LEXY_FWD(fns)...); | ||||
| } | ||||
| template <typename ReturnType, typename... Fns> | ||||
| constexpr auto callback_with_state(Fns&&... fns) | ||||
| { | ||||
|     return _callback_with_state<ReturnType, std::decay_t<Fns>...>(LEXY_FWD(fns)...); | ||||
| } | ||||
|  | ||||
| template <typename Sink> | ||||
| struct _cb_from_sink | ||||
| { | ||||
|     Sink _sink; | ||||
|  | ||||
|     using _cb         = lexy::sink_callback<Sink>; | ||||
|     using return_type = typename _cb::return_type; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const -> decltype((LEXY_DECLVAL(_cb&)(LEXY_FWD(args)), | ||||
|                                                                  ..., LEXY_DECLVAL(_cb&&).finish())) | ||||
|     { | ||||
|         auto cb = _sink.sink(); | ||||
|         (cb(LEXY_FWD(args)), ...); | ||||
|         return LEXY_MOV(cb).finish(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// Creates a callback that forwards all arguments to the sink. | ||||
| template <typename Sink, typename = lexy::sink_callback<Sink>> | ||||
| constexpr auto callback(Sink&& sink) | ||||
| { | ||||
|     return _cb_from_sink<std::decay_t<Sink>>{LEXY_FWD(sink)}; | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename MemFn> | ||||
| struct _mem_fn_traits // MemFn is member data | ||||
| { | ||||
|     using return_type = MemFn; | ||||
| }; | ||||
|  | ||||
| #define LEXY_MAKE_MEM_FN_TRAITS(...)                                                               \ | ||||
|     template <typename ReturnType, typename... Args>                                               \ | ||||
|     struct _mem_fn_traits<ReturnType(Args...) __VA_ARGS__>                                         \ | ||||
|     {                                                                                              \ | ||||
|         using return_type = ReturnType;                                                            \ | ||||
|     };                                                                                             \ | ||||
|     template <typename ReturnType, typename... Args>                                               \ | ||||
|     struct _mem_fn_traits<ReturnType(Args..., ...) __VA_ARGS__>                                    \ | ||||
|     {                                                                                              \ | ||||
|         using return_type = ReturnType;                                                            \ | ||||
|     }; | ||||
|  | ||||
| #define LEXY_MAKE_MEM_FN_TRAITS_CV(...)                                                            \ | ||||
|     LEXY_MAKE_MEM_FN_TRAITS(__VA_ARGS__)                                                           \ | ||||
|     LEXY_MAKE_MEM_FN_TRAITS(const __VA_ARGS__)                                                     \ | ||||
|     LEXY_MAKE_MEM_FN_TRAITS(volatile __VA_ARGS__)                                                  \ | ||||
|     LEXY_MAKE_MEM_FN_TRAITS(const volatile __VA_ARGS__) | ||||
|  | ||||
| #define LEXY_MAKE_MEM_FN_TRAITS_CV_REF(...)                                                        \ | ||||
|     LEXY_MAKE_MEM_FN_TRAITS_CV(__VA_ARGS__)                                                        \ | ||||
|     LEXY_MAKE_MEM_FN_TRAITS_CV(&__VA_ARGS__)                                                       \ | ||||
|     LEXY_MAKE_MEM_FN_TRAITS_CV(&&__VA_ARGS__) | ||||
|  | ||||
| LEXY_MAKE_MEM_FN_TRAITS_CV_REF() | ||||
| LEXY_MAKE_MEM_FN_TRAITS_CV_REF(noexcept) | ||||
|  | ||||
| #undef LEXY_MAKE_MEM_FN_TRAITS_CV_REF | ||||
| #undef LEXY_MAKE_MEM_FN_TRAITS_CV | ||||
| #undef LEXY_MAKE_MEM_FN_TRAITS | ||||
|  | ||||
| template <typename Fn> | ||||
| struct _mem_fn; | ||||
| template <typename MemFn, typename T> | ||||
| struct _mem_fn<MemFn T::*> | ||||
| { | ||||
|     MemFn T::*_fn; | ||||
|  | ||||
|     using return_type = typename _mem_fn_traits<MemFn>::return_type; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const | ||||
|         -> decltype(_detail::_mem_invoker<MemFn T::*>::invoke(_fn, LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return _detail::_mem_invoker<MemFn T::*>::invoke(_fn, LEXY_FWD(args)...); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// Creates a callback from a member function. | ||||
| template <typename MemFn, typename T> | ||||
| constexpr auto mem_fn(MemFn T::*fn) | ||||
| { | ||||
|     return _mem_fn<MemFn T::*>{fn}; | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_ADAPTER_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										72
									
								
								dep/lexy/include/lexy/callback/aggregate.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								dep/lexy/include/lexy/callback/aggregate.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_AGGREGATE_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_AGGREGATE_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/base.hpp> | ||||
| #include <lexy/dsl/member.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| struct nullopt; | ||||
|  | ||||
| template <typename T> | ||||
| struct _as_aggregate | ||||
| { | ||||
|     using return_type = T; | ||||
|     static_assert(std::is_aggregate_v<return_type>); | ||||
|  | ||||
|     constexpr T operator()(lexy::nullopt&&) const | ||||
|     { | ||||
|         return {}; | ||||
|     } | ||||
|     constexpr T operator()(T&& result) const | ||||
|     { | ||||
|         return LEXY_MOV(result); | ||||
|     } | ||||
|  | ||||
|     template <typename Fn, typename Value, typename... Tail> | ||||
|     constexpr T operator()(lexy::member<Fn>, Value&& value, Tail&&... tail) const | ||||
|     { | ||||
|         T result{}; | ||||
|         Fn{}(result, LEXY_FWD(value)); | ||||
|         return (*this)(LEXY_MOV(result), LEXY_FWD(tail)...); | ||||
|     } | ||||
|     template <typename Fn, typename Value, typename... Tail> | ||||
|     constexpr T operator()(T&& result, lexy::member<Fn>, Value&& value, Tail&&... tail) const | ||||
|     { | ||||
|         Fn{}(result, LEXY_FWD(value)); | ||||
|         return (*this)(LEXY_MOV(result), LEXY_FWD(tail)...); | ||||
|     } | ||||
|  | ||||
|     struct _sink | ||||
|     { | ||||
|         T _result{}; | ||||
|  | ||||
|         using return_type = T; | ||||
|  | ||||
|         template <typename Fn, typename Value> | ||||
|         constexpr void operator()(lexy::member<Fn>, Value&& value) | ||||
|         { | ||||
|             Fn()(_result, LEXY_FWD(value)); | ||||
|         } | ||||
|  | ||||
|         constexpr auto&& finish() && | ||||
|         { | ||||
|             return LEXY_MOV(_result); | ||||
|         } | ||||
|     }; | ||||
|     constexpr auto sink() const | ||||
|     { | ||||
|         return _sink{}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// A callback with sink that creates an aggregate. | ||||
| template <typename T> | ||||
| constexpr auto as_aggregate = _as_aggregate<T>{}; | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_AGGREGATE_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										91
									
								
								dep/lexy/include/lexy/callback/base.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								dep/lexy/include/lexy/callback/base.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_BASE_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_BASE_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/config.hpp> | ||||
| #include <lexy/_detail/detect.hpp> | ||||
| #include <lexy/_detail/invoke.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename T> | ||||
| using _detect_callback = typename T::return_type; | ||||
| template <typename T> | ||||
| constexpr bool is_callback = _detail::is_detected<_detect_callback, T>; | ||||
|  | ||||
| template <typename T, typename... Args> | ||||
| using _detect_callback_for = decltype(LEXY_DECLVAL(const T)(LEXY_DECLVAL(Args)...)); | ||||
| template <typename T, typename... Args> | ||||
| constexpr bool is_callback_for | ||||
|     = _detail::is_detected<_detect_callback_for, std::decay_t<T>, Args...>; | ||||
|  | ||||
| template <typename T, typename State> | ||||
| using _detect_callback_state = decltype(LEXY_DECLVAL(const T)[LEXY_DECLVAL(State&)]); | ||||
| template <typename T, typename State> | ||||
| constexpr bool is_callback_state | ||||
|     = _detail::is_detected<_detect_callback_state, T, std::decay_t<State>>; | ||||
|  | ||||
| template <typename T, typename State, typename... Args> | ||||
| using _detect_callback_with_state_for | ||||
|     = decltype(LEXY_DECLVAL(const T)[LEXY_DECLVAL(State&)](LEXY_DECLVAL(Args)...)); | ||||
| template <typename T, typename State, typename... Args> | ||||
| constexpr bool is_callback_with_state_for | ||||
|     = _detail::is_detected<_detect_callback_with_state_for, std::decay_t<T>, State, Args...>; | ||||
|  | ||||
| /// Returns the type of the `.sink()` function. | ||||
| template <typename Sink, typename... Args> | ||||
| using sink_callback = decltype(LEXY_DECLVAL(Sink).sink(LEXY_DECLVAL(Args)...)); | ||||
|  | ||||
| template <typename T, typename... Args> | ||||
| using _detect_sink_callback_for = decltype(LEXY_DECLVAL(T&)(LEXY_DECLVAL(Args)...)); | ||||
| template <typename T, typename... Args> | ||||
| constexpr bool is_sink_callback_for | ||||
|     = _detail::is_detected<_detect_sink_callback_for, std::decay_t<T>, Args...>; | ||||
|  | ||||
| template <typename T, typename... Args> | ||||
| using _detect_sink = decltype(LEXY_DECLVAL(const T).sink(LEXY_DECLVAL(Args)...).finish()); | ||||
| template <typename T, typename... Args> | ||||
| constexpr bool is_sink = _detail::is_detected<_detect_sink, T, Args...>; | ||||
| } // namespace lexy | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename Fn> | ||||
| struct _fn_holder | ||||
| { | ||||
|     Fn fn; | ||||
|  | ||||
|     constexpr explicit _fn_holder(Fn fn) : fn(fn) {} | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const -> decltype(_detail::invoke(fn, | ||||
|                                                                                 LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return _detail::invoke(fn, LEXY_FWD(args)...); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Fn> | ||||
| using _fn_as_base = std::conditional_t<std::is_class_v<Fn>, Fn, _fn_holder<Fn>>; | ||||
|  | ||||
| template <typename... Fns> | ||||
| struct _overloaded : _fn_as_base<Fns>... | ||||
| { | ||||
|     constexpr explicit _overloaded(Fns... fns) : _fn_as_base<Fns>(LEXY_MOV(fns))... {} | ||||
|  | ||||
|     using _fn_as_base<Fns>::operator()...; | ||||
| }; | ||||
|  | ||||
| template <typename... Op> | ||||
| constexpr auto _make_overloaded(Op&&... op) | ||||
| { | ||||
|     if constexpr (sizeof...(Op) == 1) | ||||
|         return (LEXY_FWD(op), ...); | ||||
|     else | ||||
|         return _overloaded(LEXY_FWD(op)...); | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_BASE_HPP_INCLUDED | ||||
							
								
								
									
										385
									
								
								dep/lexy/include/lexy/callback/bind.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										385
									
								
								dep/lexy/include/lexy/callback/bind.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,385 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_BIND_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_BIND_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/tuple.hpp> | ||||
| #include <lexy/callback/base.hpp> | ||||
|  | ||||
| //=== placeholder details ===// | ||||
| namespace lexy::_detail | ||||
| { | ||||
| struct placeholder_base | ||||
| {}; | ||||
| template <typename T> | ||||
| constexpr auto is_placeholder = std::is_base_of_v<placeholder_base, T>; | ||||
|  | ||||
| template <typename BoundArg, typename State, typename... Args> | ||||
| constexpr decltype(auto) expand_bound_arg(const BoundArg& bound, State& state, | ||||
|                                           const _detail::tuple<Args...>& actual_args) | ||||
| { | ||||
|     if constexpr (is_placeholder<std::decay_t<BoundArg>>) | ||||
|         return bound(state, actual_args); | ||||
|     else | ||||
|         return bound; | ||||
| } | ||||
|  | ||||
| struct all_values_placeholder | ||||
| {}; | ||||
|  | ||||
| struct no_bind_state | ||||
| {}; | ||||
|  | ||||
| template <std::size_t Idx, typename Fn, typename... BoundArgs, typename State, | ||||
|           typename... ActualArgs, std::size_t... ActualIdx, typename... ProducedArgs> | ||||
| constexpr decltype(auto) _invoke_bound(Fn&& fn, const _detail::tuple<BoundArgs...>& bound_args, | ||||
|                                        State&                               state, | ||||
|                                        const _detail::tuple<ActualArgs...>& actual_args, | ||||
|                                        _detail::index_sequence<ActualIdx...>, | ||||
|                                        ProducedArgs&&... produced_args) | ||||
| { | ||||
|     if constexpr (Idx == sizeof...(BoundArgs)) | ||||
|     { | ||||
|         (void)bound_args; | ||||
|         (void)state; | ||||
|         (void)actual_args; | ||||
|         return LEXY_FWD(fn)(LEXY_FWD(produced_args)...); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         using bound_arg_t | ||||
|             = std::decay_t<typename _detail::tuple<BoundArgs...>::template element_type<Idx>>; | ||||
|         if constexpr (std::is_same_v<bound_arg_t, all_values_placeholder>) | ||||
|         { | ||||
|             return _invoke_bound<Idx + 1>(LEXY_FWD(fn), bound_args, state, actual_args, | ||||
|                                           actual_args.index_sequence(), LEXY_FWD(produced_args)..., | ||||
|                                           // Expand to all actual arguments. | ||||
|                                           LEXY_FWD(actual_args.template get<ActualIdx>())...); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return _invoke_bound<Idx + 1>(LEXY_FWD(fn), bound_args, state, actual_args, | ||||
|                                           actual_args.index_sequence(), LEXY_FWD(produced_args)..., | ||||
|                                           // Expand the currently bound argument | ||||
|                                           expand_bound_arg(bound_args.template get<Idx>(), state, | ||||
|                                                            actual_args)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| template <typename Fn, typename... BoundArgs, std::size_t... Idx, typename State, | ||||
|           typename... Args> | ||||
| constexpr decltype(auto) invoke_bound(Fn&&                                fn, // | ||||
|                                       const _detail::tuple<BoundArgs...>& bound_args, | ||||
|                                       _detail::index_sequence<Idx...>, // | ||||
|                                       State& state, Args&&... args) | ||||
| { | ||||
|     auto actual_args = _detail::forward_as_tuple(LEXY_FWD(args)...); | ||||
|     if constexpr ((_detail::is_decayed_same<BoundArgs, _detail::all_values_placeholder> || ...)) | ||||
|     { | ||||
|         // If we're having the placeholder we need to recursively expand every argument. | ||||
|         return _invoke_bound<0>(LEXY_FWD(fn), bound_args, state, actual_args, | ||||
|                                 actual_args.index_sequence()); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // If we're not having the all_values_placeholder, every placeholder expands to a single | ||||
|         // argument. We can thus expand it easily by mapping each value of bound args to the actual | ||||
|         // argument. | ||||
|         return LEXY_FWD(fn)( | ||||
|             expand_bound_arg(bound_args.template get<Idx>(), state, actual_args)...); | ||||
|     } | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| //=== placeholders ===// | ||||
| namespace lexy | ||||
| { | ||||
| /// Placeholder for bind that expands to all values produced by the rule. | ||||
| constexpr auto values = _detail::all_values_placeholder{}; | ||||
|  | ||||
| struct nullopt; | ||||
|  | ||||
| struct _default | ||||
| { | ||||
|     template <typename T, typename = std::enable_if_t<std::is_default_constructible_v<T>>> | ||||
|     constexpr operator T() const noexcept | ||||
|     { | ||||
|         return T(); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <std::size_t N, typename T, typename Fn> | ||||
| struct _nth_value : _detail::placeholder_base // fallback + map | ||||
| { | ||||
|     LEXY_EMPTY_MEMBER T  _fallback; | ||||
|     LEXY_EMPTY_MEMBER Fn _fn; | ||||
|  | ||||
|     template <typename State, typename... Args> | ||||
|     LEXY_FORCE_INLINE constexpr decltype(auto) operator()(State&, | ||||
|                                                           const _detail::tuple<Args...>& args) const | ||||
|     { | ||||
|         if constexpr (N > sizeof...(Args)) | ||||
|             return _fallback; // Argument is missing. | ||||
|         else | ||||
|         { | ||||
|             using arg_t = typename _detail::tuple<Args...>::template element_type<N - 1>; | ||||
|             if constexpr (_detail::is_decayed_same<arg_t, nullopt>) | ||||
|                 return _fallback; // Argument is nullopt. | ||||
|             else | ||||
|                 return _detail::invoke(_fn, args.template get<N - 1>()); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| template <std::size_t N, typename T> | ||||
| struct _nth_value<N, T, void> : _detail::placeholder_base // fallback only | ||||
| { | ||||
|     LEXY_EMPTY_MEMBER T _fallback; | ||||
|  | ||||
|     template <typename State, typename... Args> | ||||
|     LEXY_FORCE_INLINE constexpr decltype(auto) operator()(State&, | ||||
|                                                           const _detail::tuple<Args...>& args) const | ||||
|     { | ||||
|         if constexpr (N > sizeof...(Args)) | ||||
|             return _fallback; // Argument is missing. | ||||
|         else | ||||
|         { | ||||
|             using arg_t = typename _detail::tuple<Args...>::template element_type<N - 1>; | ||||
|             if constexpr (_detail::is_decayed_same<arg_t, nullopt>) | ||||
|                 return _fallback; // Argument is nullopt. | ||||
|             else | ||||
|                 return args.template get<N - 1>(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template <typename Fn> | ||||
|     constexpr auto map(Fn&& fn) const | ||||
|     { | ||||
|         return _nth_value<N, T, std::decay_t<Fn>>{{}, _fallback, LEXY_FWD(fn)}; | ||||
|     } | ||||
| }; | ||||
| template <std::size_t N, typename Fn> | ||||
| struct _nth_value<N, void, Fn> : _detail::placeholder_base // map only | ||||
| { | ||||
|     LEXY_EMPTY_MEMBER Fn _fn; | ||||
|  | ||||
|     template <typename State, typename... Args> | ||||
|     LEXY_FORCE_INLINE constexpr decltype(auto) operator()(State&, | ||||
|                                                           const _detail::tuple<Args...>& args) const | ||||
|     { | ||||
|         static_assert(N <= sizeof...(Args), "not enough arguments for nth_value<N>"); | ||||
|         return _detail::invoke(_fn, args.template get<N - 1>()); | ||||
|     } | ||||
|  | ||||
|     template <typename Arg> | ||||
|     constexpr auto operator||(Arg&& fallback) const | ||||
|     { | ||||
|         return _nth_value<N, std::decay_t<Arg>, Fn>{{}, LEXY_FWD(fallback), _fn}; | ||||
|     } | ||||
|     template <typename Arg> | ||||
|     constexpr auto or_(Arg&& fallback) const | ||||
|     { | ||||
|         return *this || LEXY_FWD(fallback); | ||||
|     } | ||||
|  | ||||
|     constexpr auto or_default() const | ||||
|     { | ||||
|         return *this || _default{}; | ||||
|     } | ||||
| }; | ||||
| template <std::size_t N> | ||||
| struct _nth_value<N, void, void> : _detail::placeholder_base | ||||
| { | ||||
|     // I'm sorry, but this is for consistency with std::bind. | ||||
|     static_assert(N > 0, "values are 1-indexed"); | ||||
|  | ||||
|     template <typename State, typename... Args> | ||||
|     LEXY_FORCE_INLINE constexpr decltype(auto) operator()(State&, | ||||
|                                                           const _detail::tuple<Args...>& args) const | ||||
|     { | ||||
|         static_assert(N <= sizeof...(Args), "not enough arguments for nth_value<N>"); | ||||
|         return args.template get<N - 1>(); | ||||
|     } | ||||
|  | ||||
|     template <typename Arg> | ||||
|     constexpr auto operator||(Arg&& fallback) const | ||||
|     { | ||||
|         return _nth_value<N, std::decay_t<Arg>, void>{{}, LEXY_FWD(fallback)}; | ||||
|     } | ||||
|     template <typename Arg> | ||||
|     constexpr auto or_(Arg&& fallback) const | ||||
|     { | ||||
|         return *this || LEXY_FWD(fallback); | ||||
|     } | ||||
|  | ||||
|     constexpr auto or_default() const | ||||
|     { | ||||
|         return *this || _default{}; | ||||
|     } | ||||
|  | ||||
|     template <typename Fn> | ||||
|     constexpr auto map(Fn&& fn) const | ||||
|     { | ||||
|         return _nth_value<N, void, std::decay_t<Fn>>{{}, LEXY_FWD(fn)}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// Placeholder for bind that expands to the nth value produced by the rule. | ||||
| template <std::size_t N> | ||||
| constexpr auto nth_value = _nth_value<N, void, void>{}; | ||||
|  | ||||
| inline namespace placeholders | ||||
| { | ||||
|     constexpr auto _1 = nth_value<1>; | ||||
|     constexpr auto _2 = nth_value<2>; | ||||
|     constexpr auto _3 = nth_value<3>; | ||||
|     constexpr auto _4 = nth_value<4>; | ||||
|     constexpr auto _5 = nth_value<5>; | ||||
|     constexpr auto _6 = nth_value<6>; | ||||
|     constexpr auto _7 = nth_value<7>; | ||||
|     constexpr auto _8 = nth_value<8>; | ||||
| } // namespace placeholders | ||||
|  | ||||
| template <typename Fn> | ||||
| struct _parse_state : _detail::placeholder_base | ||||
| { | ||||
|     LEXY_EMPTY_MEMBER Fn _fn; | ||||
|  | ||||
|     template <typename State, typename... Args> | ||||
|     constexpr decltype(auto) operator()(State& state, const _detail::tuple<Args...>&) const | ||||
|     { | ||||
|         static_assert(!std::is_same_v<State, _detail::no_bind_state>, | ||||
|                       "lexy::parse_state requires that a state is passed to lexy::parse()"); | ||||
|         return _detail::invoke(_fn, state); | ||||
|     } | ||||
| }; | ||||
| template <> | ||||
| struct _parse_state<void> : _detail::placeholder_base | ||||
| { | ||||
|     template <typename State, typename... Args> | ||||
|     constexpr decltype(auto) operator()(State& state, const _detail::tuple<Args...>&) const | ||||
|     { | ||||
|         static_assert(!std::is_same_v<State, _detail::no_bind_state>, | ||||
|                       "lexy::parse_state requires that a state is passed to lexy::parse()"); | ||||
|         return state; | ||||
|     } | ||||
|  | ||||
|     template <typename Fn> | ||||
|     constexpr auto map(Fn&& fn) const | ||||
|     { | ||||
|         return _parse_state<std::decay_t<Fn>>{{}, LEXY_FWD(fn)}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| constexpr auto parse_state = _parse_state<void>{}; | ||||
| } // namespace lexy | ||||
|  | ||||
| //=== bind ===// | ||||
| namespace lexy | ||||
| { | ||||
| template <typename Callback, typename... BoundArgs> | ||||
| struct _bound_cb | ||||
| { | ||||
|     LEXY_EMPTY_MEMBER Callback _callback; | ||||
|     LEXY_EMPTY_MEMBER _detail::tuple<BoundArgs...> _bound_args; | ||||
|  | ||||
|     using return_type = typename Callback::return_type; | ||||
|  | ||||
|     template <typename State> | ||||
|     struct _with_state | ||||
|     { | ||||
|         const _bound_cb& _bound; | ||||
|         State&           _state; | ||||
|  | ||||
|         template <typename... Args> | ||||
|         constexpr return_type operator()(Args&&... args) const&& | ||||
|         { | ||||
|             return _detail::invoke_bound(_bound._callback, _bound._bound_args, | ||||
|                                          _bound._bound_args.index_sequence(), _state, | ||||
|                                          LEXY_FWD(args)...); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     template <typename State> | ||||
|     constexpr auto operator[](State& state) const | ||||
|     { | ||||
|         return _with_state<State>{*this, state}; | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr return_type operator()(Args&&... args) const | ||||
|     { | ||||
|         auto state = _detail::no_bind_state{}; | ||||
|         return _detail::invoke_bound(_callback, _bound_args, _bound_args.index_sequence(), state, | ||||
|                                      LEXY_FWD(args)...); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// Binds the `operator()` of the callback with pre-defined/remapped values. | ||||
| template <typename Callback, typename... BoundArgs> | ||||
| constexpr auto bind(Callback&& callback, BoundArgs&&... args) | ||||
| { | ||||
|     using bound = _bound_cb<std::decay_t<Callback>, std::decay_t<BoundArgs>...>; | ||||
|     return bound{LEXY_FWD(callback), _detail::make_tuple(LEXY_FWD(args)...)}; | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename Sink> | ||||
| struct _sink_wrapper | ||||
| { | ||||
|     const Sink& _sink; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) | ||||
|     { | ||||
|         return _sink.sink(LEXY_FWD(args)...); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Sink, typename... BoundArgs> | ||||
| struct _bound_sink | ||||
| { | ||||
|     LEXY_EMPTY_MEMBER Sink _sink; | ||||
|     LEXY_EMPTY_MEMBER _detail::tuple<BoundArgs...> _bound; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const -> decltype(_sink(LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return _sink(LEXY_FWD(args)...); | ||||
|     } | ||||
|  | ||||
|     template <bool Dummy = true, | ||||
|               typename   = std::enable_if_t<(!_detail::is_placeholder<BoundArgs> && ... && Dummy)>> | ||||
|     constexpr auto sink() const | ||||
|     { | ||||
|         auto state = _detail::no_bind_state{}; | ||||
|         return _detail::invoke_bound(_sink_wrapper<Sink>{_sink}, _bound, _bound.index_sequence(), | ||||
|                                      state); | ||||
|     } | ||||
|  | ||||
|     template <typename State> | ||||
|     constexpr auto sink(State& state) const | ||||
|     { | ||||
|         return _detail::invoke_bound(_sink_wrapper<Sink>{_sink}, _bound, _bound.index_sequence(), | ||||
|                                      state); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// Binds the `.sink()` function of a sink. | ||||
| /// The result has a `.sink()` function that accepts the state (i.e. the parse state), but no | ||||
| /// additional values. | ||||
| template <typename Sink, typename... BoundArgs> | ||||
| constexpr auto bind_sink(Sink&& sink, BoundArgs&&... args) | ||||
| { | ||||
|     static_assert( | ||||
|         (!_detail::is_decayed_same<BoundArgs, _detail::all_values_placeholder> && ...), | ||||
|         "lexy::values as a placeholder for bind_sink() doesn't make sense - there won't be any values"); | ||||
|     using bound = _bound_sink<std::decay_t<Sink>, std::decay_t<BoundArgs>...>; | ||||
|     return bound{LEXY_FWD(sink), _detail::make_tuple(LEXY_FWD(args)...)}; | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_BIND_HPP_INCLUDED | ||||
							
								
								
									
										80
									
								
								dep/lexy/include/lexy/callback/bit_cast.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								dep/lexy/include/lexy/callback/bit_cast.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_BIT_CAST_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_BIT_CAST_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/base.hpp> | ||||
|  | ||||
| #ifndef LEXY_HAS_BITCAST | ||||
| #    if defined(__has_builtin) | ||||
| #        if __has_builtin(__builtin_bit_cast) | ||||
| #            define LEXY_HAS_BITCAST 2 | ||||
| #        endif | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| #ifndef LEXY_HAS_BITCAST | ||||
| #    if defined(__has_include) | ||||
| #        if __has_include(<bit>) && __cplusplus >= 202002L | ||||
| #            include <bit> | ||||
| #            ifdef __cpp_lib_bit_cast | ||||
| #                define LEXY_HAS_BITCAST 1 | ||||
| #            endif | ||||
| #        endif | ||||
| #    endif | ||||
| #endif | ||||
|  | ||||
| #ifndef LEXY_HAS_BITCAST | ||||
| #    define LEXY_HAS_BITCAST 0 | ||||
| #endif | ||||
|  | ||||
| #if LEXY_HAS_BITCAST == 2 | ||||
| #    define LEXY_BITCAST_CONSTEXPR constexpr | ||||
| #elif LEXY_HAS_BITCAST == 1 | ||||
| #    define LEXY_BITCAST_CONSTEXPR constexpr | ||||
| #else | ||||
| #    include <cstring> | ||||
| #    define LEXY_BITCAST_CONSTEXPR | ||||
| #endif | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename T> | ||||
| struct _bit_cast | ||||
| { | ||||
|     static_assert(std::is_trivially_copyable_v<T>); | ||||
|  | ||||
|     using return_type = T; | ||||
|  | ||||
|     template <typename Arg, typename = std::enable_if_t<sizeof(T) == sizeof(Arg) | ||||
|                                                         && std::is_trivially_copyable_v<Arg>>> | ||||
|     LEXY_BITCAST_CONSTEXPR T operator()(const Arg& arg) const | ||||
|     { | ||||
| #if LEXY_HAS_BITCAST == 2 | ||||
|  | ||||
|         return __builtin_bit_cast(T, arg); | ||||
|  | ||||
| #elif LEXY_HAS_BITCAST == 1 | ||||
|  | ||||
|         return std::bit_cast<T>(arg); | ||||
|  | ||||
| #else | ||||
|  | ||||
|         static_assert(std::is_default_constructible_v<T>, "sorry, get a better standard library"); | ||||
|  | ||||
|         T to; | ||||
|         std::memcpy(&to, &arg, sizeof(T)); | ||||
|         return to; | ||||
|  | ||||
| #endif | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// std::bit_cast as a callback. | ||||
| template <typename T> | ||||
| constexpr auto bit_cast = _bit_cast<T>{}; | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_BIT_CAST_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										120
									
								
								dep/lexy/include/lexy/callback/composition.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								dep/lexy/include/lexy/callback/composition.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_COMPOSITION_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_COMPOSITION_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/base.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename Cb, typename State, typename = void> | ||||
| struct _compose_state | ||||
| { | ||||
|     const Cb& _cb; | ||||
|     State&    _state; | ||||
|  | ||||
|     using return_type = typename Cb::return_type; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const -> decltype(_cb(LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return _cb(LEXY_FWD(args)...); | ||||
|     } | ||||
| }; | ||||
| template <typename Cb, typename State> | ||||
| struct _compose_state<Cb, State, std::enable_if_t<lexy::is_callback_state<Cb, State>>> | ||||
| { | ||||
|     const Cb& _cb; | ||||
|     State&    _state; | ||||
|  | ||||
|     using return_type = typename Cb::return_type; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const -> decltype(_cb[_state](LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return _cb[_state](LEXY_FWD(args)...); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename First, typename Second> | ||||
| struct _compose_cb | ||||
| { | ||||
|     LEXY_EMPTY_MEMBER First  _first; | ||||
|     LEXY_EMPTY_MEMBER Second _second; | ||||
|  | ||||
|     constexpr explicit _compose_cb(First&& first, Second&& second) | ||||
|     : _first(LEXY_MOV(first)), _second(LEXY_MOV(second)) | ||||
|     {} | ||||
|  | ||||
|     using return_type = typename Second::return_type; | ||||
|  | ||||
|     template <typename State, | ||||
|               typename = std::enable_if_t<lexy::is_callback_state<First, State> // | ||||
|                                           || lexy::is_callback_state<Second, State>>> | ||||
|     constexpr auto operator[](State& state) const | ||||
|     { | ||||
|         auto first  = _compose_state<First, State>{_first, state}; | ||||
|         auto second = _compose_state<Second, State>{_second, state}; | ||||
|         return lexy::_compose_cb(LEXY_MOV(first), LEXY_MOV(second)); | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const | ||||
|         -> LEXY_DECAY_DECLTYPE(_first(LEXY_FWD(args)...), LEXY_DECLVAL(return_type)) | ||||
|     { | ||||
|         return _second(_first(LEXY_FWD(args)...)); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Sink, typename Callback> | ||||
| struct _compose_s | ||||
| { | ||||
|     LEXY_EMPTY_MEMBER Sink     _sink; | ||||
|     LEXY_EMPTY_MEMBER Callback _callback; | ||||
|  | ||||
|     using return_type = typename Callback::return_type; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto sink(Args&&... args) const -> decltype(_sink.sink(LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return _sink.sink(LEXY_FWD(args)...); | ||||
|     } | ||||
|  | ||||
|     template <typename State, typename = std::enable_if_t<lexy::is_callback_state<Callback, State>>> | ||||
|     constexpr auto operator[](State& state) const | ||||
|     { | ||||
|         return _compose_state<Callback, State>{_callback, state}; | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const -> decltype(_callback(LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return _callback(LEXY_FWD(args)...); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// Composes two callbacks. | ||||
| template <typename First, typename Second, typename = _detect_callback<First>, | ||||
|           typename = _detect_callback<Second>> | ||||
| constexpr auto operator|(First first, Second second) | ||||
| { | ||||
|     return _compose_cb(LEXY_MOV(first), LEXY_MOV(second)); | ||||
| } | ||||
| template <typename S, typename Cb, typename Second> | ||||
| constexpr auto operator|(_compose_s<S, Cb> composed, Second second) | ||||
| { | ||||
|     auto cb = LEXY_MOV(composed._callback) | LEXY_MOV(second); | ||||
|     return _compose_s<S, decltype(cb)>{LEXY_MOV(composed._sink), LEXY_MOV(cb)}; | ||||
| } | ||||
|  | ||||
| /// Composes a sink with a callback. | ||||
| template <typename Sink, typename Callback, typename = _detect_callback<Callback>> | ||||
| constexpr auto operator>>(Sink sink, Callback cb) | ||||
| { | ||||
|     return _compose_s<Sink, Callback>{LEXY_MOV(sink), LEXY_MOV(cb)}; | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_COMPOSITION_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										33
									
								
								dep/lexy/include/lexy/callback/constant.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								dep/lexy/include/lexy/callback/constant.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_CONSTANT_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_CONSTANT_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/base.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename T> | ||||
| struct _constant | ||||
| { | ||||
|     T _value; | ||||
|  | ||||
|     using return_type = T; | ||||
|  | ||||
|     constexpr const T& operator()() const | ||||
|     { | ||||
|         return _value; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// Creates a callback that produces the given value without accepting arguments. | ||||
| template <typename Arg> | ||||
| LEXY_CONSTEVAL auto constant(Arg&& value) | ||||
| { | ||||
|     return _constant<std::decay_t<Arg>>{LEXY_FWD(value)}; | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_CONSTANT_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										511
									
								
								dep/lexy/include/lexy/callback/container.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										511
									
								
								dep/lexy/include/lexy/callback/container.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,511 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_CONTAINER_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_CONTAINER_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/base.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| struct nullopt; | ||||
|  | ||||
| template <typename Container> | ||||
| using _detect_reserve = decltype(LEXY_DECLVAL(Container&).reserve(std::size_t())); | ||||
| template <typename Container> | ||||
| constexpr auto _has_reserve = _detail::is_detected<_detect_reserve, Container>; | ||||
|  | ||||
| template <typename Container> | ||||
| using _detect_append = decltype(LEXY_DECLVAL(Container&).append(LEXY_DECLVAL(Container&&))); | ||||
| template <typename Container> | ||||
| constexpr auto _has_append = _detail::is_detected<_detect_append, Container>; | ||||
| } // namespace lexy | ||||
|  | ||||
| //=== as_list ===// | ||||
| namespace lexy | ||||
| { | ||||
| template <typename Container> | ||||
| struct _list_sink | ||||
| { | ||||
|     Container _result; | ||||
|  | ||||
|     using return_type = Container; | ||||
|  | ||||
|     template <typename C = Container, typename U> | ||||
|     constexpr auto operator()(U&& obj) -> decltype(LEXY_DECLVAL(C&).push_back(LEXY_FWD(obj))) | ||||
|     { | ||||
|         return _result.push_back(LEXY_FWD(obj)); | ||||
|     } | ||||
|  | ||||
|     template <typename C = Container, typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) | ||||
|         -> decltype(LEXY_DECLVAL(C&).emplace_back(LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return _result.emplace_back(LEXY_FWD(args)...); | ||||
|     } | ||||
|  | ||||
|     constexpr Container&& finish() && | ||||
|     { | ||||
|         return LEXY_MOV(_result); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Container, typename AllocFn> | ||||
| struct _list_alloc | ||||
| { | ||||
|     AllocFn _alloc; | ||||
|  | ||||
|     using return_type = Container; | ||||
|  | ||||
|     template <typename State> | ||||
|     struct _with_state | ||||
|     { | ||||
|         State&         _state; | ||||
|         const AllocFn& _alloc; | ||||
|  | ||||
|         constexpr Container operator()(Container&& container) const | ||||
|         { | ||||
|             return LEXY_MOV(container); | ||||
|         } | ||||
|         constexpr Container operator()(nullopt&&) const | ||||
|         { | ||||
|             return Container(_detail::invoke(_alloc, _state)); | ||||
|         } | ||||
|  | ||||
|         template <typename... Args> | ||||
|         constexpr auto operator()(Args&&... args) const | ||||
|             -> LEXY_DECAY_DECLTYPE((LEXY_DECLVAL(Container&).push_back(LEXY_FWD(args)), ...), | ||||
|                                    LEXY_DECLVAL(Container)) | ||||
|         { | ||||
|             Container result(_detail::invoke(_alloc, _state)); | ||||
|             if constexpr (_has_reserve<Container>) | ||||
|                 result.reserve(sizeof...(args)); | ||||
|             (result.emplace_back(LEXY_FWD(args)), ...); | ||||
|             return result; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     template <typename State> | ||||
|     constexpr auto operator[](State& state) const | ||||
|     { | ||||
|         return _with_state<State>{state, _alloc}; | ||||
|     } | ||||
|  | ||||
|     template <typename State> | ||||
|     constexpr auto sink(State& state) const | ||||
|     { | ||||
|         return _list_sink<Container>{Container(_detail::invoke(_alloc, state))}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Container> | ||||
| struct _list | ||||
| { | ||||
|     using return_type = Container; | ||||
|  | ||||
|     constexpr Container operator()(Container&& container) const | ||||
|     { | ||||
|         return LEXY_MOV(container); | ||||
|     } | ||||
|     constexpr Container operator()(nullopt&&) const | ||||
|     { | ||||
|         return Container(); | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const | ||||
|         -> LEXY_DECAY_DECLTYPE((LEXY_DECLVAL(Container&).push_back(LEXY_FWD(args)), ...), | ||||
|                                LEXY_DECLVAL(Container)) | ||||
|     { | ||||
|         Container result; | ||||
|         if constexpr (_has_reserve<Container>) | ||||
|             result.reserve(sizeof...(args)); | ||||
|         (result.emplace_back(LEXY_FWD(args)), ...); | ||||
|         return result; | ||||
|     } | ||||
|     template <typename C = Container, typename... Args> | ||||
|     constexpr auto operator()(const typename C::allocator_type& allocator, Args&&... args) const | ||||
|         -> decltype((LEXY_DECLVAL(C&).push_back(LEXY_FWD(args)), ...), C(allocator)) | ||||
|     { | ||||
|         Container result(allocator); | ||||
|         if constexpr (_has_reserve<Container>) | ||||
|             result.reserve(sizeof...(args)); | ||||
|         (result.emplace_back(LEXY_FWD(args)), ...); | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     constexpr auto sink() const | ||||
|     { | ||||
|         return _list_sink<Container>{Container()}; | ||||
|     } | ||||
|     template <typename C = Container> | ||||
|     constexpr auto sink(const typename C::allocator_type& allocator) const | ||||
|     { | ||||
|         return _list_sink<Container>{Container(allocator)}; | ||||
|     } | ||||
|  | ||||
|     template <typename AllocFn> | ||||
|     constexpr auto allocator(AllocFn alloc_fn) const | ||||
|     { | ||||
|         return _list_alloc<Container, AllocFn>{alloc_fn}; | ||||
|     } | ||||
|     constexpr auto allocator() const | ||||
|     { | ||||
|         return allocator([](const auto& alloc) { return alloc; }); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// A callback with sink that creates a list of things (e.g. a `std::vector`, `std::list`, etc.). | ||||
| /// It repeatedly calls `push_back()` and `emplace_back()`. | ||||
| template <typename Container> | ||||
| constexpr auto as_list = _list<Container>{}; | ||||
| } // namespace lexy | ||||
|  | ||||
| //=== as_collection ===// | ||||
| namespace lexy | ||||
| { | ||||
| template <typename Container> | ||||
| struct _collection_sink | ||||
| { | ||||
|     Container _result; | ||||
|  | ||||
|     using return_type = Container; | ||||
|  | ||||
|     template <typename C = Container, typename U> | ||||
|     constexpr auto operator()(U&& obj) -> decltype(LEXY_DECLVAL(C&).insert(LEXY_FWD(obj))) | ||||
|     { | ||||
|         return _result.insert(LEXY_FWD(obj)); | ||||
|     } | ||||
|  | ||||
|     template <typename C = Container, typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) | ||||
|         -> decltype(LEXY_DECLVAL(C&).emplace(LEXY_FWD(args)...)) | ||||
|     { | ||||
|         return _result.emplace(LEXY_FWD(args)...); | ||||
|     } | ||||
|  | ||||
|     constexpr Container&& finish() && | ||||
|     { | ||||
|         return LEXY_MOV(_result); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Container, typename AllocFn> | ||||
| struct _collection_alloc | ||||
| { | ||||
|     AllocFn _alloc; | ||||
|  | ||||
|     using return_type = Container; | ||||
|  | ||||
|     template <typename State> | ||||
|     struct _with_state | ||||
|     { | ||||
|         State&         _state; | ||||
|         const AllocFn& _alloc; | ||||
|  | ||||
|         constexpr Container operator()(Container&& container) const | ||||
|         { | ||||
|             return LEXY_MOV(container); | ||||
|         } | ||||
|         constexpr Container operator()(nullopt&&) const | ||||
|         { | ||||
|             return Container(_detail::invoke(_alloc, _state)); | ||||
|         } | ||||
|  | ||||
|         template <typename... Args> | ||||
|         constexpr auto operator()(Args&&... args) const | ||||
|             -> LEXY_DECAY_DECLTYPE((LEXY_DECLVAL(Container&).insert(LEXY_FWD(args)), ...), | ||||
|                                    LEXY_DECLVAL(Container)) | ||||
|         { | ||||
|             Container result(_detail::invoke(_alloc, _state)); | ||||
|             if constexpr (_has_reserve<Container>) | ||||
|                 result.reserve(sizeof...(args)); | ||||
|             (result.emplace(LEXY_FWD(args)), ...); | ||||
|             return result; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     template <typename State> | ||||
|     constexpr auto operator[](State& state) const | ||||
|     { | ||||
|         return _with_state<State>{state, _alloc}; | ||||
|     } | ||||
|  | ||||
|     template <typename State> | ||||
|     constexpr auto sink(State& state) const | ||||
|     { | ||||
|         return _collection_sink<Container>{Container(_detail::invoke(_alloc, state))}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Container> | ||||
| struct _collection | ||||
| { | ||||
|     using return_type = Container; | ||||
|  | ||||
|     constexpr Container operator()(Container&& container) const | ||||
|     { | ||||
|         return LEXY_MOV(container); | ||||
|     } | ||||
|     constexpr Container operator()(nullopt&&) const | ||||
|     { | ||||
|         return Container(); | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const | ||||
|         -> LEXY_DECAY_DECLTYPE((LEXY_DECLVAL(Container&).insert(LEXY_FWD(args)), ...), | ||||
|                                LEXY_DECLVAL(Container)) | ||||
|     { | ||||
|         Container result; | ||||
|         if constexpr (_has_reserve<Container>) | ||||
|             result.reserve(sizeof...(args)); | ||||
|         (result.emplace(LEXY_FWD(args)), ...); | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     template <typename C = Container, typename... Args> | ||||
|     constexpr auto operator()(const typename C::allocator_type& allocator, Args&&... args) const | ||||
|         -> decltype((LEXY_DECLVAL(C&).insert(LEXY_FWD(args)), ...), C(allocator)) | ||||
|     { | ||||
|         Container result(allocator); | ||||
|         if constexpr (_has_reserve<Container>) | ||||
|             result.reserve(sizeof...(args)); | ||||
|         (result.emplace(LEXY_FWD(args)), ...); | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     constexpr auto sink() const | ||||
|     { | ||||
|         return _collection_sink<Container>{Container()}; | ||||
|     } | ||||
|     template <typename C = Container> | ||||
|     constexpr auto sink(const typename C::allocator_type& allocator) const | ||||
|     { | ||||
|         return _collection_sink<Container>{Container(allocator)}; | ||||
|     } | ||||
|  | ||||
|     template <typename AllocFn> | ||||
|     constexpr auto allocator(AllocFn alloc_fn) const | ||||
|     { | ||||
|         return _collection_alloc<Container, AllocFn>{alloc_fn}; | ||||
|     } | ||||
|     constexpr auto allocator() const | ||||
|     { | ||||
|         return allocator([](const auto& alloc) { return alloc; }); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// A callback with sink that creates an unordered collection of things (e.g. a `std::set`, | ||||
| /// `std::unordered_map`, etc.). It repeatedly calls `insert()` and `emplace()`. | ||||
| template <typename T> | ||||
| constexpr auto as_collection = _collection<T>{}; | ||||
| } // namespace lexy | ||||
|  | ||||
| //=== concat ===// | ||||
| namespace lexy | ||||
| { | ||||
| template <typename Container> | ||||
| struct _concat | ||||
| { | ||||
|     using return_type = Container; | ||||
|  | ||||
|     constexpr Container operator()(nullopt&&) const | ||||
|     { | ||||
|         return Container(); | ||||
|     } | ||||
|  | ||||
|     template <typename... Tail> | ||||
|     constexpr Container _call(Container&& head, Tail&&... tail) const | ||||
|     { | ||||
|         if constexpr (sizeof...(Tail) == 0) | ||||
|             return LEXY_MOV(head); | ||||
|         else | ||||
|         { | ||||
|             if constexpr (_has_reserve<Container>) | ||||
|             { | ||||
|                 auto total_size = (head.size() + ... + tail.size()); | ||||
|                 head.reserve(total_size); | ||||
|             } | ||||
|  | ||||
|             auto append = [&head](Container&& container) { | ||||
|                 if constexpr (_has_append<Container>) | ||||
|                 { | ||||
|                     head.append(LEXY_MOV(container)); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     for (auto& elem : container) | ||||
|                         head.push_back(LEXY_MOV(elem)); | ||||
|                 } | ||||
|             }; | ||||
|             (append(LEXY_MOV(tail)), ...); | ||||
|  | ||||
|             return LEXY_MOV(head); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const -> decltype(_call(Container(LEXY_FWD(args))...)) | ||||
|     { | ||||
|         return _call(Container(LEXY_FWD(args))...); | ||||
|     } | ||||
|  | ||||
|     struct _sink | ||||
|     { | ||||
|         Container _result; | ||||
|  | ||||
|         using return_type = Container; | ||||
|  | ||||
|         constexpr void operator()(Container&& container) | ||||
|         { | ||||
|             if (_result.empty()) | ||||
|             { | ||||
|                 // We assign until we have items. | ||||
|                 // That way we get the existing allocator. | ||||
|                 _result = LEXY_MOV(container); | ||||
|             } | ||||
|             else if constexpr (_has_append<Container>) | ||||
|             { | ||||
|                 _result.append(LEXY_MOV(container)); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if constexpr (_has_reserve<Container>) | ||||
|                 { | ||||
|                     auto capacity   = _result.capacity(); | ||||
|                     auto total_size = _result.size() + container.size(); | ||||
|                     if (total_size > capacity) | ||||
|                     { | ||||
|                         // If we need more space we reserve at least twice as much. | ||||
|                         auto exp_capacity = 2 * capacity; | ||||
|                         if (total_size > exp_capacity) | ||||
|                             _result.reserve(total_size); | ||||
|                         else | ||||
|                             _result.reserve(exp_capacity); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 for (auto& elem : container) | ||||
|                     _result.push_back(LEXY_MOV(elem)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         constexpr Container&& finish() && | ||||
|         { | ||||
|             return LEXY_MOV(_result); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     constexpr auto sink() const | ||||
|     { | ||||
|         return _sink{}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template <typename Container> | ||||
| constexpr auto concat = _concat<Container>{}; | ||||
| } // namespace lexy | ||||
|  | ||||
| //=== collect ===// | ||||
| namespace lexy | ||||
| { | ||||
| template <typename Container, typename Callback> | ||||
| class _collect_sink | ||||
| { | ||||
| public: | ||||
|     constexpr explicit _collect_sink(Callback callback) : _callback(LEXY_MOV(callback)) {} | ||||
|     template <typename C = Container> | ||||
|     constexpr explicit _collect_sink(Callback callback, const typename C::allocator_type& allocator) | ||||
|     : _result(allocator), _callback(LEXY_MOV(callback)) | ||||
|     {} | ||||
|  | ||||
|     using return_type = Container; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) | ||||
|         -> decltype(void(LEXY_DECLVAL(Callback)(LEXY_FWD(args)...))) | ||||
|     { | ||||
|         _result.push_back(_callback(LEXY_FWD(args)...)); | ||||
|     } | ||||
|  | ||||
|     constexpr auto finish() && | ||||
|     { | ||||
|         return LEXY_MOV(_result); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     Container                  _result; | ||||
|     LEXY_EMPTY_MEMBER Callback _callback; | ||||
| }; | ||||
| template <typename Callback> | ||||
| class _collect_sink<void, Callback> | ||||
| { | ||||
| public: | ||||
|     constexpr explicit _collect_sink(Callback callback) : _count(0), _callback(LEXY_MOV(callback)) | ||||
|     {} | ||||
|  | ||||
|     using return_type = std::size_t; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) | ||||
|         -> decltype(void(LEXY_DECLVAL(Callback)(LEXY_FWD(args)...))) | ||||
|     { | ||||
|         _callback(LEXY_FWD(args)...); | ||||
|         ++_count; | ||||
|     } | ||||
|  | ||||
|     constexpr auto finish() && | ||||
|     { | ||||
|         return _count; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     std::size_t                _count; | ||||
|     LEXY_EMPTY_MEMBER Callback _callback; | ||||
| }; | ||||
|  | ||||
| template <typename Container, typename Callback> | ||||
| class _collect | ||||
| { | ||||
| public: | ||||
|     constexpr explicit _collect(Callback callback) : _callback(LEXY_MOV(callback)) {} | ||||
|  | ||||
|     constexpr auto sink() const | ||||
|     { | ||||
|         return _collect_sink<Container, Callback>(_callback); | ||||
|     } | ||||
|     template <typename C = Container> | ||||
|     constexpr auto sink(const typename C::allocator_type& allocator) const | ||||
|     { | ||||
|         return _collect_sink<Container, Callback>(_callback, allocator); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     LEXY_EMPTY_MEMBER Callback _callback; | ||||
| }; | ||||
|  | ||||
| /// Returns a sink that invokes the void-returning callback multiple times, resulting in the number | ||||
| /// of times it was invoked. | ||||
| template <typename Callback> | ||||
| constexpr auto collect(Callback&& callback) | ||||
| { | ||||
|     using callback_t = std::decay_t<Callback>; | ||||
|     static_assert(std::is_void_v<typename callback_t::return_type>, | ||||
|                   "need to specify a container to collect into for non-void callbacks"); | ||||
|     return _collect<void, callback_t>(LEXY_FWD(callback)); | ||||
| } | ||||
|  | ||||
| /// Returns a sink that invokes the callback multiple times, storing each result in the container. | ||||
| template <typename Container, typename Callback> | ||||
| constexpr auto collect(Callback&& callback) | ||||
| { | ||||
|     using callback_t = std::decay_t<Callback>; | ||||
|     static_assert(!std::is_void_v<typename callback_t::return_type>, | ||||
|                   "cannot collect a void callback into a container"); | ||||
|     return _collect<Container, callback_t>(LEXY_FWD(callback)); | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_CONTAINER_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										92
									
								
								dep/lexy/include/lexy/callback/fold.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								dep/lexy/include/lexy/callback/fold.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_FOLD_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_FOLD_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/base.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <bool Inplace> | ||||
| struct _fold_sfinae; | ||||
| template <> | ||||
| struct _fold_sfinae<true> | ||||
| { | ||||
|     template <typename Op, typename T, typename... Args> | ||||
|     using type = decltype(void( | ||||
|         _detail::invoke(LEXY_DECLVAL(Op), LEXY_DECLVAL(T&), LEXY_DECLVAL(Args)...))); | ||||
| }; | ||||
| template <> | ||||
| struct _fold_sfinae<false> | ||||
| { | ||||
|     template <typename Op, typename T, typename... Args> | ||||
|     using type = decltype(void( | ||||
|         _detail::invoke(LEXY_DECLVAL(Op), LEXY_DECLVAL(T&&), LEXY_DECLVAL(Args)...))); | ||||
| }; | ||||
|  | ||||
| template <typename T, typename Arg, bool Inplace, typename Op> | ||||
| struct _fold | ||||
| { | ||||
|     Arg                  _init; | ||||
|     LEXY_EMPTY_MEMBER Op _op; | ||||
|  | ||||
|     struct _sink_callback | ||||
|     { | ||||
|         T  _result; | ||||
|         Op _op; | ||||
|  | ||||
|         using return_type = T; | ||||
|  | ||||
|         template <typename... Args> | ||||
|         constexpr auto operator()(Args&&... args) -> | ||||
|             typename _fold_sfinae<Inplace>::template type<Op, T, Args&&...> | ||||
|         { | ||||
|             if constexpr (Inplace) | ||||
|                 _detail::invoke(_op, _result, LEXY_FWD(args)...); | ||||
|             else | ||||
|                 _result = _detail::invoke(_op, LEXY_MOV(_result), LEXY_FWD(args)...); | ||||
|         } | ||||
|  | ||||
|         constexpr T finish() && | ||||
|         { | ||||
|             return LEXY_MOV(_result); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     constexpr auto sink() const | ||||
|     { | ||||
|         if constexpr (std::is_constructible_v<T, Arg>) | ||||
|             return _sink_callback{T(_init), _op}; | ||||
|         else | ||||
|             return _sink_callback{_init(), _op}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// Sink that folds all the arguments with the binary operation op. | ||||
| template <typename T, typename Arg = T, typename... Op> | ||||
| constexpr auto fold(Arg&& init, Op&&... op) | ||||
| { | ||||
|     auto fn = _make_overloaded(LEXY_FWD(op)...); | ||||
|     return _fold<T, std::decay_t<Arg>, false, decltype(fn)>{LEXY_FWD(init), LEXY_MOV(fn)}; | ||||
| } | ||||
|  | ||||
| /// Sink that folds all the arguments with the binary operation op that modifies the | ||||
| /// result in-place. | ||||
| template <typename T, typename Arg = T, typename... Op> | ||||
| constexpr auto fold_inplace(Arg&& init, Op&&... op) | ||||
| { | ||||
|     auto fn = _make_overloaded(LEXY_FWD(op)...); | ||||
|     return _fold<T, std::decay_t<Arg>, true, decltype(fn)>{LEXY_FWD(init), LEXY_MOV(fn)}; | ||||
| } | ||||
| } // namespace lexy | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| /// Sink that counts all arguments. | ||||
| constexpr auto count | ||||
|     = fold_inplace<std::size_t>(0u, [](std::size_t& result, auto&&...) { ++result; }); | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_FOLD_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										51
									
								
								dep/lexy/include/lexy/callback/forward.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								dep/lexy/include/lexy/callback/forward.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_FORWARD_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_FORWARD_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/base.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| struct nullopt; | ||||
|  | ||||
| template <typename T> | ||||
| struct _fwd | ||||
| { | ||||
|     using return_type = T; | ||||
|  | ||||
|     constexpr T operator()(T&& t) const | ||||
|     { | ||||
|         return LEXY_MOV(t); | ||||
|     } | ||||
|     constexpr T operator()(const T& t) const | ||||
|     { | ||||
|         return t; | ||||
|     } | ||||
| }; | ||||
| template <> | ||||
| struct _fwd<void> | ||||
| { | ||||
|     using return_type = void; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto sink(const Args&...) const | ||||
|     { | ||||
|         // We don't need a separate type, forward itself can have the required functions. | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     constexpr void operator()() const {} | ||||
|     constexpr void operator()(const lexy::nullopt&) const {} | ||||
|  | ||||
|     constexpr void finish() && {} | ||||
| }; | ||||
|  | ||||
| /// A callback that just forwards an existing object. | ||||
| template <typename T> | ||||
| constexpr auto forward = _fwd<T>{}; | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_FORWARD_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										44
									
								
								dep/lexy/include/lexy/callback/integer.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								dep/lexy/include/lexy/callback/integer.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_INTEGER_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_INTEGER_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/base.hpp> | ||||
| #include <lexy/dsl/sign.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename T> | ||||
| struct _int | ||||
| { | ||||
|     using return_type = T; | ||||
|  | ||||
|     // You don't actually produce an integer value. | ||||
|     constexpr T operator()(lexy::plus_sign) const  = delete; | ||||
|     constexpr T operator()(lexy::minus_sign) const = delete; | ||||
|  | ||||
|     template <typename Integer> | ||||
|     constexpr T operator()(const Integer& value) const | ||||
|     { | ||||
|         return T(value); | ||||
|     } | ||||
|     template <typename Integer> | ||||
|     constexpr T operator()(lexy::plus_sign, const Integer& value) const | ||||
|     { | ||||
|         return T(value); | ||||
|     } | ||||
|     template <typename Integer> | ||||
|     constexpr T operator()(lexy::minus_sign, const Integer& value) const | ||||
|     { | ||||
|         return T(-value); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| // A callback that takes an optional sign and an integer and produces the signed integer. | ||||
| template <typename T> | ||||
| constexpr auto as_integer = _int<T>{}; | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_INTEGER_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										34
									
								
								dep/lexy/include/lexy/callback/noop.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								dep/lexy/include/lexy/callback/noop.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_NOOP_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_NOOP_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/base.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| struct _noop | ||||
| { | ||||
|     using return_type = void; | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto sink(const Args&...) const | ||||
|     { | ||||
|         // We don't need a separate type, noop itself can have the required functions. | ||||
|         return *this; | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr void operator()(const Args&...) const | ||||
|     {} | ||||
|  | ||||
|     constexpr void finish() && {} | ||||
| }; | ||||
|  | ||||
| /// A callback with sink that does nothing. | ||||
| inline constexpr auto noop = _noop{}; | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_NOOP_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										98
									
								
								dep/lexy/include/lexy/callback/object.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								dep/lexy/include/lexy/callback/object.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_OBJECT_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_OBJECT_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/callback/base.hpp> | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <typename T, typename... Args> | ||||
| using _detect_brace_construct = decltype(T{LEXY_DECLVAL(Args)...}); | ||||
| template <typename T, typename... Args> | ||||
| constexpr auto is_brace_constructible = _detail::is_detected<_detect_brace_construct, T, Args...>; | ||||
|  | ||||
| template <typename T, typename... Args> | ||||
| constexpr auto is_constructible | ||||
|     = std::is_constructible_v<T, Args...> || is_brace_constructible<T, Args...>; | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| template <typename T> | ||||
| struct _construct | ||||
| { | ||||
|     using return_type = T; | ||||
|  | ||||
|     constexpr T operator()(T&& t) const | ||||
|     { | ||||
|         return LEXY_MOV(t); | ||||
|     } | ||||
|     constexpr T operator()(const T& t) const | ||||
|     { | ||||
|         return t; | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const | ||||
|         -> std::enable_if_t<_detail::is_constructible<T, Args&&...>, T> | ||||
|     { | ||||
|         if constexpr (std::is_constructible_v<T, Args&&...>) | ||||
|             return T(LEXY_FWD(args)...); | ||||
|         else | ||||
|             return T{LEXY_FWD(args)...}; | ||||
|     } | ||||
| }; | ||||
| template <> | ||||
| struct _construct<void> | ||||
| { | ||||
|     using return_type = void; | ||||
|  | ||||
|     constexpr void operator()() const {} | ||||
| }; | ||||
|  | ||||
| /// A callback that constructs an object of type T by forwarding the arguments. | ||||
| template <typename T> | ||||
| constexpr auto construct = _construct<T>{}; | ||||
|  | ||||
| template <typename T, typename PtrT> | ||||
| struct _new | ||||
| { | ||||
|     using return_type = PtrT; | ||||
|  | ||||
|     constexpr PtrT operator()(T&& t) const | ||||
|     { | ||||
|         auto ptr = new T(LEXY_MOV(t)); | ||||
|         return PtrT(ptr); | ||||
|     } | ||||
|     constexpr PtrT operator()(const T& t) const | ||||
|     { | ||||
|         auto ptr = new T(t); | ||||
|         return PtrT(ptr); | ||||
|     } | ||||
|  | ||||
|     template <typename... Args> | ||||
|     constexpr auto operator()(Args&&... args) const | ||||
|         -> std::enable_if_t<_detail::is_constructible<T, Args&&...>, PtrT> | ||||
|     { | ||||
|         if constexpr (std::is_constructible_v<T, Args&&...>) | ||||
|         { | ||||
|             auto ptr = new T(LEXY_FWD(args)...); | ||||
|             return PtrT(ptr); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             auto ptr = new T{LEXY_FWD(args)...}; | ||||
|             return PtrT(ptr); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// A callback that constructs an object of type T on the heap by forwarding the arguments. | ||||
| template <typename T, typename PtrT = T*> | ||||
| constexpr auto new_ = _new<T, PtrT>{}; | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_OBJECT_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										210
									
								
								dep/lexy/include/lexy/callback/string.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								dep/lexy/include/lexy/callback/string.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,210 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CALLBACK_STRING_HPP_INCLUDED | ||||
| #define LEXY_CALLBACK_STRING_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/_detail/code_point.hpp> | ||||
| #include <lexy/callback/base.hpp> | ||||
| #include <lexy/code_point.hpp> | ||||
| #include <lexy/encoding.hpp> | ||||
| #include <lexy/input/base.hpp> | ||||
| #include <lexy/lexeme.hpp> | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| struct nullopt; | ||||
|  | ||||
| template <typename String> | ||||
| using _string_char_type = LEXY_DECAY_DECLTYPE(LEXY_DECLVAL(String)[0]); | ||||
|  | ||||
| template <typename String, typename Encoding, typename CaseFoldingDSL = void> | ||||
| struct _as_string | ||||
| { | ||||
|     using return_type = String; | ||||
|     using _char_type  = _string_char_type<String>; | ||||
|     static_assert(lexy::_detail::is_compatible_char_type<Encoding, _char_type>, | ||||
|                   "invalid character type/encoding combination"); | ||||
|  | ||||
|     static constexpr String&& _case_folding(String&& str) | ||||
|     { | ||||
|         if constexpr (std::is_void_v<CaseFoldingDSL>) | ||||
|         { | ||||
|             return LEXY_MOV(str); | ||||
|         } | ||||
|         else if constexpr (CaseFoldingDSL::template is_inplace<Encoding>) | ||||
|         { | ||||
|             // We can change the string in place. | ||||
|             auto original_reader = lexy::_range_reader<Encoding>(str.begin(), str.end()); | ||||
|             auto reader = typename CaseFoldingDSL::template case_folding<decltype(original_reader)>{ | ||||
|                 original_reader}; | ||||
|             for (auto ptr = str.data(); true; ++ptr) | ||||
|             { | ||||
|                 auto cur = reader.peek(); | ||||
|                 if (cur == Encoding::eof()) | ||||
|                     break; | ||||
|                 reader.bump(); | ||||
|  | ||||
|                 // Once we've bumped it, we're not looking at it again. | ||||
|                 *ptr = static_cast<_char_type>(cur); | ||||
|             } | ||||
|  | ||||
|             return LEXY_MOV(str); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // We store the existing string somewhere else and clear it. | ||||
|             // Then we can read the case folded string and append each code unit. | ||||
|             auto original = LEXY_MOV(str); | ||||
|             str           = String(); | ||||
|             str.reserve(original.size()); | ||||
|  | ||||
|             auto original_reader = lexy::_range_reader<Encoding>(original.begin(), original.end()); | ||||
|             auto reader = typename CaseFoldingDSL::template case_folding<decltype(original_reader)>{ | ||||
|                 original_reader}; | ||||
|             while (true) | ||||
|             { | ||||
|                 auto cur = reader.peek(); | ||||
|                 if (cur == Encoding::eof()) | ||||
|                     break; | ||||
|                 str.push_back(static_cast<_char_type>(cur)); | ||||
|                 reader.bump(); | ||||
|             } | ||||
|  | ||||
|             return LEXY_MOV(str); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     template <typename NewCaseFoldingDSL> | ||||
|     constexpr auto case_folding(NewCaseFoldingDSL) const | ||||
|     { | ||||
|         return _as_string<String, Encoding, NewCaseFoldingDSL>{}; | ||||
|     } | ||||
|  | ||||
|     constexpr String operator()(nullopt&&) const | ||||
|     { | ||||
|         return String(); | ||||
|     } | ||||
|     constexpr String&& operator()(String&& str) const | ||||
|     { | ||||
|         return _case_folding(LEXY_MOV(str)); | ||||
|     } | ||||
|  | ||||
|     template <typename Iterator> | ||||
|     constexpr auto operator()(Iterator begin, Iterator end) const -> decltype(String(begin, end)) | ||||
|     { | ||||
|         return _case_folding(String(begin, end)); | ||||
|     } | ||||
|     template <typename Str = String, typename Iterator> | ||||
|     constexpr auto operator()(const typename Str::allocator_type& allocator, Iterator begin, | ||||
|                               Iterator end) const -> decltype(String(begin, end, allocator)) | ||||
|     { | ||||
|         return _case_folding(String(begin, end, allocator)); | ||||
|     } | ||||
|  | ||||
|     template <typename Reader> | ||||
|     constexpr String operator()(lexeme<Reader> lex) const | ||||
|     { | ||||
|         static_assert(lexy::char_type_compatible_with_reader<Reader, _char_type>, | ||||
|                       "cannot convert lexeme to this string type"); | ||||
|  | ||||
|         using iterator = typename lexeme<Reader>::iterator; | ||||
|         if constexpr (std::is_convertible_v<iterator, const _char_type*>) | ||||
|             return _case_folding(String(lex.data(), lex.size())); | ||||
|         else | ||||
|             return _case_folding(String(lex.begin(), lex.end())); | ||||
|     } | ||||
|     template <typename Str = String, typename Reader> | ||||
|     constexpr String operator()(const typename Str::allocator_type& allocator, | ||||
|                                 lexeme<Reader>                      lex) const | ||||
|     { | ||||
|         static_assert(lexy::char_type_compatible_with_reader<Reader, _char_type>, | ||||
|                       "cannot convert lexeme to this string type"); | ||||
|  | ||||
|         using iterator = typename lexeme<Reader>::iterator; | ||||
|         if constexpr (std::is_convertible_v<iterator, const _char_type*>) | ||||
|             return _case_folding(String(lex.data(), lex.size(), allocator)); | ||||
|         else | ||||
|             return _case_folding(String(lex.begin(), lex.end(), allocator)); | ||||
|     } | ||||
|  | ||||
|     constexpr String operator()(code_point cp) const | ||||
|     { | ||||
|         typename Encoding::char_type buffer[4] = {}; | ||||
|         auto size = _detail::encode_code_point<Encoding>(cp.value(), buffer, 4); | ||||
|         return _case_folding(String(buffer, buffer + size)); | ||||
|     } | ||||
|     template <typename Str = String> | ||||
|     constexpr String operator()(const typename Str::allocator_type& allocator, code_point cp) const | ||||
|     { | ||||
|         typename Encoding::char_type buffer[4] = {}; | ||||
|         auto size = _detail::encode_code_point<Encoding>(cp.value(), buffer, 4); | ||||
|         return _case_folding(String(buffer, buffer + size, allocator)); | ||||
|     } | ||||
|  | ||||
|     struct _sink | ||||
|     { | ||||
|         String _result; | ||||
|  | ||||
|         using return_type = String; | ||||
|  | ||||
|         template <typename CharT, typename = decltype(LEXY_DECLVAL(String).push_back(CharT()))> | ||||
|         constexpr void operator()(CharT c) | ||||
|         { | ||||
|             _result.push_back(c); | ||||
|         } | ||||
|  | ||||
|         constexpr void operator()(String&& str) | ||||
|         { | ||||
|             _result.append(LEXY_MOV(str)); | ||||
|         } | ||||
|  | ||||
|         template <typename Str = String, typename Iterator> | ||||
|         constexpr auto operator()(Iterator begin, Iterator end) | ||||
|             -> decltype(void(LEXY_DECLVAL(Str).append(begin, end))) | ||||
|         { | ||||
|             _result.append(begin, end); | ||||
|         } | ||||
|  | ||||
|         template <typename Reader> | ||||
|         constexpr void operator()(lexeme<Reader> lex) | ||||
|         { | ||||
|             static_assert(lexy::char_type_compatible_with_reader<Reader, _char_type>, | ||||
|                           "cannot convert lexeme to this string type"); | ||||
|             _result.append(lex.begin(), lex.end()); | ||||
|         } | ||||
|  | ||||
|         constexpr void operator()(code_point cp) | ||||
|         { | ||||
|             typename Encoding::char_type buffer[4] = {}; | ||||
|             auto size = _detail::encode_code_point<Encoding>(cp.value(), buffer, 4); | ||||
|             _result.append(buffer, buffer + size); | ||||
|         } | ||||
|  | ||||
|         constexpr String&& finish() && | ||||
|         { | ||||
|             return _case_folding(LEXY_MOV(_result)); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     constexpr auto sink() const | ||||
|     { | ||||
|         return _sink{String()}; | ||||
|     } | ||||
|     template <typename S = String> | ||||
|     constexpr auto sink(const typename S::allocator_type& allocator) const | ||||
|     { | ||||
|         return _sink{String(allocator)}; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| /// A callback with sink that creates a string (e.g. `std::string`). | ||||
| /// As a callback, it converts a lexeme into the string. | ||||
| /// As a sink, it repeatedly calls `.push_back()` for individual characters, | ||||
| /// or `.append()` for lexemes or other strings. | ||||
| template <typename String, typename Encoding = deduce_encoding<_string_char_type<String>>> | ||||
| constexpr auto as_string = _as_string<String, Encoding>{}; | ||||
| } // namespace lexy | ||||
|  | ||||
| #endif // LEXY_CALLBACK_STRING_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										306
									
								
								dep/lexy/include/lexy/code_point.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								dep/lexy/include/lexy/code_point.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,306 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_CODE_POINT_HPP_INCLUDED | ||||
| #define LEXY_CODE_POINT_HPP_INCLUDED | ||||
|  | ||||
| #include <cstdint> | ||||
| #include <lexy/_detail/assert.hpp> | ||||
| #include <lexy/_detail/config.hpp> | ||||
|  | ||||
| #if LEXY_HAS_UNICODE_DATABASE | ||||
| #    define LEXY_UNICODE_CONSTEXPR constexpr | ||||
| #else | ||||
| #    define LEXY_UNICODE_CONSTEXPR | ||||
| #endif | ||||
|  | ||||
| namespace lexy | ||||
| { | ||||
| /// A unicode code point. | ||||
| class code_point | ||||
| { | ||||
| public: | ||||
|     constexpr code_point() noexcept : _value(0xFFFF'FFFF) {} | ||||
|     constexpr explicit code_point(char32_t value) noexcept : _value(value) {} | ||||
|  | ||||
|     constexpr auto value() const noexcept | ||||
|     { | ||||
|         return _value; | ||||
|     } | ||||
|  | ||||
|     //=== classification ===// | ||||
|     constexpr bool is_ascii() const noexcept | ||||
|     { | ||||
|         return _value <= 0x7F; | ||||
|     } | ||||
|     constexpr bool is_bmp() const noexcept | ||||
|     { | ||||
|         return _value <= 0xFFFF; | ||||
|     } | ||||
|     constexpr bool is_valid() const noexcept | ||||
|     { | ||||
|         return _value <= 0x10'FFFF; | ||||
|     } | ||||
|  | ||||
|     constexpr bool is_control() const noexcept | ||||
|     { | ||||
|         return _value <= 0x1F || (0x7F <= _value && _value <= 0x9F); | ||||
|     } | ||||
|     constexpr bool is_surrogate() const noexcept | ||||
|     { | ||||
|         return 0xD800 <= _value && _value <= 0xDFFF; | ||||
|     } | ||||
|     constexpr bool is_private_use() const noexcept | ||||
|     { | ||||
|         return (0xE000 <= _value && _value <= 0xF8FF) | ||||
|                || (0x0F'0000 <= _value && _value <= 0x0F'FFFD) | ||||
|                || (0x10'0000 <= _value && _value <= 0x10'FFFD); | ||||
|     } | ||||
|     constexpr bool is_noncharacter() const noexcept | ||||
|     { | ||||
|         // Contiguous range of 32 non-characters. | ||||
|         if (0xFDD0 <= _value && _value <= 0xFDEF) | ||||
|             return true; | ||||
|  | ||||
|         // Last two code points of every plane. | ||||
|         auto in_plane = _value & 0xFFFF; | ||||
|         return in_plane == 0xFFFE || in_plane == 0xFFFF; | ||||
|     } | ||||
|  | ||||
|     constexpr bool is_scalar() const noexcept | ||||
|     { | ||||
|         return is_valid() && !is_surrogate(); | ||||
|     } | ||||
|  | ||||
|     //=== general category ===// | ||||
|     enum general_category_t | ||||
|     { | ||||
|     // NOLINTNEXTLINE: can't use parentheses here | ||||
| #define LEXY_UNICODE_CATEGORY(Short, Long) Short, Long = Short | ||||
|  | ||||
|         LEXY_UNICODE_CATEGORY(Lu, uppercase_letter), | ||||
|         LEXY_UNICODE_CATEGORY(Ll, lowercase_letter), | ||||
|         LEXY_UNICODE_CATEGORY(Lt, titlecase_letter), | ||||
|         LEXY_UNICODE_CATEGORY(Lm, modifier_letter), | ||||
|         LEXY_UNICODE_CATEGORY(Lo, other_letter), | ||||
|  | ||||
|         LEXY_UNICODE_CATEGORY(Mn, nonspacing_mark), | ||||
|         LEXY_UNICODE_CATEGORY(Mc, spacing_mark), | ||||
|         LEXY_UNICODE_CATEGORY(Me, enclosing_mark), | ||||
|  | ||||
|         LEXY_UNICODE_CATEGORY(Nd, decimal_number), | ||||
|         LEXY_UNICODE_CATEGORY(Nl, letter_number), | ||||
|         LEXY_UNICODE_CATEGORY(No, other_number), | ||||
|  | ||||
|         LEXY_UNICODE_CATEGORY(Pc, connector_punctuation), | ||||
|         LEXY_UNICODE_CATEGORY(Pd, dash_punctuation), | ||||
|         LEXY_UNICODE_CATEGORY(Ps, open_punctuation), | ||||
|         LEXY_UNICODE_CATEGORY(Pe, closing_punctuation), | ||||
|         LEXY_UNICODE_CATEGORY(Pi, initial_puncutation), | ||||
|         LEXY_UNICODE_CATEGORY(Pf, final_puncutation), | ||||
|         LEXY_UNICODE_CATEGORY(Po, other_punctuation), | ||||
|  | ||||
|         LEXY_UNICODE_CATEGORY(Sm, math_symbol), | ||||
|         LEXY_UNICODE_CATEGORY(Sc, currency_symbol), | ||||
|         LEXY_UNICODE_CATEGORY(Sk, modifier_symbol), | ||||
|         LEXY_UNICODE_CATEGORY(So, other_symbol), | ||||
|  | ||||
|         LEXY_UNICODE_CATEGORY(Zs, space_separator), | ||||
|         LEXY_UNICODE_CATEGORY(Zl, line_separator), | ||||
|         LEXY_UNICODE_CATEGORY(Zp, paragraph_separator), | ||||
|  | ||||
|         LEXY_UNICODE_CATEGORY(Cc, control), | ||||
|         LEXY_UNICODE_CATEGORY(Cf, format), | ||||
|         LEXY_UNICODE_CATEGORY(Cs, surrogate), | ||||
|         LEXY_UNICODE_CATEGORY(Co, private_use), | ||||
|         LEXY_UNICODE_CATEGORY(Cn, unassigned), | ||||
|  | ||||
| #undef LEXY_UNICODE_CATEGORY | ||||
|     }; | ||||
|  | ||||
|     template <general_category_t... Cats> | ||||
|     struct _gc_group | ||||
|     { | ||||
|         const char* name; | ||||
|  | ||||
|         friend constexpr bool operator==(_gc_group, general_category_t cat) | ||||
|         { | ||||
|             return ((cat == Cats) || ...); | ||||
|         } | ||||
|         friend constexpr bool operator==(general_category_t cat, _gc_group) | ||||
|         { | ||||
|             return ((cat == Cats) || ...); | ||||
|         } | ||||
|  | ||||
|         friend constexpr bool operator!=(_gc_group, general_category_t cat) | ||||
|         { | ||||
|             return !(_gc_group{} == cat); | ||||
|         } | ||||
|         friend constexpr bool operator!=(general_category_t cat, _gc_group) | ||||
|         { | ||||
|             return !(_gc_group{} == cat); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| #define LEXY_UNICODE_CATEGORY_GROUP(Name, Short, Long, ...)                                        \ | ||||
|     static constexpr _gc_group<__VA_ARGS__> Short{"code-point." Name};                             \ | ||||
|     static constexpr _gc_group<__VA_ARGS__> Long = Short | ||||
|  | ||||
|     LEXY_UNICODE_CATEGORY_GROUP("cased-letter", LC, cased_letter, Lu, Ll, Lt); | ||||
|     LEXY_UNICODE_CATEGORY_GROUP("letter", L, letter, Lu, Ll, Lt, Lm, Lo); | ||||
|     LEXY_UNICODE_CATEGORY_GROUP("mark", M, mark, Mn, Mc, Me); | ||||
|     LEXY_UNICODE_CATEGORY_GROUP("number", N, number, Nd, Nl, No); | ||||
|     LEXY_UNICODE_CATEGORY_GROUP("punctuation", P, punctuation, Pc, Pd, Ps, Pe, Pi, Pf, Po); | ||||
|     LEXY_UNICODE_CATEGORY_GROUP("symbol", S, symbol, Sm, Sc, Sk, So); | ||||
|     LEXY_UNICODE_CATEGORY_GROUP("separator", Z, separator, Zs, Zl, Zp); | ||||
|     LEXY_UNICODE_CATEGORY_GROUP("other", C, other, Cc, Cf, Cs, Co, Cn); | ||||
|  | ||||
| #undef LEXY_UNICODE_CATEGORY_GROUP | ||||
|  | ||||
|     LEXY_UNICODE_CONSTEXPR general_category_t general_category() const noexcept; | ||||
|  | ||||
|     //=== comparision ===// | ||||
|     friend constexpr bool operator==(code_point lhs, code_point rhs) noexcept | ||||
|     { | ||||
|         return lhs._value == rhs._value; | ||||
|     } | ||||
|     friend constexpr bool operator!=(code_point lhs, code_point rhs) noexcept | ||||
|     { | ||||
|         return lhs._value != rhs._value; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     char32_t _value; | ||||
| }; | ||||
|  | ||||
| LEXY_UNICODE_CONSTEXPR code_point simple_case_fold(code_point cp) noexcept; | ||||
| } // namespace lexy | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| constexpr const char* general_category_name(lexy::code_point::general_category_t category) | ||||
| { | ||||
|     switch (category) | ||||
|     { | ||||
|     case lexy::code_point::Lu: | ||||
|         return "code-point.uppercase-letter"; | ||||
|     case lexy::code_point::Ll: | ||||
|         return "code-point.lowercase-letter"; | ||||
|     case lexy::code_point::Lt: | ||||
|         return "code-point.titlecase-letter"; | ||||
|     case lexy::code_point::Lm: | ||||
|         return "code-point.modifier-letter"; | ||||
|     case lexy::code_point::Lo: | ||||
|         return "code-point.other-letter"; | ||||
|  | ||||
|     case lexy::code_point::Mn: | ||||
|         return "code-point.nonspacing-mark"; | ||||
|     case lexy::code_point::Mc: | ||||
|         return "code-point.combining-mark"; | ||||
|     case lexy::code_point::Me: | ||||
|         return "code-point.enclosing-mark"; | ||||
|  | ||||
|     case lexy::code_point::Nd: | ||||
|         return "code-point.decimal-number"; | ||||
|     case lexy::code_point::Nl: | ||||
|         return "code-point.letter-number"; | ||||
|     case lexy::code_point::No: | ||||
|         return "code-point.other-number"; | ||||
|  | ||||
|     case lexy::code_point::Pc: | ||||
|         return "code-point.connector-punctuation"; | ||||
|     case lexy::code_point::Pd: | ||||
|         return "code-point.dash-punctuation"; | ||||
|     case lexy::code_point::Ps: | ||||
|         return "code-point.open-punctuation"; | ||||
|     case lexy::code_point::Pe: | ||||
|         return "code-point.close-punctuation"; | ||||
|     case lexy::code_point::Pi: | ||||
|         return "code-point.initial-quote-punctuation"; | ||||
|     case lexy::code_point::Pf: | ||||
|         return "code-point.final-quote-punctuation"; | ||||
|     case lexy::code_point::Po: | ||||
|         return "code-point.other-punctuation"; | ||||
|  | ||||
|     case lexy::code_point::Sm: | ||||
|         return "code-point.math-symbol"; | ||||
|     case lexy::code_point::Sc: | ||||
|         return "code-point.currency-symbol"; | ||||
|     case lexy::code_point::Sk: | ||||
|         return "code-point.modifier-symbol"; | ||||
|     case lexy::code_point::So: | ||||
|         return "code-point.other-symbol"; | ||||
|  | ||||
|     case lexy::code_point::Zs: | ||||
|         return "code-point.space-separator"; | ||||
|     case lexy::code_point::Zl: | ||||
|         return "code-point.line-separator"; | ||||
|     case lexy::code_point::Zp: | ||||
|         return "code-point.paragraph-separator"; | ||||
|  | ||||
|     case lexy::code_point::Cc: | ||||
|         return "code-point.control"; | ||||
|     case lexy::code_point::Cf: | ||||
|         return "code-point.format"; | ||||
|     case lexy::code_point::Cs: | ||||
|         return "code-point.surrogate"; | ||||
|     case lexy::code_point::Co: | ||||
|         return "code-point.private-use"; | ||||
|     case lexy::code_point::Cn: | ||||
|         return "code-point.not-assigned"; | ||||
|     } | ||||
|  | ||||
|     return nullptr; // unreachable | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #if LEXY_HAS_UNICODE_DATABASE | ||||
| #    include <lexy/_detail/unicode_database.hpp> | ||||
|  | ||||
| constexpr lexy::code_point::general_category_t lexy::code_point::general_category() const noexcept | ||||
| { | ||||
|     if (!is_valid()) | ||||
|         return general_category_t::unassigned; | ||||
|  | ||||
|     auto idx = _unicode_db::property_index(_value); | ||||
|     return _unicode_db::category[idx]; | ||||
| } | ||||
|  | ||||
| constexpr lexy::code_point lexy::simple_case_fold(code_point cp) noexcept | ||||
| { | ||||
|     if (!cp.is_valid()) | ||||
|         return cp; | ||||
|  | ||||
|     auto idx    = _unicode_db::property_index(cp.value()); | ||||
|     auto offset = _unicode_db::case_folding_offset[idx]; | ||||
|     return code_point(char32_t(std::int_least32_t(cp.value()) + offset)); | ||||
| } | ||||
|  | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <lexy::_unicode_db::binary_properties_t... Props> | ||||
| LEXY_FORCE_INLINE constexpr bool code_point_has_properties(char32_t cp) | ||||
| { | ||||
|     constexpr auto mask = ((1 << Props) | ...); | ||||
|  | ||||
|     auto idx   = _unicode_db::property_index(cp); | ||||
|     auto props = _unicode_db::binary_properties[idx]; | ||||
|     return (props & mask) != 0; | ||||
| } | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #    define LEXY_UNICODE_PROPERTY(Name) ::lexy::_unicode_db::Name | ||||
|  | ||||
| #else | ||||
| namespace lexy::_detail | ||||
| { | ||||
| template <int... Props> | ||||
| bool code_point_has_properties(char32_t cp); // not implemented | ||||
| } // namespace lexy::_detail | ||||
|  | ||||
| #    define LEXY_UNICODE_PROPERTY(Name) 0 | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #endif // LEXY_CODE_POINT_HPP_INCLUDED | ||||
|  | ||||
							
								
								
									
										68
									
								
								dep/lexy/include/lexy/dsl.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								dep/lexy/include/lexy/dsl.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| // Copyright (C) 2020-2025 Jonathan Müller and lexy contributors | ||||
| // SPDX-License-Identifier: BSL-1.0 | ||||
|  | ||||
| #ifndef LEXY_DSL_HPP_INCLUDED | ||||
| #define LEXY_DSL_HPP_INCLUDED | ||||
|  | ||||
| #include <lexy/dsl/any.hpp> | ||||
| #include <lexy/dsl/ascii.hpp> | ||||
| #include <lexy/dsl/bits.hpp> | ||||
| #include <lexy/dsl/bom.hpp> | ||||
| #include <lexy/dsl/brackets.hpp> | ||||
| #include <lexy/dsl/branch.hpp> | ||||
| #include <lexy/dsl/byte.hpp> | ||||
| #include <lexy/dsl/capture.hpp> | ||||
| #include <lexy/dsl/case_folding.hpp> | ||||
| #include <lexy/dsl/char_class.hpp> | ||||
| #include <lexy/dsl/choice.hpp> | ||||
| #include <lexy/dsl/code_point.hpp> | ||||
| #include <lexy/dsl/combination.hpp> | ||||
| #include <lexy/dsl/context_counter.hpp> | ||||
| #include <lexy/dsl/context_flag.hpp> | ||||
| #include <lexy/dsl/context_identifier.hpp> | ||||
| #include <lexy/dsl/delimited.hpp> | ||||
| #include <lexy/dsl/digit.hpp> | ||||
| #include <lexy/dsl/effect.hpp> | ||||
| #include <lexy/dsl/eof.hpp> | ||||
| #include <lexy/dsl/error.hpp> | ||||
| #include <lexy/dsl/expression.hpp> | ||||
| #include <lexy/dsl/flags.hpp> | ||||
| #include <lexy/dsl/follow.hpp> | ||||
| #include <lexy/dsl/identifier.hpp> | ||||
| #include <lexy/dsl/if.hpp> | ||||
| #include <lexy/dsl/integer.hpp> | ||||
| #include <lexy/dsl/list.hpp> | ||||
| #include <lexy/dsl/literal.hpp> | ||||
| #include <lexy/dsl/lookahead.hpp> | ||||
| #include <lexy/dsl/loop.hpp> | ||||
| #include <lexy/dsl/member.hpp> | ||||
| #include <lexy/dsl/newline.hpp> | ||||
| #include <lexy/dsl/operator.hpp> | ||||
| #include <lexy/dsl/option.hpp> | ||||
| #include <lexy/dsl/parse_as.hpp> | ||||
| #include <lexy/dsl/peek.hpp> | ||||
| #include <lexy/dsl/position.hpp> | ||||
| #include <lexy/dsl/production.hpp> | ||||
| #include <lexy/dsl/punctuator.hpp> | ||||
| #include <lexy/dsl/recover.hpp> | ||||
| #include <lexy/dsl/repeat.hpp> | ||||
| #include <lexy/dsl/return.hpp> | ||||
| #include <lexy/dsl/scan.hpp> | ||||
| #include <lexy/dsl/separator.hpp> | ||||
| #include <lexy/dsl/sequence.hpp> | ||||
| #include <lexy/dsl/sign.hpp> | ||||
| #include <lexy/dsl/subgrammar.hpp> | ||||
| #include <lexy/dsl/symbol.hpp> | ||||
| #include <lexy/dsl/terminator.hpp> | ||||
| #include <lexy/dsl/times.hpp> | ||||
| #include <lexy/dsl/token.hpp> | ||||
| #include <lexy/dsl/unicode.hpp> | ||||
| #include <lexy/dsl/until.hpp> | ||||
| #include <lexy/dsl/whitespace.hpp> | ||||
|  | ||||
| #if LEXY_EXPERIMENTAL | ||||
| #    include <lexy/dsl/parse_tree_node.hpp> | ||||
| #endif | ||||
|  | ||||
| #endif // LEXY_DSL_HPP_INCLUDED | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user